1
0
Fork 0
forked from wry/wry

autocommit 2022-04-14 16:06:11 CEST

This commit is contained in:
Julian Orth 2022-04-14 16:06:11 +02:00
parent de199a740b
commit 35ddfbcbe3
14 changed files with 203 additions and 35 deletions

View file

@ -14,7 +14,13 @@ linear_ids!(ConnectorIds, ConnectorId);
linear_ids!(InputDeviceIds, InputDeviceId);
pub trait Backend {
fn switch_to(&self, vtnr: u32);
fn switch_to(&self, vtnr: u32) {
let _ = vtnr;
}
fn set_idle(&self, idle: bool) {
let _ = idle;
}
}
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]

View file

@ -8,11 +8,7 @@ use {
pub struct DummyBackend {}
impl Backend for DummyBackend {
fn switch_to(&self, vtnr: u32) {
let _ = vtnr;
}
}
impl Backend for DummyBackend {}
pub struct DummyOutput {
pub id: ConnectorId,

View file

@ -4,7 +4,7 @@ mod video;
use {
crate::{
async_engine::{AsyncError, AsyncFd},
async_engine::{AsyncError, AsyncFd, Phase},
backend::{
Backend, InputDevice, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId,
InputEvent, KeyState,
@ -25,6 +25,7 @@ use {
logind::{LogindError, Session},
render::RenderError,
state::State,
tasks::idle,
udev::{Udev, UdevError, UdevMonitor},
utils::{
clonecell::{CloneCell, UnsafeCellCloneSafe},
@ -34,7 +35,10 @@ use {
smallmap::SmallMap,
syncqueue::SyncQueue,
},
video::{drm::DrmError, gbm::GbmError},
video::{
drm::{DrmError, DRM_MODE_ATOMIC_ALLOW_MODESET},
gbm::GbmError,
},
},
std::{
cell::{Cell, RefCell},
@ -128,6 +132,34 @@ impl Backend for MetalBackend {
}
})
}
fn set_idle(&self, idle: bool) {
let devices = self.device_holder.drm_devices.lock();
for device in devices.values() {
let mut change = device.dev.master.change();
for connector in device.connectors.values() {
if let Some(crtc) = connector.crtc.get() {
if idle == crtc.active.value.get() {
crtc.active.value.set(!idle);
change.change_object(crtc.id, |c| {
c.change(crtc.active.id, (!idle) as _);
});
}
}
}
if let Err(e) = change.commit(DRM_MODE_ATOMIC_ALLOW_MODESET, 0) {
log::error!("Could not set monitors idle/not idle: {}", ErrorFmt(e));
return;
}
}
if !idle {
for device in devices.values() {
for connector in device.connectors.values() {
self.present(connector);
}
}
}
}
}
async fn run_(state: Rc<State>) -> Result<(), MetalError> {
@ -193,6 +225,9 @@ async fn run_(state: Rc<State>) -> Result<(), MetalError> {
return Err(MetalError::Enumerate(Box::new(e)));
}
state.backend.set(Some(metal.clone()));
let _idle = state
.eng
.spawn2(Phase::PostLayout, idle(state.clone(), metal.clone()));
pending().await
}

View file

@ -1002,7 +1002,14 @@ impl MetalBackend {
self.present(connector);
}
fn present(&self, connector: &Rc<MetalConnector>) {
pub fn present(&self, connector: &Rc<MetalConnector>) {
let crtc = match connector.crtc.get() {
Some(crtc) => crtc,
_ => return,
};
if !crtc.active.value.get() {
return;
}
let buffers = match connector.buffers.get() {
None => return,
Some(b) => b,

View file

@ -113,11 +113,7 @@ pub struct XBackend {
_grab: SpawnedFuture<()>,
}
impl Backend for XBackend {
fn switch_to(&self, _vtnr: u32) {
log::error!("X backend cannot switch vts");
}
}
impl Backend for XBackend {}
struct XBackendData {
state: Rc<State>,

View file

@ -47,7 +47,7 @@ pub enum Cmd {
pub struct ScreenshotArgs {
/// The filename of the saved screenshot
///
/// If no filename is given, the screenshot will be saved under jay-%Y-%m-%d-%H:%M:%S.qoi
/// If no filename is given, the screenshot will be saved under %Y-%m-%d-%H%M%S_jay.qoi
/// in the current directory.
///
/// The filename can contain the usual strftime parameters.

View file

@ -60,7 +60,7 @@ async fn run(screenshot: Rc<Screenshot>) {
.args
.filename
.as_deref()
.unwrap_or("jay-%Y-%m-%d-%H:%M:%S.qoi");
.unwrap_or("%Y-%m-%d-%H%M%S_jay.qoi");
let filename = Local::now().format(filename).to_string();
if let Err(e) = std::fs::write(&filename, &data) {
fatal!("Could not write `{}`: {}", filename, ErrorFmt(e));

View file

@ -17,7 +17,7 @@ use {
logger::Logger,
render::{self, RenderError},
sighand::{self, SighandError},
state::{ConnectorData, State},
state::{ConnectorData, IdleState, State},
tasks,
tree::{
container_layout, container_render_data, float_layout, float_titles, DisplayNode,
@ -32,12 +32,12 @@ use {
xwayland,
},
forker::ForkerProxy,
std::{cell::Cell, ops::Deref, rc::Rc, sync::Arc},
std::{cell::Cell, ops::Deref, rc::Rc, sync::Arc, time::Duration},
thiserror::Error,
uapi::c,
};
pub const MAX_EXTENTS: i32 = (1 << 24) - 1;
pub const MAX_EXTENTS: i32 = (1 << 22) - 1;
pub fn start_compositor(global: GlobalArgs, args: RunArgs) {
let forker = match ForkerProxy::create() {
@ -123,6 +123,12 @@ fn main_(forker: Rc<ForkerProxy>, logger: Arc<Logger>, _args: &RunArgs) -> Resul
connectors: Default::default(),
outputs: Default::default(),
status: Default::default(),
idle: IdleState {
input: Default::default(),
change: Default::default(),
timeout: Cell::new(Duration::from_secs(10)),
timeout_changed: Default::default(),
},
});
{
let dummy_output = Rc::new(OutputNode {

View file

@ -247,10 +247,12 @@ impl Xwindow {
_ => return,
};
let extents = self.surface.extents.get();
// let extents = self.xdg.extents.get();
// parent.child_active_changed(self, self.active_surfaces.get() > 0);
parent.node_child_size_changed(self, extents.width(), extents.height());
// parent.child_title_changed(self, self.title.borrow_mut().deref());
parent.node_child_title_changed(
self,
self.data.info.title.borrow_mut().as_deref().unwrap_or(""),
);
}
pub fn is_mapped(&self) -> bool {
@ -414,7 +416,9 @@ impl SizedNode for Xwindow {
fn change_extents(self: &Rc<Self>, rect: &Rect) {
let old = self.data.info.extents.replace(*rect);
if old != *rect {
self.events.push(XWaylandEvent::Configure(self.clone()));
if !self.data.info.override_redirect.get() {
self.events.push(XWaylandEvent::Configure(self.clone()));
}
if old.position() != rect.position() {
self.surface.set_absolute_position(rect.x1(), rect.y1());
}

View file

@ -25,8 +25,8 @@ use {
OutputNode, SizedNode, WorkspaceNode,
},
utils::{
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, fdcloser::FdCloser,
linkedlist::LinkedList, queue::AsyncQueue,
asyncevent::AsyncEvent, clonecell::CloneCell, copyhashmap::CopyHashMap,
errorfmt::ErrorFmt, fdcloser::FdCloser, linkedlist::LinkedList, queue::AsyncQueue,
},
wheel::Wheel,
xkbcommon::{XkbContext, XkbKeymap},
@ -37,6 +37,7 @@ use {
cell::{Cell, RefCell},
rc::Rc,
sync::Arc,
time::Duration,
},
};
@ -77,6 +78,14 @@ pub struct State {
pub connectors: CopyHashMap<ConnectorId, Rc<ConnectorData>>,
pub outputs: CopyHashMap<ConnectorId, Rc<OutputData>>,
pub status: CloneCell<Rc<String>>,
pub idle: IdleState,
}
pub struct IdleState {
pub input: Cell<bool>,
pub change: AsyncEvent,
pub timeout: Cell<Duration>,
pub timeout_changed: Cell<bool>,
}
pub struct InputDeviceData {
@ -290,4 +299,10 @@ impl State {
output.set_status(&status);
}
}
pub fn input_occurred(&self) {
if !self.idle.input.replace(true) {
self.idle.change.trigger();
}
}
}

View file

@ -1,10 +1,10 @@
mod backend;
mod connector;
mod idle;
mod input_device;
mod slow_clients;
mod start_backend;
pub use start_backend::start_backend;
use {
crate::{
state::State,
@ -12,6 +12,7 @@ use {
},
std::rc::Rc,
};
pub use {idle::idle, start_backend::start_backend};
pub async fn handle_backend_events(state: Rc<State>) {
let mut beh = BackendEventHandler { state };

101
src/tasks/idle.rs Normal file
View file

@ -0,0 +1,101 @@
use {
crate::{
async_engine::{AsyncError, Timer},
backend::Backend,
state::State,
utils::errorfmt::ErrorFmt,
},
futures_util::{select, FutureExt},
std::{rc::Rc, time::Duration},
uapi::c,
};
pub async fn idle(state: Rc<State>, backend: Rc<dyn Backend>) {
let timer = match state.eng.timer(c::CLOCK_MONOTONIC) {
Ok(t) => t,
Err(e) => {
log::error!("Could not create idle timer: {}", ErrorFmt(e));
return;
}
};
state.idle.change.trigger();
state.idle.timeout_changed.set(true);
let mut idle = Idle {
state,
backend,
timer,
idle: false,
dead: false,
last_input: now(),
};
idle.run().await;
}
struct Idle {
state: Rc<State>,
backend: Rc<dyn Backend>,
timer: Timer,
idle: bool,
dead: bool,
last_input: c::timespec,
}
impl Idle {
async fn run(&mut self) {
while !self.dead {
select! {
res = self.timer.expired().fuse() => self.handle_expired(res),
_ = self.state.idle.change.triggered().fuse() => self.handle_idle_changes(),
}
}
}
fn handle_expired(&mut self, res: Result<u64, AsyncError>) {
if let Err(e) = res {
log::error!("Could not wait for idle timer to expire: {}", ErrorFmt(e));
self.dead = true;
return;
}
let timeout = self.state.idle.timeout.get();
let since = duration_since(self.last_input);
if since >= timeout {
self.backend.set_idle(true);
self.idle = true;
} else {
self.program_timer(timeout - since);
}
}
fn handle_idle_changes(&mut self) {
if self.state.idle.timeout_changed.replace(false) {
self.program_timer(self.state.idle.timeout.get());
}
if self.state.idle.input.replace(false) {
self.last_input = now();
if self.idle {
self.backend.set_idle(false);
self.idle = false;
}
}
}
fn program_timer(&mut self, timeout: Duration) {
if let Err(e) = self.timer.program(Some(timeout), None) {
log::error!("Could not program idle timer: {}", ErrorFmt(e));
self.dead = true;
}
}
}
fn now() -> c::timespec {
let mut now = uapi::pod_zeroed();
let _ = uapi::clock_gettime(c::CLOCK_MONOTONIC, &mut now);
now
}
fn duration_since(start: c::timespec) -> Duration {
let now = now();
let nanos =
(now.tv_sec as i64 - start.tv_sec as i64) * 1_000_000_000 + (now.tv_nsec - start.tv_nsec);
Duration::from_nanos(nanos as u64)
}

View file

@ -56,6 +56,7 @@ impl DeviceHandler {
}
if any_events {
seat.mark_last_active();
self.state.input_occurred();
}
} else {
while self.dev.event().is_some() {

View file

@ -7,7 +7,7 @@ use {
},
rect::Rect,
state::State,
tree::Node,
tree::{Node, SizedNode},
utils::{
bitflags::BitflagsExt, errorfmt::ErrorFmt, linkedlist::LinkedList, queue::AsyncQueue,
},
@ -1344,15 +1344,15 @@ impl Wm {
};
self.update_override_redirect(data, event.override_redirect);
if data.info.override_redirect.get() {
let extents = Rect::new_sized(
event.x as _,
event.y as _,
event.width as _,
event.height as _,
)
.unwrap();
let changed = data.info.extents.replace(extents) != extents;
if changed {
if let Some(window) = data.window.get() {
let extents = Rect::new_sized(
event.x as _,
event.y as _,
event.width as _,
event.height as _,
)
.unwrap();
window.change_extents(&extents);
self.state.tree_changed();
}
}