autocommit 2022-04-04 00:28:58 CEST
This commit is contained in:
parent
9ec1c5c995
commit
1f71290dab
21 changed files with 1217 additions and 132 deletions
|
|
@ -9,14 +9,25 @@ pub trait Backend {
|
||||||
fn switch_to(&self, vtnr: u32);
|
fn switch_to(&self, vtnr: u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Output {
|
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
|
||||||
|
pub struct Mode {
|
||||||
|
pub width: i32,
|
||||||
|
pub height: i32,
|
||||||
|
pub refresh_rate: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Connector {
|
||||||
fn id(&self) -> OutputId;
|
fn id(&self) -> OutputId;
|
||||||
fn removed(&self) -> bool;
|
fn event(&self) -> Option<ConnectorEvent>;
|
||||||
fn width(&self) -> i32;
|
|
||||||
fn height(&self) -> i32;
|
|
||||||
fn on_change(&self, cb: Rc<dyn Fn()>);
|
fn on_change(&self, cb: Rc<dyn Fn()>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ConnectorEvent {
|
||||||
|
Removed,
|
||||||
|
ModeChanged(Mode),
|
||||||
|
}
|
||||||
|
|
||||||
pub trait InputDevice {
|
pub trait InputDevice {
|
||||||
fn id(&self) -> InputDeviceId;
|
fn id(&self) -> InputDeviceId;
|
||||||
fn removed(&self) -> bool;
|
fn removed(&self) -> bool;
|
||||||
|
|
@ -49,7 +60,7 @@ pub enum InputDeviceAccelProfile {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum BackendEvent {
|
pub enum BackendEvent {
|
||||||
NewOutput(Rc<dyn Output>),
|
NewConnector(Rc<dyn Connector>),
|
||||||
NewInputDevice(Rc<dyn InputDevice>),
|
NewInputDevice(Rc<dyn InputDevice>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::backend::{Backend, Output, OutputId};
|
use crate::backend::{Backend, Connector, ConnectorEvent, OutputId};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct DummyBackend {}
|
pub struct DummyBackend {}
|
||||||
|
|
@ -13,21 +13,13 @@ pub struct DummyOutput {
|
||||||
pub id: OutputId,
|
pub id: OutputId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Output for DummyOutput {
|
impl Connector for DummyOutput {
|
||||||
fn id(&self) -> OutputId {
|
fn id(&self) -> OutputId {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn removed(&self) -> bool {
|
fn event(&self) -> Option<ConnectorEvent> {
|
||||||
false
|
None
|
||||||
}
|
|
||||||
|
|
||||||
fn width(&self) -> i32 {
|
|
||||||
100
|
|
||||||
}
|
|
||||||
|
|
||||||
fn height(&self) -> i32 {
|
|
||||||
100
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_change(&self, _cb: Rc<dyn Fn()>) {
|
fn on_change(&self, _cb: Rc<dyn Fn()>) {
|
||||||
|
|
|
||||||
|
|
@ -232,6 +232,7 @@ impl MetalBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_drm_change(self: &Rc<Self>, _dev: UdevDevice) -> Option<()> {
|
fn handle_drm_change(self: &Rc<Self>, _dev: UdevDevice) -> Option<()> {
|
||||||
|
// TODO: Handle monitor connections and connector hotplug
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::async_engine::{AsyncFd, SpawnedFuture};
|
use crate::async_engine::{AsyncFd, SpawnedFuture};
|
||||||
use crate::backend::{BackendEvent, Output, OutputId};
|
use crate::backend::{BackendEvent, Connector, ConnectorEvent, Mode, OutputId};
|
||||||
use crate::backends::metal::{DrmId, MetalBackend, MetalError};
|
use crate::backends::metal::{DrmId, MetalBackend, MetalError};
|
||||||
use crate::drm::drm::{
|
use crate::drm::drm::{
|
||||||
drm_mode_modeinfo, Change, ConnectorStatus, ConnectorType, DrmBlob, DrmConnector, DrmCrtc,
|
drm_mode_modeinfo, Change, ConnectorStatus, ConnectorType, DrmBlob, DrmConnector, DrmCrtc,
|
||||||
|
|
@ -24,6 +24,7 @@ use std::ffi::CString;
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use uapi::c;
|
use uapi::c;
|
||||||
|
use crate::utils::syncqueue::SyncQueue;
|
||||||
|
|
||||||
pub struct PendingDrmDevice {
|
pub struct PendingDrmDevice {
|
||||||
pub id: DrmId,
|
pub id: DrmId,
|
||||||
|
|
@ -77,6 +78,8 @@ pub struct MetalConnector {
|
||||||
pub modes: Vec<DrmModeInfo>,
|
pub modes: Vec<DrmModeInfo>,
|
||||||
pub mode: CloneCell<Option<Rc<DrmModeInfo>>>,
|
pub mode: CloneCell<Option<Rc<DrmModeInfo>>>,
|
||||||
|
|
||||||
|
pub events: SyncQueue<ConnectorEvent>,
|
||||||
|
|
||||||
pub buffers: CloneCell<Option<Rc<[RenderBuffer; 2]>>>,
|
pub buffers: CloneCell<Option<Rc<[RenderBuffer; 2]>>>,
|
||||||
pub next_buffer: NumCell<usize>,
|
pub next_buffer: NumCell<usize>,
|
||||||
|
|
||||||
|
|
@ -110,27 +113,13 @@ impl Debug for OnChange {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Output for MetalConnector {
|
impl Connector for MetalConnector {
|
||||||
fn id(&self) -> OutputId {
|
fn id(&self) -> OutputId {
|
||||||
self.output_id
|
self.output_id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn removed(&self) -> bool {
|
fn event(&self) -> Option<ConnectorEvent> {
|
||||||
false
|
self.events.pop()
|
||||||
}
|
|
||||||
|
|
||||||
fn width(&self) -> i32 {
|
|
||||||
match self.mode.get() {
|
|
||||||
Some(m) => m.hdisplay as _,
|
|
||||||
_ => 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn height(&self) -> i32 {
|
|
||||||
match self.mode.get() {
|
|
||||||
Some(m) => m.vdisplay as _,
|
|
||||||
_ => 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_change(&self, cb: Rc<dyn Fn()>) {
|
fn on_change(&self, cb: Rc<dyn Fn()>) {
|
||||||
|
|
@ -223,12 +212,22 @@ fn create_connector(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let props = collect_properties(&dev.master, connector)?;
|
let props = collect_properties(&dev.master, connector)?;
|
||||||
|
let mode = info.modes.first().cloned().map(Rc::new);
|
||||||
|
let events = SyncQueue::default();
|
||||||
|
if let Some(mode) = &mode {
|
||||||
|
events.push(ConnectorEvent::ModeChanged(Mode {
|
||||||
|
width: mode.hdisplay as _,
|
||||||
|
height: mode.vdisplay as _,
|
||||||
|
refresh_rate: mode.refresh_rate(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
Ok(MetalConnector {
|
Ok(MetalConnector {
|
||||||
id: connector,
|
id: connector,
|
||||||
master: dev.master.clone(),
|
master: dev.master.clone(),
|
||||||
output_id: state.output_ids.next(),
|
output_id: state.output_ids.next(),
|
||||||
crtcs,
|
crtcs,
|
||||||
mode: CloneCell::new(info.modes.first().cloned().map(Rc::new)),
|
mode: CloneCell::new(mode),
|
||||||
|
events,
|
||||||
modes: info.modes,
|
modes: info.modes,
|
||||||
buffers: Default::default(),
|
buffers: Default::default(),
|
||||||
next_buffer: Default::default(),
|
next_buffer: Default::default(),
|
||||||
|
|
@ -486,6 +485,9 @@ impl MetalBackend {
|
||||||
self.init_drm_device(&slf)?;
|
self.init_drm_device(&slf)?;
|
||||||
|
|
||||||
for connector in slf.connectors.values() {
|
for connector in slf.connectors.values() {
|
||||||
|
self.state
|
||||||
|
.backend_events
|
||||||
|
.push(BackendEvent::NewConnector(connector.clone()));
|
||||||
if connector.primary_plane.get().is_some() {
|
if connector.primary_plane.get().is_some() {
|
||||||
self.start_connector(connector);
|
self.start_connector(connector);
|
||||||
}
|
}
|
||||||
|
|
@ -880,9 +882,6 @@ impl MetalBackend {
|
||||||
|
|
||||||
fn start_connector(&self, connector: &Rc<MetalConnector>) {
|
fn start_connector(&self, connector: &Rc<MetalConnector>) {
|
||||||
let mode = connector.mode.get().unwrap();
|
let mode = connector.mode.get().unwrap();
|
||||||
self.state
|
|
||||||
.backend_events
|
|
||||||
.push(BackendEvent::NewOutput(connector.clone()));
|
|
||||||
log::info!(
|
log::info!(
|
||||||
"Initialized connector {}-{} with mode {:?}",
|
"Initialized connector {}-{} with mode {:?}",
|
||||||
connector.connector_type,
|
connector.connector_type,
|
||||||
|
|
@ -905,7 +904,7 @@ impl MetalBackend {
|
||||||
if let Some(node) = self.state.root.outputs.get(&connector.output_id) {
|
if let Some(node) = self.state.root.outputs.get(&connector.output_id) {
|
||||||
buffer
|
buffer
|
||||||
.egl
|
.egl
|
||||||
.render(&*node, &self.state, Some(node.position.get()));
|
.render(&*node, &self.state, Some(node.global.pos.get()));
|
||||||
}
|
}
|
||||||
let mut changes = connector.master.change();
|
let mut changes = connector.master.change();
|
||||||
changes.change_object(plane.id, |c| {
|
changes.change_object(plane.id, |c| {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
use crate::async_engine::{Phase, SpawnedFuture};
|
use crate::async_engine::{Phase, SpawnedFuture};
|
||||||
use crate::backend::{
|
use crate::backend::{Backend, BackendEvent, InputDevice, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId, InputEvent, KeyState, Connector, OutputId, ScrollAxis, Mode, ConnectorEvent};
|
||||||
Backend, BackendEvent, InputDevice, InputDeviceAccelProfile, InputDeviceCapability,
|
|
||||||
InputDeviceId, InputEvent, KeyState, Output, OutputId, ScrollAxis,
|
|
||||||
};
|
|
||||||
use crate::drm::drm::{Drm, DrmError};
|
use crate::drm::drm::{Drm, DrmError};
|
||||||
use crate::drm::gbm::{GbmDevice, GbmError, GBM_BO_USE_RENDERING};
|
use crate::drm::gbm::{GbmDevice, GbmError, GBM_BO_USE_RENDERING};
|
||||||
use crate::drm::{ModifiedFormat, INVALID_MODIFIER};
|
use crate::drm::{ModifiedFormat, INVALID_MODIFIER};
|
||||||
|
|
@ -42,6 +39,7 @@ use std::cell::{Cell, RefCell};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
use crate::utils::syncqueue::SyncQueue;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum XBackendError {
|
pub enum XBackendError {
|
||||||
|
|
@ -396,7 +394,7 @@ impl XBackendData {
|
||||||
id: self.state.output_ids.next(),
|
id: self.state.output_ids.next(),
|
||||||
_backend: self.clone(),
|
_backend: self.clone(),
|
||||||
window: window_id,
|
window: window_id,
|
||||||
removed: Cell::new(false),
|
events: Default::default(),
|
||||||
width: Cell::new(0),
|
width: Cell::new(0),
|
||||||
height: Cell::new(0),
|
height: Cell::new(0),
|
||||||
serial: Default::default(),
|
serial: Default::default(),
|
||||||
|
|
@ -479,7 +477,7 @@ impl XBackendData {
|
||||||
self.outputs.set(window_id, output.clone());
|
self.outputs.set(window_id, output.clone());
|
||||||
self.state
|
self.state
|
||||||
.backend_events
|
.backend_events
|
||||||
.push(BackendEvent::NewOutput(output.clone()));
|
.push(BackendEvent::NewConnector(output.clone()));
|
||||||
self.present(&output).await;
|
self.present(&output).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -636,10 +634,6 @@ impl XBackendData {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn present(&self, output: &Rc<XOutput>) {
|
async fn present(&self, output: &Rc<XOutput>) {
|
||||||
if output.removed.get() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let serial = output.serial.fetch_add(1);
|
let serial = output.serial.fetch_add(1);
|
||||||
|
|
||||||
let image = &output.images[output.next_image.fetch_add(1) % output.images.len()];
|
let image = &output.images[output.next_image.fetch_add(1) % output.images.len()];
|
||||||
|
|
@ -648,7 +642,7 @@ impl XBackendData {
|
||||||
|
|
||||||
if let Some(node) = self.state.root.outputs.get(&output.id) {
|
if let Some(node) = self.state.root.outputs.get(&output.id) {
|
||||||
let fb = image.fb.get();
|
let fb = image.fb.get();
|
||||||
fb.render(&*node, &self.state, Some(node.position.get()));
|
fb.render(&*node, &self.state, Some(node.global.pos.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let pp = PresentPixmap {
|
let pp = PresentPixmap {
|
||||||
|
|
@ -795,7 +789,7 @@ impl XBackendData {
|
||||||
Some(o) => o,
|
Some(o) => o,
|
||||||
_ => return Ok(()),
|
_ => return Ok(()),
|
||||||
};
|
};
|
||||||
output.removed.set(true);
|
output.events.push(ConnectorEvent::Removed);
|
||||||
output.changed();
|
output.changed();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -820,6 +814,11 @@ impl XBackendData {
|
||||||
old.fb.set(new.fb.get());
|
old.fb.set(new.fb.get());
|
||||||
old.pixmap.set(new.pixmap.get());
|
old.pixmap.set(new.pixmap.get());
|
||||||
}
|
}
|
||||||
|
output.events.push(ConnectorEvent::ModeChanged(Mode {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
refresh_rate: 60, // TODO
|
||||||
|
}));
|
||||||
output.changed();
|
output.changed();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -830,7 +829,7 @@ struct XOutput {
|
||||||
id: OutputId,
|
id: OutputId,
|
||||||
_backend: Rc<XBackendData>,
|
_backend: Rc<XBackendData>,
|
||||||
window: u32,
|
window: u32,
|
||||||
removed: Cell<bool>,
|
events: SyncQueue<ConnectorEvent>,
|
||||||
width: Cell<i32>,
|
width: Cell<i32>,
|
||||||
height: Cell<i32>,
|
height: Cell<i32>,
|
||||||
serial: NumCell<u32>,
|
serial: NumCell<u32>,
|
||||||
|
|
@ -856,21 +855,13 @@ impl XOutput {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Output for XOutput {
|
impl Connector for XOutput {
|
||||||
fn id(&self) -> OutputId {
|
fn id(&self) -> OutputId {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn removed(&self) -> bool {
|
fn event(&self) -> Option<ConnectorEvent> {
|
||||||
self.removed.get()
|
self.events.pop()
|
||||||
}
|
|
||||||
|
|
||||||
fn width(&self) -> i32 {
|
|
||||||
self.width.get()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn height(&self) -> i32 {
|
|
||||||
self.height.get()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_change(&self, cb: Rc<dyn Fn()>) {
|
fn on_change(&self, cb: Rc<dyn Fn()>) {
|
||||||
|
|
|
||||||
|
|
@ -120,12 +120,12 @@ fn main_(logger: Arc<Logger>, _args: &RunArgs) -> Result<(), MainError> {
|
||||||
{
|
{
|
||||||
let dummy_output = Rc::new(OutputNode {
|
let dummy_output = Rc::new(OutputNode {
|
||||||
id: state.node_ids.next(),
|
id: state.node_ids.next(),
|
||||||
position: Default::default(),
|
|
||||||
global: Rc::new(WlOutputGlobal::new(
|
global: Rc::new(WlOutputGlobal::new(
|
||||||
state.globals.name(),
|
state.globals.name(),
|
||||||
Rc::new(DummyOutput {
|
Rc::new(DummyOutput {
|
||||||
id: state.output_ids.next(),
|
id: state.output_ids.next(),
|
||||||
}),
|
}),
|
||||||
|
0,
|
||||||
)),
|
)),
|
||||||
workspaces: Default::default(),
|
workspaces: Default::default(),
|
||||||
workspace: Default::default(),
|
workspace: Default::default(),
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ pub use sys::{
|
||||||
drm_mode_modeinfo, DRM_CLIENT_CAP_ATOMIC, DRM_MODE_ATOMIC_ALLOW_MODESET,
|
drm_mode_modeinfo, DRM_CLIENT_CAP_ATOMIC, DRM_MODE_ATOMIC_ALLOW_MODESET,
|
||||||
DRM_MODE_ATOMIC_NONBLOCK, DRM_MODE_PAGE_FLIP_EVENT,
|
DRM_MODE_ATOMIC_NONBLOCK, DRM_MODE_PAGE_FLIP_EVENT,
|
||||||
};
|
};
|
||||||
|
use crate::utils::vec_ext::VecExt;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum DrmError {
|
pub enum DrmError {
|
||||||
|
|
@ -63,6 +64,8 @@ pub enum DrmError {
|
||||||
GetPropBlob(#[source] OsError),
|
GetPropBlob(#[source] OsError),
|
||||||
#[error("Property has an invalid size")]
|
#[error("Property has an invalid size")]
|
||||||
InvalidProbSize,
|
InvalidProbSize,
|
||||||
|
#[error("Property has a size that is not a multiple of the vector type")]
|
||||||
|
UnalignedPropSize,
|
||||||
#[error("Could not perform drm properties ioctl")]
|
#[error("Could not perform drm properties ioctl")]
|
||||||
GetProperties(#[source] OsError),
|
GetProperties(#[source] OsError),
|
||||||
#[error("Could not perform drm atomic ioctl")]
|
#[error("Could not perform drm atomic ioctl")]
|
||||||
|
|
@ -316,6 +319,25 @@ impl DrmMaster {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getblob_vec<T: Pod>(&self, blob: DrmBlob) -> Result<Vec<T>, DrmError> {
|
||||||
|
assert_ne!(mem::size_of::<T>(), 0);
|
||||||
|
let mut vec = vec![];
|
||||||
|
loop {
|
||||||
|
let (_, bytes) = vec.split_at_spare_mut_bytes_ext();
|
||||||
|
match mode_getprobblob(self.raw(), blob.0, bytes) {
|
||||||
|
Err(e) => return Err(DrmError::GetPropBlob(e)),
|
||||||
|
Ok(n) if n % mem::size_of::<T>() != 0 => return Err(DrmError::UnalignedPropSize),
|
||||||
|
Ok(n) if n <= bytes.len() => {
|
||||||
|
unsafe {
|
||||||
|
vec.set_len(n / mem::size_of::<T>());
|
||||||
|
}
|
||||||
|
return Ok(vec);
|
||||||
|
}
|
||||||
|
Ok(n) => vec.reserve_exact(n / mem::size_of::<T>()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn event(&self) -> Result<Option<DrmEvent>, DrmError> {
|
pub fn event(&self) -> Result<Option<DrmEvent>, DrmError> {
|
||||||
if self.events.is_empty() {
|
if self.events.is_empty() {
|
||||||
let mut buf = self.buf.borrow_mut();
|
let mut buf = self.buf.borrow_mut();
|
||||||
|
|
@ -570,6 +592,16 @@ impl DrmModeInfo {
|
||||||
name,
|
name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn refresh_rate(&self) -> u32 {
|
||||||
|
let clock_mhz = self.clock as u64 * 1_000_000;
|
||||||
|
let htotal = self.htotal as u64;
|
||||||
|
let vtotal = self.vtotal as u64;
|
||||||
|
(((clock_mhz / htotal) + (vtotal / 2)) / vtotal) as u32
|
||||||
|
// simplifies to
|
||||||
|
// clock_mhz / (htotal * vtotal) + 1/2
|
||||||
|
// why round up (+1/2) instead of down?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
||||||
1059
src/edid.rs
Normal file
1059
src/edid.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::backend::Output;
|
use crate::backend::Connector;
|
||||||
use crate::client::{Client, ClientError, ClientId};
|
use crate::client::{Client, ClientError, ClientId};
|
||||||
use crate::globals::{Global, GlobalName};
|
use crate::globals::{Global, GlobalName};
|
||||||
use crate::ifs::zxdg_output_v1::ZxdgOutputV1;
|
use crate::ifs::zxdg_output_v1::ZxdgOutputV1;
|
||||||
|
|
@ -17,6 +17,7 @@ use std::cell::{Cell, RefCell};
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
use crate::backend;
|
||||||
|
|
||||||
const SP_UNKNOWN: i32 = 0;
|
const SP_UNKNOWN: i32 = 0;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
@ -52,18 +53,20 @@ const MODE_PREFERRED: u32 = 2;
|
||||||
|
|
||||||
pub struct WlOutputGlobal {
|
pub struct WlOutputGlobal {
|
||||||
name: GlobalName,
|
name: GlobalName,
|
||||||
output: Rc<dyn Output>,
|
pub connector: Rc<dyn Connector>,
|
||||||
pos: Cell<Rect>,
|
pub pos: Cell<Rect>,
|
||||||
|
pub mode: Cell<backend::Mode>,
|
||||||
pub node: CloneCell<Option<Rc<OutputNode>>>,
|
pub node: CloneCell<Option<Rc<OutputNode>>>,
|
||||||
pub bindings: RefCell<AHashMap<ClientId, AHashMap<WlOutputId, Rc<WlOutput>>>>,
|
pub bindings: RefCell<AHashMap<ClientId, AHashMap<WlOutputId, Rc<WlOutput>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WlOutputGlobal {
|
impl WlOutputGlobal {
|
||||||
pub fn new(name: GlobalName, output: Rc<dyn Output>) -> Self {
|
pub fn new(name: GlobalName, connector: Rc<dyn Connector>, x1: i32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
output: output.clone(),
|
connector: connector.clone(),
|
||||||
pos: Cell::new(Rect::new_sized(0, 0, output.width(), output.height()).unwrap()),
|
pos: Cell::new(Rect::new_empty(x1, 0)),
|
||||||
|
mode: Default::default(),
|
||||||
node: Default::default(),
|
node: Default::default(),
|
||||||
bindings: Default::default(),
|
bindings: Default::default(),
|
||||||
}
|
}
|
||||||
|
|
@ -73,30 +76,18 @@ impl WlOutputGlobal {
|
||||||
self.pos.get()
|
self.pos.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_properties(&self) {
|
pub fn send_mode(&self) {
|
||||||
let width = self.output.width();
|
let bindings = self.bindings.borrow_mut();
|
||||||
let height = self.output.height();
|
for binding in bindings.values() {
|
||||||
|
for binding in binding.values() {
|
||||||
let pos = self.pos.get();
|
binding.send_geometry();
|
||||||
let old_width = pos.width();
|
binding.send_mode();
|
||||||
let old_height = pos.height();
|
binding.send_scale();
|
||||||
let changed = old_width != width || old_height != height;
|
binding.send_done();
|
||||||
|
binding.client.flush();
|
||||||
if changed {
|
let xdg = binding.xdg_outputs.lock();
|
||||||
self.pos
|
for xdg in xdg.values() {
|
||||||
.set(Rect::new_sized(pos.x1(), pos.y1(), width, height).unwrap());
|
xdg.send_updates();
|
||||||
let bindings = self.bindings.borrow_mut();
|
|
||||||
for binding in bindings.values() {
|
|
||||||
for binding in binding.values() {
|
|
||||||
binding.send_geometry();
|
|
||||||
binding.send_mode();
|
|
||||||
binding.send_scale();
|
|
||||||
binding.send_done();
|
|
||||||
binding.client.flush();
|
|
||||||
let xdg = binding.xdg_outputs.lock();
|
|
||||||
for xdg in xdg.values() {
|
|
||||||
xdg.send_updates();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ impl XdgPopup {
|
||||||
let mut rel_pos = positioner.get_position(false, false);
|
let mut rel_pos = positioner.get_position(false, false);
|
||||||
let mut abs_pos = rel_pos.move_(parent_abs.x1(), parent_abs.y1());
|
let mut abs_pos = rel_pos.move_(parent_abs.x1(), parent_abs.y1());
|
||||||
if let Some(ws) = parent.workspace.get() {
|
if let Some(ws) = parent.workspace.get() {
|
||||||
let output_pos = ws.output.get().position.get();
|
let output_pos = ws.output.get().global.pos.get();
|
||||||
let mut overflow = output_pos.get_overflow(&abs_pos);
|
let mut overflow = output_pos.get_overflow(&abs_pos);
|
||||||
if !overflow.is_contained() {
|
if !overflow.is_contained() {
|
||||||
let mut flip_x = positioner.ca.contains(CA::FLIP_X) && overflow.x_overflow();
|
let mut flip_x = positioner.ca.contains(CA::FLIP_X) && overflow.x_overflow();
|
||||||
|
|
|
||||||
|
|
@ -262,7 +262,7 @@ impl ZwlrLayerSurfaceV1 {
|
||||||
if anchor == 0 {
|
if anchor == 0 {
|
||||||
anchor = LEFT | RIGHT | TOP | BOTTOM;
|
anchor = LEFT | RIGHT | TOP | BOTTOM;
|
||||||
}
|
}
|
||||||
let opos = self.output.position.get();
|
let opos = self.output.global.pos.get();
|
||||||
let mut x1 = opos.x1();
|
let mut x1 = opos.x1();
|
||||||
let mut y1 = opos.y1();
|
let mut y1 = opos.y1();
|
||||||
if anchor.contains(LEFT) {
|
if anchor.contains(LEFT) {
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ impl ZwlrLayerShellV1 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
log::info!("output = {:?}", output.position.get());
|
log::info!("output = {:?}", output.global.pos.get());
|
||||||
if req.layer > OVERLAY {
|
if req.layer > OVERLAY {
|
||||||
return Err(GetLayerSurfaceError::UnknownLayer(req.layer));
|
return Err(GetLayerSurfaceError::UnknownLayer(req.layer));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,7 @@ mod wire_xcon;
|
||||||
mod xcon;
|
mod xcon;
|
||||||
mod xkbcommon;
|
mod xkbcommon;
|
||||||
mod xwayland;
|
mod xwayland;
|
||||||
|
mod edid;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
cli::main();
|
cli::main();
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ pub struct Renderer<'a> {
|
||||||
|
|
||||||
impl Renderer<'_> {
|
impl Renderer<'_> {
|
||||||
pub fn render_output(&mut self, output: &OutputNode, x: i32, y: i32) {
|
pub fn render_output(&mut self, output: &OutputNode, x: i32, y: i32) {
|
||||||
let opos = output.position.get();
|
let opos = output.global.pos.get();
|
||||||
macro_rules! render_layer {
|
macro_rules! render_layer {
|
||||||
($layer:expr) => {
|
($layer:expr) => {
|
||||||
for ls in $layer.iter() {
|
for ls in $layer.iter() {
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,7 @@ impl State {
|
||||||
width += 2 * self.theme.border_width.get();
|
width += 2 * self.theme.border_width.get();
|
||||||
height += 2 * self.theme.border_width.get() + self.theme.title_height.get();
|
height += 2 * self.theme.border_width.get() + self.theme.title_height.get();
|
||||||
let output = workspace.output.get();
|
let output = workspace.output.get();
|
||||||
let output_rect = output.position.get();
|
let output_rect = output.global.pos.get();
|
||||||
let position = {
|
let position = {
|
||||||
let mut x1 = output_rect.x1();
|
let mut x1 = output_rect.x1();
|
||||||
let mut y1 = output_rect.y1();
|
let mut y1 = output_rect.y1();
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::backend::{BackendEvent, Output};
|
use crate::backend::{BackendEvent, Connector};
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
use crate::tasks::input_device;
|
use crate::tasks::input_device;
|
||||||
use crate::tasks::output::OutputHandler;
|
use crate::tasks::output::OutputHandler;
|
||||||
|
|
@ -18,12 +18,12 @@ impl BackendEventHandler {
|
||||||
|
|
||||||
fn handle_event(&mut self, event: BackendEvent) {
|
fn handle_event(&mut self, event: BackendEvent) {
|
||||||
match event {
|
match event {
|
||||||
BackendEvent::NewOutput(output) => self.handle_new_output(output),
|
BackendEvent::NewConnector(output) => self.handle_new_output(output),
|
||||||
BackendEvent::NewInputDevice(s) => input_device::handle(&self.state, s),
|
BackendEvent::NewInputDevice(s) => input_device::handle(&self.state, s),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_new_output(&mut self, output: Rc<dyn Output>) {
|
fn handle_new_output(&mut self, output: Rc<dyn Connector>) {
|
||||||
let id = output.id();
|
let id = output.id();
|
||||||
let oh = OutputHandler {
|
let oh = OutputHandler {
|
||||||
state: self.state.clone(),
|
state: self.state.clone(),
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
use crate::backend::Output;
|
use crate::backend::{Connector, ConnectorEvent};
|
||||||
use crate::ifs::wl_output::WlOutputGlobal;
|
use crate::ifs::wl_output::WlOutputGlobal;
|
||||||
use crate::rect::Rect;
|
use crate::rect::Rect;
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
use crate::tree::{OutputNode, OutputRenderData, WorkspaceNode};
|
use crate::tree::{OutputNode, OutputRenderData, WorkspaceNode};
|
||||||
use crate::utils::asyncevent::AsyncEvent;
|
use crate::utils::asyncevent::AsyncEvent;
|
||||||
use crate::utils::clonecell::CloneCell;
|
use crate::utils::clonecell::CloneCell;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{RefCell};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct OutputHandler {
|
pub struct OutputHandler {
|
||||||
pub state: Rc<State>,
|
pub state: Rc<State>,
|
||||||
pub output: Rc<dyn Output>,
|
pub output: Rc<dyn Connector>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OutputHandler {
|
impl OutputHandler {
|
||||||
|
|
@ -21,12 +21,11 @@ impl OutputHandler {
|
||||||
self.output.on_change(Rc::new(move || ae.trigger()));
|
self.output.on_change(Rc::new(move || ae.trigger()));
|
||||||
}
|
}
|
||||||
let name = self.state.globals.name();
|
let name = self.state.globals.name();
|
||||||
let global = Rc::new(WlOutputGlobal::new(name, self.output.clone()));
|
let x1 = self.state.root.outputs.lock().values().map(|o| o.global.pos.get().x2()).max().unwrap_or(0);
|
||||||
let x1 = self.state.root.outputs.lock().values().map(|o| o.position.get().x2()).max().unwrap_or(0);
|
let global = Rc::new(WlOutputGlobal::new(name, self.output.clone(), x1));
|
||||||
let on = Rc::new(OutputNode {
|
let on = Rc::new(OutputNode {
|
||||||
id: self.state.node_ids.next(),
|
id: self.state.node_ids.next(),
|
||||||
workspaces: Default::default(),
|
workspaces: Default::default(),
|
||||||
position: Cell::new(Rect::new_empty(x1, 0)),
|
|
||||||
workspace: CloneCell::new(None),
|
workspace: CloneCell::new(None),
|
||||||
seat_state: Default::default(),
|
seat_state: Default::default(),
|
||||||
global: global.clone(),
|
global: global.clone(),
|
||||||
|
|
@ -68,20 +67,15 @@ impl OutputHandler {
|
||||||
self.state.root.outputs.set(self.output.id(), on.clone());
|
self.state.root.outputs.set(self.output.id(), on.clone());
|
||||||
self.state.add_global(&global);
|
self.state.add_global(&global);
|
||||||
self.state.outputs.set(self.output.id(), global.clone());
|
self.state.outputs.set(self.output.id(), global.clone());
|
||||||
let mut width = 0;
|
'outer: loop {
|
||||||
let mut height = 0;
|
while let Some(event) = self.output.event() {
|
||||||
loop {
|
match event {
|
||||||
if self.output.removed() {
|
ConnectorEvent::Removed => break 'outer,
|
||||||
break;
|
ConnectorEvent::ModeChanged(mode) => {
|
||||||
|
on.update_mode(mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let new_width = self.output.width();
|
|
||||||
let new_height = self.output.height();
|
|
||||||
if new_width != width || new_height != height {
|
|
||||||
width = new_width;
|
|
||||||
height = new_height;
|
|
||||||
on.change_size(new_width, new_height);
|
|
||||||
}
|
|
||||||
global.update_properties();
|
|
||||||
ae.triggered().await;
|
ae.triggered().await;
|
||||||
}
|
}
|
||||||
global.node.set(None);
|
global.node.set(None);
|
||||||
|
|
|
||||||
|
|
@ -434,7 +434,7 @@ impl Node for DisplayNode {
|
||||||
}
|
}
|
||||||
let outputs = self.outputs.lock();
|
let outputs = self.outputs.lock();
|
||||||
for output in outputs.values() {
|
for output in outputs.values() {
|
||||||
let pos = output.position.get();
|
let pos = output.global.pos.get();
|
||||||
if pos.contains(x, y) {
|
if pos.contains(x, y) {
|
||||||
let (x, y) = pos.translate(x, y);
|
let (x, y) = pos.translate(x, y);
|
||||||
tree.push(FoundNode {
|
tree.push(FoundNode {
|
||||||
|
|
|
||||||
|
|
@ -13,15 +13,15 @@ use crate::tree::{FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode};
|
||||||
use crate::utils::clonecell::CloneCell;
|
use crate::utils::clonecell::CloneCell;
|
||||||
use crate::utils::errorfmt::ErrorFmt;
|
use crate::utils::errorfmt::ErrorFmt;
|
||||||
use crate::utils::linkedlist::LinkedList;
|
use crate::utils::linkedlist::LinkedList;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{RefCell};
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::ops::{Deref, Sub};
|
use std::ops::{Deref, Sub};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use crate::backend::Mode;
|
||||||
|
|
||||||
tree_id!(OutputNodeId);
|
tree_id!(OutputNodeId);
|
||||||
pub struct OutputNode {
|
pub struct OutputNode {
|
||||||
pub id: OutputNodeId,
|
pub id: OutputNodeId,
|
||||||
pub position: Cell<Rect>,
|
|
||||||
pub global: Rc<WlOutputGlobal>,
|
pub global: Rc<WlOutputGlobal>,
|
||||||
pub workspaces: LinkedList<Rc<WorkspaceNode>>,
|
pub workspaces: LinkedList<Rc<WorkspaceNode>>,
|
||||||
pub workspace: CloneCell<Option<Rc<WorkspaceNode>>>,
|
pub workspace: CloneCell<Option<Rc<WorkspaceNode>>>,
|
||||||
|
|
@ -84,7 +84,7 @@ impl OutputNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn workspace_rect(&self) -> Rect {
|
fn workspace_rect(&self) -> Rect {
|
||||||
let rect = self.position.get();
|
let rect = self.global.pos.get();
|
||||||
let th = self.state.theme.title_height.get();
|
let th = self.state.theme.title_height.get();
|
||||||
Rect::new_sized(
|
Rect::new_sized(
|
||||||
rect.x1(),
|
rect.x1(),
|
||||||
|
|
@ -95,10 +95,13 @@ impl OutputNode {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn change_size(&self, width: i32, height: i32) {
|
pub fn update_mode(&self, mode: Mode) {
|
||||||
let pos = self.position.get();
|
if self.global.mode.get() == mode {
|
||||||
let rect = Rect::new_sized(pos.x1(), pos.y1(), width, height).unwrap();
|
return;
|
||||||
self.position.set(rect);
|
}
|
||||||
|
let pos = self.global.pos.get();
|
||||||
|
let rect = Rect::new_sized(pos.x1(), pos.y1(), mode.width, mode.height).unwrap();
|
||||||
|
self.global.pos.set(rect);
|
||||||
if let Some(c) = self.workspace.get() {
|
if let Some(c) = self.workspace.get() {
|
||||||
c.change_extents(&self.workspace_rect());
|
c.change_extents(&self.workspace_rect());
|
||||||
}
|
}
|
||||||
|
|
@ -107,6 +110,7 @@ impl OutputNode {
|
||||||
surface.deref().clone().change_extents(&rect);
|
surface.deref().clone().change_extents(&rect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.global.send_mode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -166,7 +170,7 @@ impl Node for OutputNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn absolute_position(&self) -> Rect {
|
fn absolute_position(&self) -> Rect {
|
||||||
self.position.get()
|
self.global.pos.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_tree_at(&self, x: i32, mut y: i32, tree: &mut Vec<FoundNode>) -> FindTreeResult {
|
fn find_tree_at(&self, x: i32, mut y: i32, tree: &mut Vec<FoundNode>) -> FindTreeResult {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::utils::ptr_ext::MutPtrExt;
|
use crate::utils::ptr_ext::{MutPtrExt, PtrExt};
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
|
|
||||||
pub struct Stack<T> {
|
pub struct Stack<T> {
|
||||||
|
|
@ -23,4 +23,13 @@ impl<T> Stack<T> {
|
||||||
pub fn pop(&self) -> Option<T> {
|
pub fn pop(&self) -> Option<T> {
|
||||||
unsafe { self.vec.get().deref_mut().pop() }
|
unsafe { self.vec.get().deref_mut().pop() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_vec(&self) -> Vec<T>
|
||||||
|
where T: Clone,
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
let v = self.vec.get().deref();
|
||||||
|
(*v).clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use std::cell::UnsafeCell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct SyncQueue<T> {
|
pub struct SyncQueue<T> {
|
||||||
el: UnsafeCell<VecDeque<T>>,
|
el: UnsafeCell<VecDeque<T>>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue