autocommit 2022-04-27 20:37:49 CEST
This commit is contained in:
parent
57899b3f35
commit
324eb835bb
24 changed files with 478 additions and 68 deletions
|
|
@ -33,6 +33,10 @@ pub trait Backend {
|
||||||
fn is_freestanding(&self) -> bool {
|
fn is_freestanding(&self) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn supports_presentation_feedback(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
|
||||||
|
|
|
||||||
|
|
@ -187,6 +187,10 @@ impl Backend for MetalBackend {
|
||||||
fn is_freestanding(&self) -> bool {
|
fn is_freestanding(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn supports_presentation_feedback(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dup_async_fd(state: &Rc<State>, fd: c::c_int) -> Result<AsyncFd, MetalError> {
|
fn dup_async_fd(state: &Rc<State>, fd: c::c_int) -> Result<AsyncFd, MetalError> {
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,19 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::{AsyncFd, SpawnedFuture},
|
async_engine::{AsyncFd, Phase, SpawnedFuture},
|
||||||
backend::{
|
backend::{
|
||||||
BackendEvent, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId, MonitorInfo,
|
BackendEvent, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId, MonitorInfo,
|
||||||
},
|
},
|
||||||
backends::metal::{DrmId, MetalBackend, MetalError},
|
backends::metal::{DrmId, MetalBackend, MetalError},
|
||||||
edid::Descriptor,
|
edid::Descriptor,
|
||||||
format::{Format, XRGB8888},
|
format::{Format, XRGB8888},
|
||||||
render::{Framebuffer, RenderContext},
|
ifs::wp_presentation_feedback::ExecutedPresentation,
|
||||||
|
render::{Framebuffer, RenderContext, RenderResult},
|
||||||
state::State,
|
state::State,
|
||||||
utils::{
|
utils::{
|
||||||
bitflags::BitflagsExt, clonecell::CloneCell, debug_fn::debug_fn, errorfmt::ErrorFmt,
|
asyncevent::AsyncEvent, bitflags::BitflagsExt, clonecell::CloneCell,
|
||||||
numcell::NumCell, oserror::OsError, syncqueue::SyncQueue,
|
debug_fn::debug_fn, errorfmt::ErrorFmt, numcell::NumCell, oserror::OsError,
|
||||||
|
syncqueue::SyncQueue,
|
||||||
},
|
},
|
||||||
video::{
|
video::{
|
||||||
drm::{
|
drm::{
|
||||||
|
|
@ -28,15 +30,13 @@ use {
|
||||||
ahash::{AHashMap, AHashSet},
|
ahash::{AHashMap, AHashSet},
|
||||||
bstr::{BString, ByteSlice},
|
bstr::{BString, ByteSlice},
|
||||||
std::{
|
std::{
|
||||||
cell::Cell,
|
cell::{Cell, RefCell},
|
||||||
ffi::CString,
|
ffi::CString,
|
||||||
fmt::{Debug, Formatter},
|
fmt::{Debug, Formatter},
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
},
|
},
|
||||||
uapi::c,
|
uapi::c,
|
||||||
};
|
};
|
||||||
use crate::async_engine::Phase;
|
|
||||||
use crate::utils::asyncevent::AsyncEvent;
|
|
||||||
|
|
||||||
pub struct PendingDrmDevice {
|
pub struct PendingDrmDevice {
|
||||||
pub id: DrmId,
|
pub id: DrmId,
|
||||||
|
|
@ -91,6 +91,7 @@ pub struct MetalConnector {
|
||||||
pub crtcs: AHashMap<DrmCrtc, Rc<MetalCrtc>>,
|
pub crtcs: AHashMap<DrmCrtc, Rc<MetalCrtc>>,
|
||||||
pub modes: Vec<DrmModeInfo>,
|
pub modes: Vec<DrmModeInfo>,
|
||||||
pub mode: CloneCell<Option<Rc<DrmModeInfo>>>,
|
pub mode: CloneCell<Option<Rc<DrmModeInfo>>>,
|
||||||
|
pub refresh: Cell<u32>,
|
||||||
|
|
||||||
pub monitor_manufacturer: String,
|
pub monitor_manufacturer: String,
|
||||||
pub monitor_name: String,
|
pub monitor_name: String,
|
||||||
|
|
@ -120,6 +121,8 @@ pub struct MetalConnector {
|
||||||
pub on_change: OnChange,
|
pub on_change: OnChange,
|
||||||
|
|
||||||
pub present_trigger: AsyncEvent,
|
pub present_trigger: AsyncEvent,
|
||||||
|
|
||||||
|
pub render_result: RefCell<RenderResult>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ConnectorFutures {
|
pub struct ConnectorFutures {
|
||||||
|
|
@ -179,9 +182,17 @@ impl MetalConnector {
|
||||||
};
|
};
|
||||||
let buffer = &buffers[self.next_buffer.fetch_add(1) % buffers.len()];
|
let buffer = &buffers[self.next_buffer.fetch_add(1) % buffers.len()];
|
||||||
if let Some(node) = self.state.root.outputs.get(&self.connector_id) {
|
if let Some(node) = self.state.root.outputs.get(&self.connector_id) {
|
||||||
buffer
|
let mut rr = self.render_result.borrow_mut();
|
||||||
.egl
|
buffer.egl.render(
|
||||||
.render(&*node, &self.state, Some(node.global.pos.get()));
|
&*node,
|
||||||
|
&self.state,
|
||||||
|
Some(node.global.pos.get()),
|
||||||
|
true,
|
||||||
|
&mut rr,
|
||||||
|
);
|
||||||
|
for fr in rr.frame_requests.drain(..) {
|
||||||
|
fr.client.dispatch_frame_requests.push(fr.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let mut changes = self.master.change();
|
let mut changes = self.master.change();
|
||||||
changes.change_object(plane.id, |c| {
|
changes.change_object(plane.id, |c| {
|
||||||
|
|
@ -285,7 +296,13 @@ fn get_connectors(
|
||||||
state: &Rc<State>,
|
state: &Rc<State>,
|
||||||
dev: &Rc<MetalDrmDeviceStatic>,
|
dev: &Rc<MetalDrmDeviceStatic>,
|
||||||
ids: &[DrmConnector],
|
ids: &[DrmConnector],
|
||||||
) -> Result<(AHashMap<DrmConnector, Rc<MetalConnector>>, Vec<ConnectorFutures>), DrmError> {
|
) -> Result<
|
||||||
|
(
|
||||||
|
AHashMap<DrmConnector, Rc<MetalConnector>>,
|
||||||
|
Vec<ConnectorFutures>,
|
||||||
|
),
|
||||||
|
DrmError,
|
||||||
|
> {
|
||||||
let mut connectors = AHashMap::new();
|
let mut connectors = AHashMap::new();
|
||||||
let mut futures = vec![];
|
let mut futures = vec![];
|
||||||
for connector in ids {
|
for connector in ids {
|
||||||
|
|
@ -385,13 +402,19 @@ fn create_connector(
|
||||||
serial_number = edid.base_block.id_serial_number.to_string();
|
serial_number = edid.base_block.id_serial_number.to_string();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let mode = info.modes.first().cloned().map(Rc::new);
|
||||||
|
let refresh = mode
|
||||||
|
.as_ref()
|
||||||
|
.map(|m| 1_000_000_000_000u64 / (m.refresh_rate_millihz() as u64))
|
||||||
|
.unwrap_or(0) as u32;
|
||||||
let slf = Rc::new(MetalConnector {
|
let slf = Rc::new(MetalConnector {
|
||||||
id: connector,
|
id: connector,
|
||||||
master: dev.master.clone(),
|
master: dev.master.clone(),
|
||||||
state: state.clone(),
|
state: state.clone(),
|
||||||
connector_id: state.connector_ids.next(),
|
connector_id: state.connector_ids.next(),
|
||||||
crtcs,
|
crtcs,
|
||||||
mode: CloneCell::new(info.modes.first().cloned().map(Rc::new)),
|
mode: CloneCell::new(mode),
|
||||||
|
refresh: Cell::new(refresh),
|
||||||
monitor_manufacturer: manufacturer,
|
monitor_manufacturer: manufacturer,
|
||||||
monitor_name: name,
|
monitor_name: name,
|
||||||
monitor_serial_number: serial_number,
|
monitor_serial_number: serial_number,
|
||||||
|
|
@ -411,7 +434,8 @@ fn create_connector(
|
||||||
crtc_id: props.get("CRTC_ID")?.map(|v| DrmCrtc(v as _)),
|
crtc_id: props.get("CRTC_ID")?.map(|v| DrmCrtc(v as _)),
|
||||||
crtc: Default::default(),
|
crtc: Default::default(),
|
||||||
on_change: Default::default(),
|
on_change: Default::default(),
|
||||||
present_trigger: Default::default()
|
present_trigger: Default::default(),
|
||||||
|
render_result: RefCell::new(Default::default()),
|
||||||
});
|
});
|
||||||
let futures = ConnectorFutures {
|
let futures = ConnectorFutures {
|
||||||
present: state.eng.spawn2(Phase::Present, slf.clone().present_loop()),
|
present: state.eng.spawn2(Phase::Present, slf.clone().present_loop()),
|
||||||
|
|
@ -655,7 +679,11 @@ impl MetalBackend {
|
||||||
|
|
||||||
let (connectors, futures) = get_connectors(&self.state, &dev, &resources.connectors)?;
|
let (connectors, futures) = get_connectors(&self.state, &dev, &resources.connectors)?;
|
||||||
|
|
||||||
let slf = Rc::new(MetalDrmDevice { dev, connectors, futures });
|
let slf = Rc::new(MetalDrmDevice {
|
||||||
|
dev,
|
||||||
|
connectors,
|
||||||
|
futures,
|
||||||
|
});
|
||||||
|
|
||||||
self.init_drm_device(&slf)?;
|
self.init_drm_device(&slf)?;
|
||||||
|
|
||||||
|
|
@ -782,9 +810,9 @@ impl MetalBackend {
|
||||||
self: &Rc<Self>,
|
self: &Rc<Self>,
|
||||||
dev: &Rc<MetalDrmDevice>,
|
dev: &Rc<MetalDrmDevice>,
|
||||||
crtc_id: DrmCrtc,
|
crtc_id: DrmCrtc,
|
||||||
_tv_sec: u32,
|
tv_sec: u32,
|
||||||
_tv_usec: u32,
|
tv_usec: u32,
|
||||||
_sequence: u32,
|
sequence: u32,
|
||||||
) {
|
) {
|
||||||
let crtc = match dev.dev.crtcs.get(&crtc_id) {
|
let crtc = match dev.dev.crtcs.get(&crtc_id) {
|
||||||
Some(c) => c,
|
Some(c) => c,
|
||||||
|
|
@ -798,6 +826,27 @@ impl MetalBackend {
|
||||||
if connector.has_damage.get() {
|
if connector.has_damage.get() {
|
||||||
connector.schedule_present();
|
connector.schedule_present();
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
let global = self.state.outputs.get(&connector.connector_id);
|
||||||
|
let mut rr = connector.render_result.borrow_mut();
|
||||||
|
for fb in rr.presentation_feedbacks.drain(..) {
|
||||||
|
match &global {
|
||||||
|
Some(g) => {
|
||||||
|
fb.client
|
||||||
|
.dispatch_presentation_feedback
|
||||||
|
.push(ExecutedPresentation {
|
||||||
|
feedback: fb.clone(),
|
||||||
|
output: g.node.global.clone(),
|
||||||
|
tv_sec: tv_sec as _,
|
||||||
|
tv_nsec: tv_usec * 1000,
|
||||||
|
seq: sequence as _,
|
||||||
|
refresh: connector.refresh.get(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => fb.client.discard_presentation_feedback.push(fb.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset_planes(&self, dev: &MetalDrmDevice, changes: &mut Change) {
|
fn reset_planes(&self, dev: &MetalDrmDevice, changes: &mut Change) {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use {
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
format::XRGB8888,
|
format::XRGB8888,
|
||||||
ifs::wl_seat::PX_PER_SCROLL,
|
ifs::wl_seat::PX_PER_SCROLL,
|
||||||
render::{Framebuffer, RenderContext, RenderError},
|
render::{Framebuffer, RenderContext, RenderError, RenderResult},
|
||||||
state::State,
|
state::State,
|
||||||
utils::{
|
utils::{
|
||||||
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell,
|
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell,
|
||||||
|
|
@ -53,6 +53,7 @@ use {
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
error::Error,
|
error::Error,
|
||||||
future::pending,
|
future::pending,
|
||||||
|
ops::DerefMut,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
},
|
},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
|
|
@ -222,6 +223,7 @@ pub async fn create(state: &Rc<State>) -> Result<Rc<XBackend>, XBackendError> {
|
||||||
root,
|
root,
|
||||||
scheduled_present: Default::default(),
|
scheduled_present: Default::default(),
|
||||||
grab_requests: Default::default(),
|
grab_requests: Default::default(),
|
||||||
|
render_result: Default::default(),
|
||||||
});
|
});
|
||||||
data.add_output().await?;
|
data.add_output().await?;
|
||||||
|
|
||||||
|
|
@ -250,6 +252,7 @@ pub struct XBackend {
|
||||||
root: u32,
|
root: u32,
|
||||||
scheduled_present: AsyncQueue<Rc<XOutput>>,
|
scheduled_present: AsyncQueue<Rc<XOutput>>,
|
||||||
grab_requests: AsyncQueue<(Rc<XSeat>, bool)>,
|
grab_requests: AsyncQueue<(Rc<XSeat>, bool)>,
|
||||||
|
render_result: RefCell<RenderResult>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl XBackend {
|
impl XBackend {
|
||||||
|
|
@ -673,8 +676,18 @@ impl XBackend {
|
||||||
image.last_serial.set(serial);
|
image.last_serial.set(serial);
|
||||||
|
|
||||||
if let Some(node) = self.state.root.outputs.get(&output.id) {
|
if let Some(node) = self.state.root.outputs.get(&output.id) {
|
||||||
|
let mut rr = self.render_result.borrow_mut();
|
||||||
let fb = image.fb.get();
|
let fb = image.fb.get();
|
||||||
fb.render(&*node, &self.state, Some(node.global.pos.get()));
|
fb.render(
|
||||||
|
&*node,
|
||||||
|
&self.state,
|
||||||
|
Some(node.global.pos.get()),
|
||||||
|
true,
|
||||||
|
rr.deref_mut(),
|
||||||
|
);
|
||||||
|
for fr in rr.frame_requests.drain(..) {
|
||||||
|
fr.client.dispatch_frame_requests.push(fr.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let pp = PresentPixmap {
|
let pp = PresentPixmap {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,12 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::{AsyncFd, SpawnedFuture},
|
async_engine::{AsyncFd, SpawnedFuture},
|
||||||
client::{error::LookupError, objects::Objects},
|
client::{error::LookupError, objects::Objects},
|
||||||
ifs::{wl_callback::WlCallback, wl_display::WlDisplay, wl_registry::WlRegistry},
|
ifs::{
|
||||||
|
wl_callback::WlCallback,
|
||||||
|
wl_display::WlDisplay,
|
||||||
|
wl_registry::WlRegistry,
|
||||||
|
wp_presentation_feedback::{ExecutedPresentation, WpPresentationFeedback},
|
||||||
|
},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::{Interface, Object, ObjectId, WL_DISPLAY_ID},
|
object::{Interface, Object, ObjectId, WL_DISPLAY_ID},
|
||||||
state::State,
|
state::State,
|
||||||
|
|
@ -132,6 +137,8 @@ impl Clients {
|
||||||
flush_request: Default::default(),
|
flush_request: Default::default(),
|
||||||
shutdown: Default::default(),
|
shutdown: Default::default(),
|
||||||
dispatch_frame_requests: AsyncQueue::new(),
|
dispatch_frame_requests: AsyncQueue::new(),
|
||||||
|
discard_presentation_feedback: Default::default(),
|
||||||
|
dispatch_presentation_feedback: Default::default(),
|
||||||
tracker: Default::default(),
|
tracker: Default::default(),
|
||||||
is_xwayland,
|
is_xwayland,
|
||||||
secure,
|
secure,
|
||||||
|
|
@ -239,6 +246,8 @@ pub struct Client {
|
||||||
flush_request: AsyncEvent,
|
flush_request: AsyncEvent,
|
||||||
shutdown: AsyncEvent,
|
shutdown: AsyncEvent,
|
||||||
pub dispatch_frame_requests: AsyncQueue<Rc<WlCallback>>,
|
pub dispatch_frame_requests: AsyncQueue<Rc<WlCallback>>,
|
||||||
|
pub discard_presentation_feedback: AsyncQueue<Rc<WpPresentationFeedback>>,
|
||||||
|
pub dispatch_presentation_feedback: AsyncQueue<ExecutedPresentation>,
|
||||||
pub tracker: Tracker<Client>,
|
pub tracker: Tracker<Client>,
|
||||||
pub is_xwayland: bool,
|
pub is_xwayland: bool,
|
||||||
pub secure: bool,
|
pub secure: bool,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::Phase,
|
async_engine::Phase,
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientError},
|
||||||
|
ifs::wp_presentation_feedback::{KIND_HW_COMPLETION, KIND_VSYNC},
|
||||||
object::ObjectId,
|
object::ObjectId,
|
||||||
utils::{
|
utils::{
|
||||||
buffd::{BufFdIn, BufFdOut, MsgParser},
|
buffd::{BufFdIn, BufFdOut, MsgParser},
|
||||||
|
|
@ -16,6 +17,8 @@ use {
|
||||||
pub async fn client(data: Rc<Client>) {
|
pub async fn client(data: Rc<Client>) {
|
||||||
let mut recv = data.state.eng.spawn(receive(data.clone())).fuse();
|
let mut recv = data.state.eng.spawn(receive(data.clone())).fuse();
|
||||||
let mut dispatch_fr = data.state.eng.spawn(dispatch_fr(data.clone())).fuse();
|
let mut dispatch_fr = data.state.eng.spawn(dispatch_fr(data.clone())).fuse();
|
||||||
|
let discard_fb = data.state.eng.spawn(discard_fb(data.clone())).fuse();
|
||||||
|
let dispatch_fb = data.state.eng.spawn(dispatch_fb(data.clone())).fuse();
|
||||||
let mut shutdown = data.shutdown.triggered().fuse();
|
let mut shutdown = data.shutdown.triggered().fuse();
|
||||||
let _send = data.state.eng.spawn2(Phase::PostLayout, send(data.clone()));
|
let _send = data.state.eng.spawn2(Phase::PostLayout, send(data.clone()));
|
||||||
select! {
|
select! {
|
||||||
|
|
@ -25,6 +28,8 @@ pub async fn client(data: Rc<Client>) {
|
||||||
}
|
}
|
||||||
drop(recv);
|
drop(recv);
|
||||||
drop(dispatch_fr);
|
drop(dispatch_fr);
|
||||||
|
drop(discard_fb);
|
||||||
|
drop(dispatch_fb);
|
||||||
data.flush_request.trigger();
|
data.flush_request.trigger();
|
||||||
match data.state.eng.timeout(5000) {
|
match data.state.eng.timeout(5000) {
|
||||||
Ok(timeout) => {
|
Ok(timeout) => {
|
||||||
|
|
@ -56,6 +61,38 @@ async fn dispatch_fr(data: Rc<Client>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn discard_fb(data: Rc<Client>) {
|
||||||
|
loop {
|
||||||
|
data.discard_presentation_feedback.non_empty().await;
|
||||||
|
while let Some(fr) = data.discard_presentation_feedback.try_pop() {
|
||||||
|
fr.send_discarded();
|
||||||
|
let _ = data.remove_obj(&*fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn dispatch_fb(data: Rc<Client>) {
|
||||||
|
loop {
|
||||||
|
data.dispatch_presentation_feedback.non_empty().await;
|
||||||
|
while let Some(fr) = data.dispatch_presentation_feedback.try_pop() {
|
||||||
|
let bindings = fr.output.bindings.borrow_mut();
|
||||||
|
if let Some(bindings) = bindings.get(&data.id) {
|
||||||
|
for binding in bindings.values() {
|
||||||
|
fr.feedback.send_sync_output(binding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fr.feedback.send_presented(
|
||||||
|
fr.tv_sec,
|
||||||
|
fr.tv_nsec,
|
||||||
|
fr.refresh,
|
||||||
|
fr.seq,
|
||||||
|
KIND_VSYNC | KIND_HW_COMPLETION,
|
||||||
|
);
|
||||||
|
let _ = data.remove_obj(&*fr.feedback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn receive(data: Rc<Client>) {
|
async fn receive(data: Rc<Client>) {
|
||||||
let display = data.display().unwrap();
|
let display = data.display().unwrap();
|
||||||
let recv = async {
|
let recv = async {
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ use {
|
||||||
wl_seat::WlSeatGlobal,
|
wl_seat::WlSeatGlobal,
|
||||||
wl_shm::WlShmGlobal,
|
wl_shm::WlShmGlobal,
|
||||||
wl_subcompositor::WlSubcompositorGlobal,
|
wl_subcompositor::WlSubcompositorGlobal,
|
||||||
|
wp_presentation::WpPresentationGlobal,
|
||||||
xdg_wm_base::XdgWmBaseGlobal,
|
xdg_wm_base::XdgWmBaseGlobal,
|
||||||
zwlr_layer_shell_v1::ZwlrLayerShellV1Global,
|
zwlr_layer_shell_v1::ZwlrLayerShellV1Global,
|
||||||
zwp_idle_inhibit_manager_v1::ZwpIdleInhibitManagerV1Global,
|
zwp_idle_inhibit_manager_v1::ZwpIdleInhibitManagerV1Global,
|
||||||
|
|
@ -135,6 +136,10 @@ impl Globals {
|
||||||
if backend.supports_idle() {
|
if backend.supports_idle() {
|
||||||
add_singleton!(ZwpIdleInhibitManagerV1Global);
|
add_singleton!(ZwpIdleInhibitManagerV1Global);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if backend.supports_presentation_feedback() {
|
||||||
|
add_singleton!(WpPresentationGlobal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> GlobalName {
|
pub fn name(&self) -> GlobalName {
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ pub mod wl_shm;
|
||||||
pub mod wl_shm_pool;
|
pub mod wl_shm_pool;
|
||||||
pub mod wl_subcompositor;
|
pub mod wl_subcompositor;
|
||||||
pub mod wl_surface;
|
pub mod wl_surface;
|
||||||
|
pub mod wp_presentation;
|
||||||
|
pub mod wp_presentation_feedback;
|
||||||
pub mod xdg_positioner;
|
pub mod xdg_positioner;
|
||||||
pub mod xdg_wm_base;
|
pub mod xdg_wm_base;
|
||||||
pub mod zwlr_layer_shell_v1;
|
pub mod zwlr_layer_shell_v1;
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ use {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct WlCallback {
|
pub struct WlCallback {
|
||||||
client: Rc<Client>,
|
pub client: Rc<Client>,
|
||||||
id: WlCallbackId,
|
pub id: WlCallbackId,
|
||||||
pub tracker: Tracker<Self>,
|
pub tracker: Tracker<Self>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ use {
|
||||||
cursor::CursorSurface, wl_subsurface::WlSubsurface, xdg_surface::XdgSurfaceError,
|
cursor::CursorSurface, wl_subsurface::WlSubsurface, xdg_surface::XdgSurfaceError,
|
||||||
zwlr_layer_surface_v1::ZwlrLayerSurfaceV1Error,
|
zwlr_layer_surface_v1::ZwlrLayerSurfaceV1Error,
|
||||||
},
|
},
|
||||||
|
wp_presentation_feedback::WpPresentationFeedback,
|
||||||
},
|
},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::Object,
|
object::Object,
|
||||||
|
|
@ -97,6 +98,7 @@ pub struct WlSurface {
|
||||||
pub children: RefCell<Option<Box<ParentData>>>,
|
pub children: RefCell<Option<Box<ParentData>>>,
|
||||||
ext: CloneCell<Rc<dyn SurfaceExt>>,
|
ext: CloneCell<Rc<dyn SurfaceExt>>,
|
||||||
pub frame_requests: RefCell<Vec<Rc<WlCallback>>>,
|
pub frame_requests: RefCell<Vec<Rc<WlCallback>>>,
|
||||||
|
pub presentation_feedback: RefCell<Vec<Rc<WpPresentationFeedback>>>,
|
||||||
seat_state: NodeSeatState,
|
seat_state: NodeSeatState,
|
||||||
toplevel: CloneCell<Option<Rc<dyn ToplevelNode>>>,
|
toplevel: CloneCell<Option<Rc<dyn ToplevelNode>>>,
|
||||||
cursors: SmallMap<SeatId, Rc<CursorSurface>, 1>,
|
cursors: SmallMap<SeatId, Rc<CursorSurface>, 1>,
|
||||||
|
|
@ -181,6 +183,7 @@ struct PendingState {
|
||||||
input_region: Cell<Option<Option<Rc<Region>>>>,
|
input_region: Cell<Option<Option<Rc<Region>>>>,
|
||||||
frame_request: RefCell<Vec<Rc<WlCallback>>>,
|
frame_request: RefCell<Vec<Rc<WlCallback>>>,
|
||||||
damage: Cell<bool>,
|
damage: Cell<bool>,
|
||||||
|
presentation_feedback: RefCell<Vec<Rc<WpPresentationFeedback>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -215,6 +218,7 @@ impl WlSurface {
|
||||||
children: Default::default(),
|
children: Default::default(),
|
||||||
ext: CloneCell::new(client.state.none_surface_ext.clone()),
|
ext: CloneCell::new(client.state.none_surface_ext.clone()),
|
||||||
frame_requests: Default::default(),
|
frame_requests: Default::default(),
|
||||||
|
presentation_feedback: Default::default(),
|
||||||
seat_state: Default::default(),
|
seat_state: Default::default(),
|
||||||
toplevel: Default::default(),
|
toplevel: Default::default(),
|
||||||
cursors: Default::default(),
|
cursors: Default::default(),
|
||||||
|
|
@ -236,6 +240,13 @@ impl WlSurface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_presentation_feedback(&self, fb: &Rc<WpPresentationFeedback>) {
|
||||||
|
self.pending
|
||||||
|
.presentation_feedback
|
||||||
|
.borrow_mut()
|
||||||
|
.push(fb.clone());
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_cursor(&self) -> bool {
|
pub fn is_cursor(&self) -> bool {
|
||||||
self.role.get() == SurfaceRole::Cursor
|
self.role.get() == SurfaceRole::Cursor
|
||||||
}
|
}
|
||||||
|
|
@ -497,6 +508,15 @@ impl WlSurface {
|
||||||
let mut pfr = self.pending.frame_request.borrow_mut();
|
let mut pfr = self.pending.frame_request.borrow_mut();
|
||||||
self.frame_requests.borrow_mut().extend(pfr.drain(..));
|
self.frame_requests.borrow_mut().extend(pfr.drain(..));
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
let mut fbs = self.presentation_feedback.borrow_mut();
|
||||||
|
for fb in fbs.drain(..) {
|
||||||
|
fb.send_discarded();
|
||||||
|
let _ = self.client.remove_obj(&*fb);
|
||||||
|
}
|
||||||
|
let mut pfbs = self.pending.presentation_feedback.borrow_mut();
|
||||||
|
mem::swap(fbs.deref_mut(), pfbs.deref_mut());
|
||||||
|
}
|
||||||
{
|
{
|
||||||
if let Some(region) = self.pending.input_region.take() {
|
if let Some(region) = self.pending.input_region.take() {
|
||||||
self.input_region.set(region);
|
self.input_region.set(region);
|
||||||
|
|
|
||||||
|
|
@ -328,21 +328,6 @@ impl XdgToplevel {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn notify_parent(&self) {
|
|
||||||
let parent = match self.toplevel_data.parent.get() {
|
|
||||||
Some(p) => p,
|
|
||||||
_ => return,
|
|
||||||
};
|
|
||||||
let extents = self.xdg.extents.get();
|
|
||||||
parent.clone().node_child_active_changed(
|
|
||||||
self,
|
|
||||||
self.toplevel_data.active_children.get() > 0,
|
|
||||||
1,
|
|
||||||
);
|
|
||||||
parent.node_child_size_changed(self, extents.width(), extents.height());
|
|
||||||
parent.node_child_title_changed(self, self.toplevel_data.title.borrow_mut().deref());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn map_floating(self: &Rc<Self>, workspace: &Rc<WorkspaceNode>) {
|
fn map_floating(self: &Rc<Self>, workspace: &Rc<WorkspaceNode>) {
|
||||||
let (width, height) = self.toplevel_data.float_size(workspace);
|
let (width, height) = self.toplevel_data.float_size(workspace);
|
||||||
self.state
|
self.state
|
||||||
|
|
@ -460,9 +445,6 @@ impl ToplevelNode for XdgToplevel {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tl_set_active(&self, active: bool) {
|
fn tl_set_active(&self, active: bool) {
|
||||||
if let Some(parent) = self.toplevel_data.parent.get() {
|
|
||||||
parent.node_child_active_changed(self, active, 1);
|
|
||||||
}
|
|
||||||
let changed = {
|
let changed = {
|
||||||
let mut states = self.states.borrow_mut();
|
let mut states = self.states.borrow_mut();
|
||||||
match active {
|
match active {
|
||||||
|
|
@ -587,10 +569,8 @@ impl XdgSurfaceExt for XdgToplevel {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extents_changed(&self) {
|
fn extents_changed(&self) {
|
||||||
self.notify_parent();
|
self.toplevel_data.pos.set(self.xdg.extents.get());
|
||||||
if self.toplevel_data.parent.get().is_some() {
|
self.tl_extents_changed();
|
||||||
self.state.tree_changed();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -307,7 +307,8 @@ impl SurfaceExt for Xwindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extents_changed(&self) {
|
fn extents_changed(&self) {
|
||||||
self.tl_notify_parent();
|
self.toplevel_data.pos.set(self.surface.extents.get());
|
||||||
|
self.tl_extents_changed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -391,12 +392,6 @@ impl ToplevelNode for Xwindow {
|
||||||
&& self.data.info.input_model.get() != XInputModel::None
|
&& self.data.info.input_model.get() != XInputModel::None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tl_set_active(&self, active: bool) {
|
|
||||||
if let Some(pn) = self.toplevel_data.parent.get() {
|
|
||||||
pn.node_child_active_changed(self, active, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tl_on_activate(&self) {
|
fn tl_on_activate(&self) {
|
||||||
self.data
|
self.data
|
||||||
.state
|
.state
|
||||||
|
|
|
||||||
|
|
@ -307,6 +307,7 @@ impl ZwlrLayerSurfaceV1 {
|
||||||
self.mapped.set(false);
|
self.mapped.set(false);
|
||||||
self.surface.destroy_node();
|
self.surface.destroy_node();
|
||||||
self.seat_state.destroy_node(self);
|
self.seat_state.destroy_node(self);
|
||||||
|
self.client.state.tree_changed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
116
src/ifs/wp_presentation.rs
Normal file
116
src/ifs/wp_presentation.rs
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
pub use crate::wire::{wp_presentation::*, WpPresentationId};
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
client::{Client, ClientError},
|
||||||
|
globals::{Global, GlobalName},
|
||||||
|
ifs::wp_presentation_feedback::WpPresentationFeedback,
|
||||||
|
leaks::Tracker,
|
||||||
|
object::Object,
|
||||||
|
utils::buffd::{MsgParser, MsgParserError},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
thiserror::Error,
|
||||||
|
uapi::c,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct WpPresentationGlobal {
|
||||||
|
pub name: GlobalName,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WpPresentationGlobal {
|
||||||
|
pub fn new(name: GlobalName) -> Self {
|
||||||
|
Self { name }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bind_(
|
||||||
|
self: Rc<Self>,
|
||||||
|
id: WpPresentationId,
|
||||||
|
client: &Rc<Client>,
|
||||||
|
_version: u32,
|
||||||
|
) -> Result<(), WpPresentationError> {
|
||||||
|
let obj = Rc::new(WpPresentation {
|
||||||
|
id,
|
||||||
|
client: client.clone(),
|
||||||
|
tracker: Default::default(),
|
||||||
|
});
|
||||||
|
track!(client, obj);
|
||||||
|
client.add_client_obj(&obj)?;
|
||||||
|
obj.send_clock_id();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
global_base!(WpPresentationGlobal, WpPresentation, WpPresentationError);
|
||||||
|
|
||||||
|
impl Global for WpPresentationGlobal {
|
||||||
|
fn singleton(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn version(&self) -> u32 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simple_add_global!(WpPresentationGlobal);
|
||||||
|
|
||||||
|
pub struct WpPresentation {
|
||||||
|
pub id: WpPresentationId,
|
||||||
|
pub client: Rc<Client>,
|
||||||
|
pub tracker: Tracker<Self>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WpPresentation {
|
||||||
|
fn send_clock_id(&self) {
|
||||||
|
self.client.event(ClockId {
|
||||||
|
self_id: self.id,
|
||||||
|
clk_id: c::CLOCK_MONOTONIC as _,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), WpPresentationError> {
|
||||||
|
let _req: Destroy = self.client.parse(self, parser)?;
|
||||||
|
self.client.remove_obj(self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn feedback(&self, parser: MsgParser<'_, '_>) -> Result<(), WpPresentationError> {
|
||||||
|
let req: Feedback = self.client.parse(self, parser)?;
|
||||||
|
let surface = self.client.lookup(req.surface)?;
|
||||||
|
let fb = Rc::new(WpPresentationFeedback {
|
||||||
|
id: req.callback,
|
||||||
|
client: self.client.clone(),
|
||||||
|
surface: surface.clone(),
|
||||||
|
tracker: Default::default(),
|
||||||
|
});
|
||||||
|
track!(self.client, fb);
|
||||||
|
self.client.add_client_obj(&fb)?;
|
||||||
|
surface.add_presentation_feedback(&fb);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_base2! {
|
||||||
|
WpPresentation;
|
||||||
|
|
||||||
|
DESTROY => destroy,
|
||||||
|
FEEDBACK => feedback,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for WpPresentation {
|
||||||
|
fn num_requests(&self) -> u32 {
|
||||||
|
FEEDBACK + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simple_add_obj!(WpPresentation);
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum WpPresentationError {
|
||||||
|
#[error("Parsing failed")]
|
||||||
|
MsgParserError(#[source] Box<MsgParserError>),
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientError(Box<ClientError>),
|
||||||
|
}
|
||||||
|
efrom!(WpPresentationError, MsgParserError);
|
||||||
|
efrom!(WpPresentationError, ClientError);
|
||||||
78
src/ifs/wp_presentation_feedback.rs
Normal file
78
src/ifs/wp_presentation_feedback.rs
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
client::Client,
|
||||||
|
ifs::{
|
||||||
|
wl_output::{WlOutput, WlOutputGlobal},
|
||||||
|
wl_surface::WlSurface,
|
||||||
|
},
|
||||||
|
leaks::Tracker,
|
||||||
|
object::Object,
|
||||||
|
wire::{wp_presentation_feedback::*, WpPresentationFeedbackId},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct WpPresentationFeedback {
|
||||||
|
pub id: WpPresentationFeedbackId,
|
||||||
|
pub client: Rc<Client>,
|
||||||
|
pub surface: Rc<WlSurface>,
|
||||||
|
pub tracker: Tracker<Self>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ExecutedPresentation {
|
||||||
|
pub feedback: Rc<WpPresentationFeedback>,
|
||||||
|
pub output: Rc<WlOutputGlobal>,
|
||||||
|
pub tv_sec: u64,
|
||||||
|
pub tv_nsec: u32,
|
||||||
|
pub seq: u64,
|
||||||
|
pub refresh: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const KIND_VSYNC: u32 = 0x1;
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub const KIND_HW_CLOCK: u32 = 0x2;
|
||||||
|
pub const KIND_HW_COMPLETION: u32 = 0x4;
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub const KIND_ZERO_COPY: u32 = 0x8;
|
||||||
|
|
||||||
|
impl WpPresentationFeedback {
|
||||||
|
pub fn send_sync_output(&self, output: &WlOutput) {
|
||||||
|
self.client.event(SyncOutput {
|
||||||
|
self_id: self.id,
|
||||||
|
output: output.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_presented(&self, tv_sec: u64, tv_nsec: u32, refresh: u32, seq: u64, flags: u32) {
|
||||||
|
self.client.event(Presented {
|
||||||
|
self_id: self.id,
|
||||||
|
tv_sec_hi: (tv_sec >> 32) as u32,
|
||||||
|
tv_sec_lo: tv_sec as u32,
|
||||||
|
tv_nsec,
|
||||||
|
refresh,
|
||||||
|
seq_hi: (seq >> 32) as u32,
|
||||||
|
seq_lo: seq as u32,
|
||||||
|
flags,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_discarded(&self) {
|
||||||
|
self.client.event(Discarded { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_base2! {
|
||||||
|
WpPresentationFeedback;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for WpPresentationFeedback {
|
||||||
|
fn num_requests(&self) -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simple_add_obj!(WpPresentationFeedback);
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum WpPresentationFeedbackError {}
|
||||||
|
|
@ -11,6 +11,7 @@ use {
|
||||||
},
|
},
|
||||||
renderer::{context::RenderContext, renderer::Renderer},
|
renderer::{context::RenderContext, renderer::Renderer},
|
||||||
sys::{glBlendFunc, glFlush, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
|
sys::{glBlendFunc, glFlush, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
|
||||||
|
RenderResult,
|
||||||
},
|
},
|
||||||
state::State,
|
state::State,
|
||||||
tree::Node,
|
tree::Node,
|
||||||
|
|
@ -45,7 +46,14 @@ impl Framebuffer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(&self, node: &dyn Node, state: &State, cursor_rect: Option<Rect>) {
|
pub fn render(
|
||||||
|
&self,
|
||||||
|
node: &dyn Node,
|
||||||
|
state: &State,
|
||||||
|
cursor_rect: Option<Rect>,
|
||||||
|
on_output: bool,
|
||||||
|
result: &mut RenderResult,
|
||||||
|
) {
|
||||||
let _ = self.ctx.ctx.with_current(|| {
|
let _ = self.ctx.ctx.with_current(|| {
|
||||||
let c = state.theme.background_color.get();
|
let c = state.theme.background_color.get();
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
@ -59,6 +67,8 @@ impl Framebuffer {
|
||||||
ctx: &self.ctx,
|
ctx: &self.ctx,
|
||||||
fb: &self.gl,
|
fb: &self.gl,
|
||||||
state,
|
state,
|
||||||
|
on_output,
|
||||||
|
result,
|
||||||
};
|
};
|
||||||
node.node_render(&mut renderer, 0, 0);
|
node.node_render(&mut renderer, 0, 0);
|
||||||
if let Some(rect) = cursor_rect {
|
if let Some(rect) = cursor_rect {
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,11 @@ use {
|
||||||
format::{Format, ARGB8888},
|
format::{Format, ARGB8888},
|
||||||
ifs::{
|
ifs::{
|
||||||
wl_buffer::WlBuffer,
|
wl_buffer::WlBuffer,
|
||||||
|
wl_callback::WlCallback,
|
||||||
wl_surface::{
|
wl_surface::{
|
||||||
xdg_surface::XdgSurface, zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, WlSurface,
|
xdg_surface::XdgSurface, zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, WlSurface,
|
||||||
},
|
},
|
||||||
|
wp_presentation_feedback::WpPresentationFeedback,
|
||||||
},
|
},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::{
|
render::{
|
||||||
|
|
@ -31,13 +33,32 @@ use {
|
||||||
},
|
},
|
||||||
utils::rc_eq::rc_eq,
|
utils::rc_eq::rc_eq,
|
||||||
},
|
},
|
||||||
std::{ops::Deref, rc::Rc, slice},
|
std::{
|
||||||
|
fmt::{Debug, Formatter},
|
||||||
|
ops::Deref,
|
||||||
|
rc::Rc,
|
||||||
|
slice,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct RenderResult {
|
||||||
|
pub frame_requests: Vec<Rc<WlCallback>>,
|
||||||
|
pub presentation_feedbacks: Vec<Rc<WpPresentationFeedback>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for RenderResult {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("RenderResult").finish_non_exhaustive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Renderer<'a> {
|
pub struct Renderer<'a> {
|
||||||
pub(super) ctx: &'a Rc<RenderContext>,
|
pub(super) ctx: &'a Rc<RenderContext>,
|
||||||
pub(super) fb: &'a GlFrameBuffer,
|
pub(super) fb: &'a GlFrameBuffer,
|
||||||
pub(super) state: &'a State,
|
pub(super) state: &'a State,
|
||||||
|
pub(super) on_output: bool,
|
||||||
|
pub(super) result: &'a mut RenderResult,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer<'_> {
|
impl Renderer<'_> {
|
||||||
|
|
@ -271,9 +292,15 @@ impl Renderer<'_> {
|
||||||
} else {
|
} else {
|
||||||
self.render_buffer(&buffer, x, y);
|
self.render_buffer(&buffer, x, y);
|
||||||
}
|
}
|
||||||
let mut fr = surface.frame_requests.borrow_mut();
|
if self.on_output {
|
||||||
for cb in fr.drain(..) {
|
{
|
||||||
surface.client.dispatch_frame_requests.push(cb);
|
let mut fr = surface.frame_requests.borrow_mut();
|
||||||
|
self.result.frame_requests.extend(fr.drain(..));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut fbs = surface.presentation_feedback.borrow_mut();
|
||||||
|
self.result.presentation_feedbacks.extend(fbs.drain(..));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,13 @@ pub fn take_screenshot(state: &State) -> Result<Screenshot, ScreenshooterError>
|
||||||
GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR,
|
GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR,
|
||||||
)?;
|
)?;
|
||||||
let fb = ctx.dmabuf_fb(bo.dmabuf())?;
|
let fb = ctx.dmabuf_fb(bo.dmabuf())?;
|
||||||
fb.render(state.root.deref(), state, Some(state.root.extents.get()));
|
fb.render(
|
||||||
|
state.root.deref(),
|
||||||
|
state,
|
||||||
|
Some(state.root.extents.get()),
|
||||||
|
false,
|
||||||
|
&mut Default::default(),
|
||||||
|
);
|
||||||
let drm = ctx.gbm.drm.dup_render()?.fd().clone();
|
let drm = ctx.gbm.drm.dup_render()?.fd().clone();
|
||||||
Ok(Screenshot { drm, bo })
|
Ok(Screenshot { drm, bo })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
use std::fmt::{Debug, Formatter};
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::{AsyncEngine, SpawnedFuture},
|
async_engine::{AsyncEngine, SpawnedFuture},
|
||||||
|
|
@ -42,6 +41,7 @@ use {
|
||||||
jay_config::Direction,
|
jay_config::Direction,
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
|
fmt::{Debug, Formatter},
|
||||||
num::Wrapping,
|
num::Wrapping,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
|
|
|
||||||
|
|
@ -351,6 +351,7 @@ impl ContainerNode {
|
||||||
} else {
|
} else {
|
||||||
self.perform_split_layout();
|
self.perform_split_layout();
|
||||||
}
|
}
|
||||||
|
self.state.tree_changed();
|
||||||
self.schedule_compute_render_data();
|
self.schedule_compute_render_data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,13 +38,20 @@ pub trait ToplevelNode: Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tl_surface_active_changed(&self, active: bool) {
|
fn tl_surface_active_changed(&self, active: bool) {
|
||||||
|
let data = self.tl_data();
|
||||||
if active {
|
if active {
|
||||||
if self.tl_data().active_children.fetch_add(1) == 0 {
|
if data.active_children.fetch_add(1) == 0 {
|
||||||
self.tl_set_active(true);
|
self.tl_set_active(true);
|
||||||
|
if let Some(parent) = data.parent.get() {
|
||||||
|
parent.node_child_active_changed(self.tl_as_node(), true, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if self.tl_data().active_children.fetch_sub(1) == 1 {
|
if data.active_children.fetch_sub(1) == 1 {
|
||||||
self.tl_set_active(false);
|
self.tl_set_active(false);
|
||||||
|
if let Some(parent) = data.parent.get() {
|
||||||
|
parent.node_child_active_changed(self.tl_as_node(), false, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -83,7 +90,9 @@ pub trait ToplevelNode: Node {
|
||||||
let data = self.tl_data();
|
let data = self.tl_data();
|
||||||
data.parent.set(Some(parent.clone()));
|
data.parent.set(Some(parent.clone()));
|
||||||
data.is_floating.set(parent.node_is_float());
|
data.is_floating.set(parent.node_is_float());
|
||||||
self.tl_notify_parent();
|
self.tl_extents_changed();
|
||||||
|
self.tl_title_changed();
|
||||||
|
self.tl_active_changed();
|
||||||
self.tl_after_parent_set(parent);
|
self.tl_after_parent_set(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,14 +100,13 @@ pub trait ToplevelNode: Node {
|
||||||
let _ = parent;
|
let _ = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tl_notify_parent(&self) {
|
fn tl_active_changed(&self) {
|
||||||
let data = self.tl_data();
|
let data = self.tl_data();
|
||||||
let parent = match data.parent.get() {
|
let parent = match data.parent.get() {
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
let node = self.tl_as_node();
|
let node = self.tl_as_node();
|
||||||
let pos = data.pos.get();
|
|
||||||
let depth = if data.active.get() {
|
let depth = if data.active.get() {
|
||||||
1
|
1
|
||||||
} else if data.active_children.get() > 0 {
|
} else if data.active_children.get() > 0 {
|
||||||
|
|
@ -109,10 +117,18 @@ pub trait ToplevelNode: Node {
|
||||||
if depth > 0 {
|
if depth > 0 {
|
||||||
parent.clone().node_child_active_changed(node, true, depth);
|
parent.clone().node_child_active_changed(node, true, depth);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tl_extents_changed(&self) {
|
||||||
|
let data = self.tl_data();
|
||||||
|
let parent = match data.parent.get() {
|
||||||
|
Some(p) => p,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
let node = self.tl_as_node();
|
||||||
|
let pos = data.pos.get();
|
||||||
parent.node_child_size_changed(node, pos.width(), pos.height());
|
parent.node_child_size_changed(node, pos.width(), pos.height());
|
||||||
parent
|
data.state.tree_changed();
|
||||||
.clone()
|
|
||||||
.node_child_title_changed(node, data.title.borrow_mut().deref());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tl_set_workspace(self: Rc<Self>, ws: &Rc<WorkspaceNode>) {
|
fn tl_set_workspace(self: Rc<Self>, ws: &Rc<WorkspaceNode>) {
|
||||||
|
|
@ -253,6 +269,7 @@ impl ToplevelData {
|
||||||
placeholder,
|
placeholder,
|
||||||
workspace: ws.clone(),
|
workspace: ws.clone(),
|
||||||
});
|
});
|
||||||
|
drop(data);
|
||||||
self.is_fullscreen.set(true);
|
self.is_fullscreen.set(true);
|
||||||
ws.fullscreen.set(Some(node.clone()));
|
ws.fullscreen.set(Some(node.clone()));
|
||||||
node.tl_set_parent(ws.clone());
|
node.tl_set_parent(ws.clone());
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use std::fmt::{Debug, Formatter};
|
|
||||||
use {
|
use {
|
||||||
crate::utils::numcell::NumCell,
|
crate::utils::numcell::NumCell,
|
||||||
std::{
|
std::{
|
||||||
cell::Cell,
|
cell::Cell,
|
||||||
|
fmt::{Debug, Formatter},
|
||||||
future::Future,
|
future::Future,
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
task::{Context, Poll, Waker},
|
task::{Context, Poll, Waker},
|
||||||
|
|
@ -17,7 +17,9 @@ pub struct AsyncEvent {
|
||||||
|
|
||||||
impl Debug for AsyncEvent {
|
impl Debug for AsyncEvent {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_struct("AsyncEvent").field("triggers", &self.triggers.get()).finish_non_exhaustive()
|
f.debug_struct("AsyncEvent")
|
||||||
|
.field("triggers", &self.triggers.get())
|
||||||
|
.finish_non_exhaustive()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
15
wire/wp_presentation.txt
Normal file
15
wire/wp_presentation.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
# requests
|
||||||
|
|
||||||
|
msg destroy = 0 {
|
||||||
|
}
|
||||||
|
|
||||||
|
msg feedback = 1 {
|
||||||
|
surface: id(wl_surface),
|
||||||
|
callback: id(wp_presentation_feedback),
|
||||||
|
}
|
||||||
|
|
||||||
|
# events
|
||||||
|
|
||||||
|
msg clock_id = 0 {
|
||||||
|
clk_id: u32,
|
||||||
|
}
|
||||||
19
wire/wp_presentation_feedback.txt
Normal file
19
wire/wp_presentation_feedback.txt
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# events
|
||||||
|
|
||||||
|
msg sync_output = 0 {
|
||||||
|
output: id(wl_output),
|
||||||
|
}
|
||||||
|
|
||||||
|
msg presented = 1 {
|
||||||
|
tv_sec_hi : u32,
|
||||||
|
tv_sec_lo : u32,
|
||||||
|
tv_nsec : u32,
|
||||||
|
refresh : u32,
|
||||||
|
seq_hi : u32,
|
||||||
|
seq_lo : u32,
|
||||||
|
flags : u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
msg discarded = 2 {
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue