wayland: add jay_screencast
This commit is contained in:
parent
022d8d1db0
commit
5a4e48e54a
14 changed files with 635 additions and 11 deletions
|
|
@ -359,7 +359,7 @@ impl MetalConnector {
|
|||
fr.send_done();
|
||||
let _ = fr.client.remove_obj(&*fr);
|
||||
}
|
||||
node.global.perform_screencopies(&buffer.fb, &buffer.tex);
|
||||
node.perform_screencopies(&buffer.fb, &buffer.tex);
|
||||
}
|
||||
changes.change_object(plane.id, |c| {
|
||||
c.change(plane.fb_id, buffer.drm.id().0 as _);
|
||||
|
|
|
|||
|
|
@ -706,7 +706,7 @@ impl XBackend {
|
|||
fr.send_done();
|
||||
let _ = fr.client.remove_obj(&*fr);
|
||||
}
|
||||
node.global.perform_screencopies(&fb, &image.tex.get());
|
||||
node.perform_screencopies(&fb, &image.tex.get());
|
||||
}
|
||||
|
||||
let pp = PresentPixmap {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use {
|
|||
zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1,
|
||||
},
|
||||
jay_output::JayOutput,
|
||||
jay_screencast::JayScreencast,
|
||||
jay_workspace::JayWorkspace,
|
||||
wl_buffer::WlBuffer,
|
||||
wl_display::WlDisplay,
|
||||
|
|
@ -27,9 +28,9 @@ use {
|
|||
copyhashmap::{CopyHashMap, Locked},
|
||||
},
|
||||
wire::{
|
||||
JayOutputId, JayWorkspaceId, WlBufferId, WlDataSourceId, WlOutputId, WlPointerId,
|
||||
WlRegionId, WlRegistryId, WlSeatId, WlSurfaceId, XdgPositionerId, XdgSurfaceId,
|
||||
XdgToplevelId, XdgWmBaseId, ZwpPrimarySelectionSourceV1Id,
|
||||
JayOutputId, JayScreencastId, JayWorkspaceId, WlBufferId, WlDataSourceId, WlOutputId,
|
||||
WlPointerId, WlRegionId, WlRegistryId, WlSeatId, WlSurfaceId, XdgPositionerId,
|
||||
XdgSurfaceId, XdgToplevelId, XdgWmBaseId, ZwpPrimarySelectionSourceV1Id,
|
||||
},
|
||||
},
|
||||
std::{cell::RefCell, mem, rc::Rc},
|
||||
|
|
@ -54,6 +55,7 @@ pub struct Objects {
|
|||
pub pointers: CopyHashMap<WlPointerId, Rc<WlPointer>>,
|
||||
pub xdg_wm_bases: CopyHashMap<XdgWmBaseId, Rc<XdgWmBase>>,
|
||||
pub seats: CopyHashMap<WlSeatId, Rc<WlSeat>>,
|
||||
pub screencasts: CopyHashMap<JayScreencastId, Rc<JayScreencast>>,
|
||||
ids: RefCell<Vec<usize>>,
|
||||
}
|
||||
|
||||
|
|
@ -80,6 +82,7 @@ impl Objects {
|
|||
pointers: Default::default(),
|
||||
xdg_wm_bases: Default::default(),
|
||||
seats: Default::default(),
|
||||
screencasts: Default::default(),
|
||||
ids: RefCell::new(vec![]),
|
||||
}
|
||||
}
|
||||
|
|
@ -110,6 +113,7 @@ impl Objects {
|
|||
self.xdg_wm_bases.clear();
|
||||
self.seats.clear();
|
||||
self.pointers.clear();
|
||||
self.screencasts.clear();
|
||||
}
|
||||
|
||||
pub fn id<T>(&self, client_data: &Client) -> Result<T, ClientError>
|
||||
|
|
|
|||
|
|
@ -390,6 +390,7 @@ fn create_dummy_output(state: &Rc<State>) {
|
|||
lock_surface: Default::default(),
|
||||
preferred_scale: Cell::new(Fixed::from_int(1)),
|
||||
hardware_cursor: Default::default(),
|
||||
screencasts: Default::default(),
|
||||
});
|
||||
let dummy_workspace = Rc::new(WorkspaceNode {
|
||||
id: state.node_ids.next(),
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ pub mod jay_log_file;
|
|||
pub mod jay_output;
|
||||
pub mod jay_pointer;
|
||||
pub mod jay_render_ctx;
|
||||
pub mod jay_screencast;
|
||||
pub mod jay_screenshot;
|
||||
pub mod jay_seat_events;
|
||||
pub mod jay_workspace;
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@ use {
|
|||
globals::{Global, GlobalName},
|
||||
ifs::{
|
||||
jay_idle::JayIdle, jay_log_file::JayLogFile, jay_output::JayOutput,
|
||||
jay_pointer::JayPointer, jay_render_ctx::JayRenderCtx, jay_screenshot::JayScreenshot,
|
||||
jay_seat_events::JaySeatEvents, jay_workspace_watcher::JayWorkspaceWatcher,
|
||||
jay_pointer::JayPointer, jay_render_ctx::JayRenderCtx, jay_screencast::JayScreencast,
|
||||
jay_screenshot::JayScreenshot, jay_seat_events::JaySeatEvents,
|
||||
jay_workspace_watcher::JayWorkspaceWatcher,
|
||||
},
|
||||
leaks::Tracker,
|
||||
object::Object,
|
||||
|
|
@ -298,6 +299,14 @@ impl JayCompositor {
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_screencast(&self, parser: MsgParser<'_, '_>) -> Result<(), JayCompositorError> {
|
||||
let req: CreateScreencast = self.client.parse(self, parser)?;
|
||||
let sc = Rc::new(JayScreencast::new(req.id, &self.client));
|
||||
track!(self.client, sc);
|
||||
self.client.add_client_obj(&sc)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
object_base! {
|
||||
|
|
@ -318,11 +327,12 @@ object_base! {
|
|||
GET_POINTER => get_pointer,
|
||||
GET_RENDER_CTX => get_render_ctx,
|
||||
WATCH_WORKSPACES => watch_workspaces,
|
||||
CREATE_SCREENCAST => create_screencast,
|
||||
}
|
||||
|
||||
impl Object for JayCompositor {
|
||||
fn num_requests(&self) -> u32 {
|
||||
WATCH_WORKSPACES + 1
|
||||
CREATE_SCREENCAST + 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
452
src/ifs/jay_screencast.rs
Normal file
452
src/ifs/jay_screencast.rs
Normal file
|
|
@ -0,0 +1,452 @@
|
|||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
format::XRGB8888,
|
||||
ifs::jay_output::JayOutput,
|
||||
leaks::Tracker,
|
||||
object::Object,
|
||||
render::{Framebuffer, RenderContext, RenderError, Texture},
|
||||
tree::{OutputNode, WorkspaceNodeId},
|
||||
utils::{
|
||||
buffd::{MsgParser, MsgParserError},
|
||||
clonecell::CloneCell,
|
||||
errorfmt::ErrorFmt,
|
||||
numcell::NumCell,
|
||||
option_ext::OptionExt,
|
||||
},
|
||||
video::{
|
||||
dmabuf::DmaBuf,
|
||||
gbm::{GbmError, GBM_BO_USE_LINEAR, GBM_BO_USE_RENDERING},
|
||||
ModifiedFormat, INVALID_MODIFIER,
|
||||
},
|
||||
wire::{jay_screencast::*, JayScreencastId},
|
||||
},
|
||||
ahash::AHashSet,
|
||||
std::{
|
||||
cell::{Cell, RefCell},
|
||||
ops::{Deref, DerefMut},
|
||||
rc::Rc,
|
||||
},
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
pub struct JayScreencast {
|
||||
pub id: JayScreencastId,
|
||||
pub client: Rc<Client>,
|
||||
pub tracker: Tracker<Self>,
|
||||
config_serial: NumCell<u32>,
|
||||
config_acked: Cell<bool>,
|
||||
buffers_serial: NumCell<u32>,
|
||||
buffers_acked: Cell<bool>,
|
||||
buffers: RefCell<Vec<ScreencastBuffer>>,
|
||||
missed_frame: Cell<bool>,
|
||||
output: CloneCell<Option<Rc<OutputNode>>>,
|
||||
destroyed: Cell<bool>,
|
||||
running: Cell<bool>,
|
||||
show_all: Cell<bool>,
|
||||
show_workspaces: RefCell<AHashSet<WorkspaceNodeId>>,
|
||||
linear: Cell<bool>,
|
||||
pending: Pending,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Pending {
|
||||
linear: Cell<Option<bool>>,
|
||||
running: Cell<Option<bool>>,
|
||||
output: Cell<Option<Option<Rc<JayOutput>>>>,
|
||||
show_all: Cell<Option<bool>>,
|
||||
show_workspaces: RefCell<Option<AHashSet<WorkspaceNodeId>>>,
|
||||
}
|
||||
|
||||
struct ScreencastBuffer {
|
||||
dmabuf: DmaBuf,
|
||||
fb: Rc<Framebuffer>,
|
||||
free: bool,
|
||||
}
|
||||
|
||||
impl JayScreencast {
|
||||
pub fn new(id: JayScreencastId, client: &Rc<Client>) -> Self {
|
||||
Self {
|
||||
id,
|
||||
client: client.clone(),
|
||||
tracker: Default::default(),
|
||||
config_serial: Default::default(),
|
||||
config_acked: Cell::new(true),
|
||||
buffers_serial: Default::default(),
|
||||
buffers_acked: Cell::new(false),
|
||||
buffers: Default::default(),
|
||||
missed_frame: Cell::new(false),
|
||||
output: Default::default(),
|
||||
destroyed: Cell::new(false),
|
||||
running: Cell::new(false),
|
||||
show_all: Cell::new(false),
|
||||
show_workspaces: Default::default(),
|
||||
linear: Cell::new(false),
|
||||
pending: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn send_buffers(&self) {
|
||||
self.buffers_acked.set(false);
|
||||
let serial = self.buffers_serial.fetch_add(1) + 1;
|
||||
let buffers = self.buffers.borrow_mut();
|
||||
for buffer in buffers.iter() {
|
||||
for plane in &buffer.dmabuf.planes {
|
||||
self.client.event(Plane {
|
||||
self_id: self.id,
|
||||
fd: plane.fd.clone(),
|
||||
offset: plane.offset,
|
||||
stride: plane.stride,
|
||||
});
|
||||
}
|
||||
self.client.event(Buffer {
|
||||
self_id: self.id,
|
||||
format: buffer.dmabuf.format.drm,
|
||||
modifier: buffer.dmabuf.modifier,
|
||||
width: buffer.dmabuf.width,
|
||||
height: buffer.dmabuf.height,
|
||||
});
|
||||
}
|
||||
self.client.event(BuffersDone {
|
||||
self_id: self.id,
|
||||
serial,
|
||||
});
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn send_config(&self) {
|
||||
self.config_acked.set(false);
|
||||
let serial = self.config_serial.fetch_add(1) + 1;
|
||||
if let Some(output) = self.output.get() {
|
||||
self.client.event(ConfigOutput {
|
||||
self_id: self.id,
|
||||
linear_id: output.id.raw(),
|
||||
});
|
||||
}
|
||||
self.client.event(ConfigAllowAllWorkspaces {
|
||||
self_id: self.id,
|
||||
allow_all: self.show_all.get() as _,
|
||||
});
|
||||
for &ws in self.show_workspaces.borrow_mut().iter() {
|
||||
self.client.event(ConfigAllowWorkspace {
|
||||
self_id: self.id,
|
||||
linear_id: ws.raw(),
|
||||
});
|
||||
}
|
||||
self.client.event(ConfigUseLinearBuffers {
|
||||
self_id: self.id,
|
||||
use_linear: self.linear.get() as _,
|
||||
});
|
||||
self.client.event(ConfigRunning {
|
||||
self_id: self.id,
|
||||
running: self.running.get() as _,
|
||||
});
|
||||
self.client.event(ConfigDone {
|
||||
self_id: self.id,
|
||||
serial,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn copy_texture(&self, on: &OutputNode, texture: &Texture) {
|
||||
if !self.running.get() {
|
||||
return;
|
||||
}
|
||||
if !self.show_all.get() {
|
||||
let ws = match on.workspace.get() {
|
||||
Some(ws) => ws,
|
||||
_ => return,
|
||||
};
|
||||
if !self.show_workspaces.borrow_mut().contains(&ws.id) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
let mut buffer = self.buffers.borrow_mut();
|
||||
for (idx, buffer) in buffer.deref_mut().iter_mut().enumerate() {
|
||||
if buffer.free {
|
||||
buffer.fb.copy_texture(&self.client.state, texture, 0, 0);
|
||||
self.client.event(Ready {
|
||||
self_id: self.id,
|
||||
idx: idx as _,
|
||||
});
|
||||
buffer.free = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
self.missed_frame.set(true);
|
||||
self.client.event(MissedFrame { self_id: self.id })
|
||||
}
|
||||
|
||||
fn detach(&self) {
|
||||
if let Some(output) = self.output.take() {
|
||||
output.screencasts.remove(&(self.client.id, self.id));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn do_destroy(&self) {
|
||||
self.detach();
|
||||
self.destroyed.set(true);
|
||||
self.client.event(Destroyed { self_id: self.id });
|
||||
}
|
||||
|
||||
pub fn realloc(&self, ctx: &Rc<RenderContext>) -> Result<(), JayScreencastError> {
|
||||
let mut buffers = vec![];
|
||||
if let Some(output) = self.output.get() {
|
||||
let mode = output.global.mode.get();
|
||||
let num = 3;
|
||||
for _ in 0..num {
|
||||
let format = ModifiedFormat {
|
||||
format: XRGB8888,
|
||||
modifier: INVALID_MODIFIER,
|
||||
};
|
||||
let mut flags = GBM_BO_USE_RENDERING;
|
||||
if self.linear.get() {
|
||||
flags |= GBM_BO_USE_LINEAR;
|
||||
}
|
||||
let buffer = ctx.gbm.create_bo(mode.width, mode.height, &format, flags)?;
|
||||
let fb = ctx.dmabuf_img(buffer.dmabuf())?.to_framebuffer()?;
|
||||
buffers.push(ScreencastBuffer {
|
||||
dmabuf: buffer.dmabuf().clone(),
|
||||
fb,
|
||||
free: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
*self.buffers.borrow_mut() = buffers;
|
||||
self.send_buffers();
|
||||
self.damage();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn damage(&self) {
|
||||
if let Some(output) = self.output.get() {
|
||||
output.global.connector.connector.damage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl JayScreencast {
|
||||
fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), JayScreencastError> {
|
||||
let _req: Destroy = self.client.parse(self, parser)?;
|
||||
self.detach();
|
||||
self.client.remove_obj(self)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_output(&self, parser: MsgParser<'_, '_>) -> Result<(), JayScreencastError> {
|
||||
let req: SetOutput = self.client.parse(self, parser)?;
|
||||
let output = if req.output.is_some() {
|
||||
Some(self.client.lookup(req.output)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if self.destroyed.get() || !self.config_acked.get() {
|
||||
return Ok(());
|
||||
}
|
||||
self.pending.output.set(Some(output));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_allow_all_workspaces(
|
||||
&self,
|
||||
parser: MsgParser<'_, '_>,
|
||||
) -> Result<(), JayScreencastError> {
|
||||
let req: SetAllowAllWorkspaces = self.client.parse(self, parser)?;
|
||||
if self.destroyed.get() || !self.config_acked.get() {
|
||||
return Ok(());
|
||||
}
|
||||
self.pending.show_all.set(Some(req.allow_all != 0));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn allow_workspace(&self, parser: MsgParser<'_, '_>) -> Result<(), JayScreencastError> {
|
||||
let req: AllowWorkspace = self.client.parse(self, parser)?;
|
||||
let ws = self.client.lookup(req.workspace)?;
|
||||
if self.destroyed.get() || !self.config_acked.get() {
|
||||
return Ok(());
|
||||
}
|
||||
let mut sw = self.pending.show_workspaces.borrow_mut();
|
||||
let sw = sw.get_or_insert_default_ext();
|
||||
if let Some(ws) = ws.workspace.get() {
|
||||
sw.insert(ws.id);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn touch_allowed_workspaces(
|
||||
&self,
|
||||
parser: MsgParser<'_, '_>,
|
||||
) -> Result<(), JayScreencastError> {
|
||||
let _req: TouchAllowedWorkspaces = self.client.parse(self, parser)?;
|
||||
if self.destroyed.get() || !self.config_acked.get() {
|
||||
return Ok(());
|
||||
}
|
||||
self.pending
|
||||
.show_workspaces
|
||||
.borrow_mut()
|
||||
.get_or_insert_default_ext();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_use_linear_buffers(&self, parser: MsgParser<'_, '_>) -> Result<(), JayScreencastError> {
|
||||
let req: SetUseLinearBuffers = self.client.parse(self, parser)?;
|
||||
if self.destroyed.get() || !self.config_acked.get() {
|
||||
return Ok(());
|
||||
}
|
||||
self.pending.linear.set(Some(req.use_linear != 0));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_running(&self, parser: MsgParser<'_, '_>) -> Result<(), JayScreencastError> {
|
||||
let req: SetRunning = self.client.parse(self, parser)?;
|
||||
if self.destroyed.get() || !self.config_acked.get() {
|
||||
return Ok(());
|
||||
}
|
||||
self.pending.running.set(Some(req.running != 0));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn configure(self: &Rc<Self>, parser: MsgParser<'_, '_>) -> Result<(), JayScreencastError> {
|
||||
let _req: Configure = self.client.parse(self.deref(), parser)?;
|
||||
|
||||
if self.destroyed.get() || !self.config_acked.get() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut need_realloc = false;
|
||||
|
||||
if let Some(output) = self.pending.output.take() {
|
||||
let output = output.and_then(|o| o.output.get());
|
||||
if output_size(&output) != output_size(&self.output.get()) {
|
||||
need_realloc = true;
|
||||
}
|
||||
self.detach();
|
||||
if let Some(new) = &output {
|
||||
new.screencasts.set((self.client.id, self.id), self.clone());
|
||||
}
|
||||
self.output.set(output);
|
||||
}
|
||||
if let Some(linear) = self.pending.linear.take() {
|
||||
if self.linear.replace(linear) != linear {
|
||||
need_realloc = true;
|
||||
}
|
||||
}
|
||||
if let Some(show_all) = self.pending.show_all.take() {
|
||||
self.show_all.set(show_all);
|
||||
}
|
||||
if let Some(new_workspaces) = self.pending.show_workspaces.borrow_mut().take() {
|
||||
*self.show_workspaces.borrow_mut() = new_workspaces;
|
||||
}
|
||||
if let Some(running) = self.pending.running.take() {
|
||||
self.running.set(running);
|
||||
}
|
||||
|
||||
if need_realloc {
|
||||
let ctx = match self.client.state.render_ctx.get() {
|
||||
Some(ctx) => ctx,
|
||||
_ => {
|
||||
self.do_destroy();
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
if let Err(e) = self.realloc(&ctx) {
|
||||
log::error!("Could not allocate buffers: {}", ErrorFmt(e));
|
||||
self.do_destroy();
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn ack_buffers(&self, parser: MsgParser<'_, '_>) -> Result<(), JayScreencastError> {
|
||||
let req: AckBuffers = self.client.parse(self, parser)?;
|
||||
if self.destroyed.get() {
|
||||
return Ok(());
|
||||
}
|
||||
if req.serial == self.buffers_serial.get() {
|
||||
self.buffers_acked.set(true);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn ack_config(&self, parser: MsgParser<'_, '_>) -> Result<(), JayScreencastError> {
|
||||
let req: AckConfig = self.client.parse(self, parser)?;
|
||||
if self.destroyed.get() {
|
||||
return Ok(());
|
||||
}
|
||||
if req.serial == self.config_serial.get() {
|
||||
self.config_acked.set(true);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn release_buffer(&self, parser: MsgParser<'_, '_>) -> Result<(), JayScreencastError> {
|
||||
let req: ReleaseBuffer = self.client.parse(self, parser)?;
|
||||
if self.destroyed.get() || !self.buffers_acked.get() {
|
||||
return Ok(());
|
||||
}
|
||||
let idx = req.idx as usize;
|
||||
if idx > self.buffers.borrow_mut().len() {
|
||||
return Err(JayScreencastError::OutOfBounds(req.idx));
|
||||
}
|
||||
self.buffers.borrow_mut()[idx].free = true;
|
||||
if self.missed_frame.replace(false) {
|
||||
self.damage();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
object_base! {
|
||||
JayScreencast;
|
||||
|
||||
DESTROY => destroy,
|
||||
SET_OUTPUT => set_output,
|
||||
SET_ALLOW_ALL_WORKSPACES => set_allow_all_workspaces,
|
||||
ALLOW_WORKSPACE => allow_workspace,
|
||||
TOUCH_ALLOWED_WORKSPACES => touch_allowed_workspaces,
|
||||
SET_USE_LINEAR_BUFFERS => set_use_linear_buffers,
|
||||
SET_RUNNING => set_running,
|
||||
CONFIGURE => configure,
|
||||
ACK_CONFIG => ack_config,
|
||||
ACK_BUFFERS => ack_buffers,
|
||||
RELEASE_BUFFER => release_buffer,
|
||||
}
|
||||
|
||||
impl Object for JayScreencast {
|
||||
fn num_requests(&self) -> u32 {
|
||||
RELEASE_BUFFER + 1
|
||||
}
|
||||
|
||||
fn break_loops(&self) {
|
||||
self.detach();
|
||||
}
|
||||
}
|
||||
|
||||
dedicated_add_obj!(JayScreencast, JayScreencastId, screencasts);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum JayScreencastError {
|
||||
#[error("Parsing failed")]
|
||||
MsgParserError(Box<MsgParserError>),
|
||||
#[error(transparent)]
|
||||
ClientError(Box<ClientError>),
|
||||
#[error("Buffer index {0} is out-of-bounds")]
|
||||
OutOfBounds(u32),
|
||||
#[error(transparent)]
|
||||
GbmError(#[from] GbmError),
|
||||
#[error(transparent)]
|
||||
RenderError(#[from] RenderError),
|
||||
}
|
||||
efrom!(JayScreencastError, MsgParserError);
|
||||
efrom!(JayScreencastError, ClientError);
|
||||
|
||||
fn output_size(output: &Option<Rc<OutputNode>>) -> (i32, i32) {
|
||||
match output {
|
||||
Some(o) => {
|
||||
let mode = o.global.mode.get();
|
||||
(mode.width, mode.height)
|
||||
}
|
||||
_ => (0, 0),
|
||||
}
|
||||
}
|
||||
10
src/state.rs
10
src/state.rs
|
|
@ -328,6 +328,16 @@ impl State {
|
|||
for watcher in self.render_ctx_watchers.lock().values() {
|
||||
watcher.send_render_ctx(ctx);
|
||||
}
|
||||
|
||||
let mut scs = vec![];
|
||||
for client in self.clients.clients.borrow_mut().values() {
|
||||
for sc in client.data.objects.screencasts.lock().values() {
|
||||
scs.push(sc.clone());
|
||||
}
|
||||
}
|
||||
for sc in scs {
|
||||
sc.do_destroy();
|
||||
}
|
||||
}
|
||||
|
||||
fn reload_cursors(&self) {
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ impl ConnectorHandler {
|
|||
preferred_scale: Cell::new(Fixed::from_int(1)),
|
||||
hardware_cursor: Default::default(),
|
||||
jay_outputs: Default::default(),
|
||||
screencasts: Default::default(),
|
||||
});
|
||||
self.state.add_output_scale(on.preferred_scale.get());
|
||||
let mode = info.initial_mode;
|
||||
|
|
@ -217,6 +218,10 @@ impl ConnectorHandler {
|
|||
jo.send_destroyed();
|
||||
jo.output.take();
|
||||
}
|
||||
let screencasts: Vec<_> = on.screencasts.lock().values().cloned().collect();
|
||||
for sc in screencasts {
|
||||
sc.do_destroy();
|
||||
}
|
||||
global.destroyed.set(true);
|
||||
self.state.root.outputs.remove(&self.id);
|
||||
self.data.connected.set(false);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use {
|
|||
fixed::Fixed,
|
||||
ifs::{
|
||||
jay_output::JayOutput,
|
||||
jay_screencast::JayScreencast,
|
||||
wl_output::WlOutputGlobal,
|
||||
wl_seat::{
|
||||
collect_kb_foci2, wl_pointer::PendingScroll, NodeSeatState, SeatId, WlSeatGlobal,
|
||||
|
|
@ -18,7 +19,7 @@ use {
|
|||
zwlr_layer_shell_v1::{BACKGROUND, BOTTOM, OVERLAY, TOP},
|
||||
},
|
||||
rect::Rect,
|
||||
render::{Renderer, Texture},
|
||||
render::{Framebuffer, Renderer, Texture},
|
||||
state::State,
|
||||
text,
|
||||
tree::{
|
||||
|
|
@ -28,7 +29,7 @@ use {
|
|||
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt,
|
||||
linkedlist::LinkedList, scroller::Scroller,
|
||||
},
|
||||
wire::JayOutputId,
|
||||
wire::{JayOutputId, JayScreencastId},
|
||||
},
|
||||
ahash::AHashMap,
|
||||
smallvec::SmallVec,
|
||||
|
|
@ -58,9 +59,17 @@ pub struct OutputNode {
|
|||
pub lock_surface: CloneCell<Option<Rc<ExtSessionLockSurfaceV1>>>,
|
||||
pub preferred_scale: Cell<Fixed>,
|
||||
pub hardware_cursor: CloneCell<Option<Rc<dyn HardwareCursor>>>,
|
||||
pub screencasts: CopyHashMap<(ClientId, JayScreencastId), Rc<JayScreencast>>,
|
||||
}
|
||||
|
||||
impl OutputNode {
|
||||
pub fn perform_screencopies(&self, fb: &Framebuffer, tex: &Texture) {
|
||||
self.global.perform_screencopies(fb, tex);
|
||||
for sc in self.screencasts.lock().values() {
|
||||
sc.copy_texture(self, tex);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear(&self) {
|
||||
self.global.clear();
|
||||
self.workspace.set(None);
|
||||
|
|
@ -337,12 +346,31 @@ impl OutputNode {
|
|||
}
|
||||
|
||||
pub fn update_mode(&self, mode: Mode) {
|
||||
if self.global.mode.get() == mode {
|
||||
let old_mode = self.global.mode.get();
|
||||
if old_mode == mode {
|
||||
return;
|
||||
}
|
||||
self.global.mode.set(mode);
|
||||
let rect = self.calculate_extents();
|
||||
self.change_extents_(&rect);
|
||||
|
||||
if (old_mode.width, old_mode.height) != (mode.width, mode.height) {
|
||||
let mut to_destroy = vec![];
|
||||
if let Some(ctx) = self.state.render_ctx.get() {
|
||||
for sc in self.screencasts.lock().values() {
|
||||
if let Err(e) = sc.realloc(&ctx) {
|
||||
log::error!(
|
||||
"Could not re-allocate buffers for screencast after mode change: {}",
|
||||
ErrorFmt(e)
|
||||
);
|
||||
to_destroy.push(sc.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
for sc in to_destroy {
|
||||
sc.do_destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate_extents(&self) -> Rect {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ pub mod nonblock;
|
|||
pub mod num_cpus;
|
||||
pub mod numcell;
|
||||
pub mod once;
|
||||
pub mod option_ext;
|
||||
pub mod oserror;
|
||||
pub mod ptr_ext;
|
||||
pub mod queue;
|
||||
|
|
|
|||
9
src/utils/option_ext.rs
Normal file
9
src/utils/option_ext.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
pub trait OptionExt<T> {
|
||||
fn get_or_insert_default_ext(&mut self) -> &mut T;
|
||||
}
|
||||
|
||||
impl<T: Default> OptionExt<T> for Option<T> {
|
||||
fn get_or_insert_default_ext(&mut self) -> &mut T {
|
||||
self.get_or_insert_with(|| Default::default())
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue