1
0
Fork 0
forked from wry/wry

autocommit 2022-04-27 20:37:49 CEST

This commit is contained in:
Julian Orth 2022-04-27 20:37:49 +02:00
parent 57899b3f35
commit 324eb835bb
24 changed files with 478 additions and 68 deletions

View file

@ -33,6 +33,10 @@ pub trait Backend {
fn is_freestanding(&self) -> bool {
false
}
fn supports_presentation_feedback(&self) -> bool {
false
}
}
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]

View file

@ -187,6 +187,10 @@ impl Backend for MetalBackend {
fn is_freestanding(&self) -> bool {
true
}
fn supports_presentation_feedback(&self) -> bool {
true
}
}
fn dup_async_fd(state: &Rc<State>, fd: c::c_int) -> Result<AsyncFd, MetalError> {

View file

@ -1,17 +1,19 @@
use {
crate::{
async_engine::{AsyncFd, SpawnedFuture},
async_engine::{AsyncFd, Phase, SpawnedFuture},
backend::{
BackendEvent, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId, MonitorInfo,
},
backends::metal::{DrmId, MetalBackend, MetalError},
edid::Descriptor,
format::{Format, XRGB8888},
render::{Framebuffer, RenderContext},
ifs::wp_presentation_feedback::ExecutedPresentation,
render::{Framebuffer, RenderContext, RenderResult},
state::State,
utils::{
bitflags::BitflagsExt, clonecell::CloneCell, debug_fn::debug_fn, errorfmt::ErrorFmt,
numcell::NumCell, oserror::OsError, syncqueue::SyncQueue,
asyncevent::AsyncEvent, bitflags::BitflagsExt, clonecell::CloneCell,
debug_fn::debug_fn, errorfmt::ErrorFmt, numcell::NumCell, oserror::OsError,
syncqueue::SyncQueue,
},
video::{
drm::{
@ -28,15 +30,13 @@ use {
ahash::{AHashMap, AHashSet},
bstr::{BString, ByteSlice},
std::{
cell::Cell,
cell::{Cell, RefCell},
ffi::CString,
fmt::{Debug, Formatter},
rc::Rc,
},
uapi::c,
};
use crate::async_engine::Phase;
use crate::utils::asyncevent::AsyncEvent;
pub struct PendingDrmDevice {
pub id: DrmId,
@ -91,6 +91,7 @@ pub struct MetalConnector {
pub crtcs: AHashMap<DrmCrtc, Rc<MetalCrtc>>,
pub modes: Vec<DrmModeInfo>,
pub mode: CloneCell<Option<Rc<DrmModeInfo>>>,
pub refresh: Cell<u32>,
pub monitor_manufacturer: String,
pub monitor_name: String,
@ -120,6 +121,8 @@ pub struct MetalConnector {
pub on_change: OnChange,
pub present_trigger: AsyncEvent,
pub render_result: RefCell<RenderResult>,
}
pub struct ConnectorFutures {
@ -179,9 +182,17 @@ impl MetalConnector {
};
let buffer = &buffers[self.next_buffer.fetch_add(1) % buffers.len()];
if let Some(node) = self.state.root.outputs.get(&self.connector_id) {
buffer
.egl
.render(&*node, &self.state, Some(node.global.pos.get()));
let mut rr = self.render_result.borrow_mut();
buffer.egl.render(
&*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();
changes.change_object(plane.id, |c| {
@ -285,7 +296,13 @@ fn get_connectors(
state: &Rc<State>,
dev: &Rc<MetalDrmDeviceStatic>,
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 futures = vec![];
for connector in ids {
@ -385,13 +402,19 @@ fn create_connector(
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 {
id: connector,
master: dev.master.clone(),
state: state.clone(),
connector_id: state.connector_ids.next(),
crtcs,
mode: CloneCell::new(info.modes.first().cloned().map(Rc::new)),
mode: CloneCell::new(mode),
refresh: Cell::new(refresh),
monitor_manufacturer: manufacturer,
monitor_name: name,
monitor_serial_number: serial_number,
@ -411,7 +434,8 @@ fn create_connector(
crtc_id: props.get("CRTC_ID")?.map(|v| DrmCrtc(v as _)),
crtc: Default::default(),
on_change: Default::default(),
present_trigger: Default::default()
present_trigger: Default::default(),
render_result: RefCell::new(Default::default()),
});
let futures = ConnectorFutures {
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 slf = Rc::new(MetalDrmDevice { dev, connectors, futures });
let slf = Rc::new(MetalDrmDevice {
dev,
connectors,
futures,
});
self.init_drm_device(&slf)?;
@ -782,9 +810,9 @@ impl MetalBackend {
self: &Rc<Self>,
dev: &Rc<MetalDrmDevice>,
crtc_id: DrmCrtc,
_tv_sec: u32,
_tv_usec: u32,
_sequence: u32,
tv_sec: u32,
tv_usec: u32,
sequence: u32,
) {
let crtc = match dev.dev.crtcs.get(&crtc_id) {
Some(c) => c,
@ -798,6 +826,27 @@ impl MetalBackend {
if connector.has_damage.get() {
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) {

View file

@ -9,7 +9,7 @@ use {
fixed::Fixed,
format::XRGB8888,
ifs::wl_seat::PX_PER_SCROLL,
render::{Framebuffer, RenderContext, RenderError},
render::{Framebuffer, RenderContext, RenderError, RenderResult},
state::State,
utils::{
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell,
@ -53,6 +53,7 @@ use {
collections::VecDeque,
error::Error,
future::pending,
ops::DerefMut,
rc::Rc,
},
thiserror::Error,
@ -222,6 +223,7 @@ pub async fn create(state: &Rc<State>) -> Result<Rc<XBackend>, XBackendError> {
root,
scheduled_present: Default::default(),
grab_requests: Default::default(),
render_result: Default::default(),
});
data.add_output().await?;
@ -250,6 +252,7 @@ pub struct XBackend {
root: u32,
scheduled_present: AsyncQueue<Rc<XOutput>>,
grab_requests: AsyncQueue<(Rc<XSeat>, bool)>,
render_result: RefCell<RenderResult>,
}
impl XBackend {
@ -673,8 +676,18 @@ impl XBackend {
image.last_serial.set(serial);
if let Some(node) = self.state.root.outputs.get(&output.id) {
let mut rr = self.render_result.borrow_mut();
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 {

View file

@ -3,7 +3,12 @@ use {
crate::{
async_engine::{AsyncFd, SpawnedFuture},
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,
object::{Interface, Object, ObjectId, WL_DISPLAY_ID},
state::State,
@ -132,6 +137,8 @@ impl Clients {
flush_request: Default::default(),
shutdown: Default::default(),
dispatch_frame_requests: AsyncQueue::new(),
discard_presentation_feedback: Default::default(),
dispatch_presentation_feedback: Default::default(),
tracker: Default::default(),
is_xwayland,
secure,
@ -239,6 +246,8 @@ pub struct Client {
flush_request: AsyncEvent,
shutdown: AsyncEvent,
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 is_xwayland: bool,
pub secure: bool,

View file

@ -2,6 +2,7 @@ use {
crate::{
async_engine::Phase,
client::{Client, ClientError},
ifs::wp_presentation_feedback::{KIND_HW_COMPLETION, KIND_VSYNC},
object::ObjectId,
utils::{
buffd::{BufFdIn, BufFdOut, MsgParser},
@ -16,6 +17,8 @@ use {
pub async fn client(data: Rc<Client>) {
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 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 _send = data.state.eng.spawn2(Phase::PostLayout, send(data.clone()));
select! {
@ -25,6 +28,8 @@ pub async fn client(data: Rc<Client>) {
}
drop(recv);
drop(dispatch_fr);
drop(discard_fb);
drop(dispatch_fb);
data.flush_request.trigger();
match data.state.eng.timeout(5000) {
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>) {
let display = data.display().unwrap();
let recv = async {

View file

@ -16,6 +16,7 @@ use {
wl_seat::WlSeatGlobal,
wl_shm::WlShmGlobal,
wl_subcompositor::WlSubcompositorGlobal,
wp_presentation::WpPresentationGlobal,
xdg_wm_base::XdgWmBaseGlobal,
zwlr_layer_shell_v1::ZwlrLayerShellV1Global,
zwp_idle_inhibit_manager_v1::ZwpIdleInhibitManagerV1Global,
@ -135,6 +136,10 @@ impl Globals {
if backend.supports_idle() {
add_singleton!(ZwpIdleInhibitManagerV1Global);
}
if backend.supports_presentation_feedback() {
add_singleton!(WpPresentationGlobal);
}
}
pub fn name(&self) -> GlobalName {

View file

@ -18,6 +18,8 @@ pub mod wl_shm;
pub mod wl_shm_pool;
pub mod wl_subcompositor;
pub mod wl_surface;
pub mod wp_presentation;
pub mod wp_presentation_feedback;
pub mod xdg_positioner;
pub mod xdg_wm_base;
pub mod zwlr_layer_shell_v1;

View file

@ -10,8 +10,8 @@ use {
};
pub struct WlCallback {
client: Rc<Client>,
id: WlCallbackId,
pub client: Rc<Client>,
pub id: WlCallbackId,
pub tracker: Tracker<Self>,
}

View file

@ -18,6 +18,7 @@ use {
cursor::CursorSurface, wl_subsurface::WlSubsurface, xdg_surface::XdgSurfaceError,
zwlr_layer_surface_v1::ZwlrLayerSurfaceV1Error,
},
wp_presentation_feedback::WpPresentationFeedback,
},
leaks::Tracker,
object::Object,
@ -97,6 +98,7 @@ pub struct WlSurface {
pub children: RefCell<Option<Box<ParentData>>>,
ext: CloneCell<Rc<dyn SurfaceExt>>,
pub frame_requests: RefCell<Vec<Rc<WlCallback>>>,
pub presentation_feedback: RefCell<Vec<Rc<WpPresentationFeedback>>>,
seat_state: NodeSeatState,
toplevel: CloneCell<Option<Rc<dyn ToplevelNode>>>,
cursors: SmallMap<SeatId, Rc<CursorSurface>, 1>,
@ -181,6 +183,7 @@ struct PendingState {
input_region: Cell<Option<Option<Rc<Region>>>>,
frame_request: RefCell<Vec<Rc<WlCallback>>>,
damage: Cell<bool>,
presentation_feedback: RefCell<Vec<Rc<WpPresentationFeedback>>>,
}
#[derive(Default)]
@ -215,6 +218,7 @@ impl WlSurface {
children: Default::default(),
ext: CloneCell::new(client.state.none_surface_ext.clone()),
frame_requests: Default::default(),
presentation_feedback: Default::default(),
seat_state: Default::default(),
toplevel: 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 {
self.role.get() == SurfaceRole::Cursor
}
@ -497,6 +508,15 @@ impl WlSurface {
let mut pfr = self.pending.frame_request.borrow_mut();
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() {
self.input_region.set(region);

View file

@ -328,21 +328,6 @@ impl XdgToplevel {
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>) {
let (width, height) = self.toplevel_data.float_size(workspace);
self.state
@ -460,9 +445,6 @@ impl ToplevelNode for XdgToplevel {
}
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 mut states = self.states.borrow_mut();
match active {
@ -587,10 +569,8 @@ impl XdgSurfaceExt for XdgToplevel {
}
fn extents_changed(&self) {
self.notify_parent();
if self.toplevel_data.parent.get().is_some() {
self.state.tree_changed();
}
self.toplevel_data.pos.set(self.xdg.extents.get());
self.tl_extents_changed();
}
}

View file

@ -307,7 +307,8 @@ impl SurfaceExt for Xwindow {
}
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
}
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) {
self.data
.state

View file

@ -307,6 +307,7 @@ impl ZwlrLayerSurfaceV1 {
self.mapped.set(false);
self.surface.destroy_node();
self.seat_state.destroy_node(self);
self.client.state.tree_changed();
}
}

116
src/ifs/wp_presentation.rs Normal file
View 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);

View 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 {}

View file

@ -11,6 +11,7 @@ use {
},
renderer::{context::RenderContext, renderer::Renderer},
sys::{glBlendFunc, glFlush, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
RenderResult,
},
state::State,
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 c = state.theme.background_color.get();
unsafe {
@ -59,6 +67,8 @@ impl Framebuffer {
ctx: &self.ctx,
fb: &self.gl,
state,
on_output,
result,
};
node.node_render(&mut renderer, 0, 0);
if let Some(rect) = cursor_rect {

View file

@ -3,9 +3,11 @@ use {
format::{Format, ARGB8888},
ifs::{
wl_buffer::WlBuffer,
wl_callback::WlCallback,
wl_surface::{
xdg_surface::XdgSurface, zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, WlSurface,
},
wp_presentation_feedback::WpPresentationFeedback,
},
rect::Rect,
render::{
@ -31,13 +33,32 @@ use {
},
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(super) ctx: &'a Rc<RenderContext>,
pub(super) fb: &'a GlFrameBuffer,
pub(super) state: &'a State,
pub(super) on_output: bool,
pub(super) result: &'a mut RenderResult,
}
impl Renderer<'_> {
@ -271,9 +292,15 @@ impl Renderer<'_> {
} else {
self.render_buffer(&buffer, x, y);
}
let mut fr = surface.frame_requests.borrow_mut();
for cb in fr.drain(..) {
surface.client.dispatch_frame_requests.push(cb);
if self.on_output {
{
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(..));
}
}
}

View file

@ -53,7 +53,13 @@ pub fn take_screenshot(state: &State) -> Result<Screenshot, ScreenshooterError>
GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR,
)?;
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();
Ok(Screenshot { drm, bo })
}

View file

@ -1,4 +1,3 @@
use std::fmt::{Debug, Formatter};
use {
crate::{
async_engine::{AsyncEngine, SpawnedFuture},
@ -42,6 +41,7 @@ use {
jay_config::Direction,
std::{
cell::{Cell, RefCell},
fmt::{Debug, Formatter},
num::Wrapping,
rc::Rc,
sync::Arc,

View file

@ -351,6 +351,7 @@ impl ContainerNode {
} else {
self.perform_split_layout();
}
self.state.tree_changed();
self.schedule_compute_render_data();
}

View file

@ -38,13 +38,20 @@ pub trait ToplevelNode: Node {
}
fn tl_surface_active_changed(&self, active: bool) {
let data = self.tl_data();
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);
if let Some(parent) = data.parent.get() {
parent.node_child_active_changed(self.tl_as_node(), true, 1);
}
}
} else {
if self.tl_data().active_children.fetch_sub(1) == 1 {
if data.active_children.fetch_sub(1) == 1 {
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();
data.parent.set(Some(parent.clone()));
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);
}
@ -91,14 +100,13 @@ pub trait ToplevelNode: Node {
let _ = parent;
}
fn tl_notify_parent(&self) {
fn tl_active_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();
let depth = if data.active.get() {
1
} else if data.active_children.get() > 0 {
@ -109,10 +117,18 @@ pub trait ToplevelNode: Node {
if depth > 0 {
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
.clone()
.node_child_title_changed(node, data.title.borrow_mut().deref());
data.state.tree_changed();
}
fn tl_set_workspace(self: Rc<Self>, ws: &Rc<WorkspaceNode>) {
@ -253,6 +269,7 @@ impl ToplevelData {
placeholder,
workspace: ws.clone(),
});
drop(data);
self.is_fullscreen.set(true);
ws.fullscreen.set(Some(node.clone()));
node.tl_set_parent(ws.clone());

View file

@ -1,8 +1,8 @@
use std::fmt::{Debug, Formatter};
use {
crate::utils::numcell::NumCell,
std::{
cell::Cell,
fmt::{Debug, Formatter},
future::Future,
pin::Pin,
task::{Context, Poll, Waker},
@ -17,7 +17,9 @@ pub struct AsyncEvent {
impl Debug for AsyncEvent {
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()
}
}