autocommit 2022-04-05 18:28:42 CEST
This commit is contained in:
parent
1f05ea431e
commit
a3e9f21fc5
29 changed files with 568 additions and 225 deletions
|
|
@ -37,8 +37,7 @@ clap = { version = "3.1.6", features = ["derive", "wrap_help"] }
|
||||||
clap_complete = "3.1.1"
|
clap_complete = "3.1.1"
|
||||||
humantime = "2.1.0"
|
humantime = "2.1.0"
|
||||||
dirs = "4.0.0"
|
dirs = "4.0.0"
|
||||||
|
backtrace = "0.3.64"
|
||||||
backtrace = { version = "0.3.64", optional = true }
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
repc = "0.1.1"
|
repc = "0.1.1"
|
||||||
|
|
@ -49,4 +48,4 @@ bstr = { version = "0.2.17", default-features = false, features = ["std"] }
|
||||||
#opt-level = 3
|
#opt-level = 3
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
rc_tracking = ["backtrace"]
|
rc_tracking = []
|
||||||
|
|
|
||||||
23
README.md
23
README.md
|
|
@ -9,12 +9,19 @@ Do not expect any kind of structured commit history.
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
While Jay is written almost completely in rust, it has some native dependencies:
|
While Jay is written almost completely in rust, it depends on the following libraries:
|
||||||
|
|
||||||
* **pixman-1.so**: For damage tracking.
|
* **libinput.so**: For processing input events.
|
||||||
* **input.so**: For processing input events.
|
* **libEGL.so**, **libGLESv2.so**: For OpenGL rendering.
|
||||||
* **EGL.so**, **GLESv2.so**: For OpenGL rendering.
|
* **libgbm.so**: For graphics buffer allocation.
|
||||||
* **gbm.so**: For graphics buffer allocation.
|
* **libxkbcommon.so**: For keymap handling.
|
||||||
* **xkbcommon.so**: For keymap handling.
|
* **libudev.so**: For device enumeration and hotplug support.
|
||||||
* **udev.so**: For device enumeration and hotplug support.
|
* **libcairo.so**, **libpangocairo-1.0.so**, **libgobject-2.0.so**, **libpango-1.0.so**: For text rendering.
|
||||||
* **cairo.so**, **pangocairo-1.0.so**, **gobject-2.0.so**, **pango-1.0.so**: For text rendering.
|
|
||||||
|
Furthermore, Jay depends on the following runtime services:
|
||||||
|
|
||||||
|
* **An up-to-date linux kernel**
|
||||||
|
* **XWayland**: For XWayland support.
|
||||||
|
* **Pipewire**: For screen-recording.
|
||||||
|
* **A running X server**: For the X backend. (Only required if you want to run Jay as an X client.)
|
||||||
|
* **Logind**: For the metal backend. (Only required if you want to run Jay from a TTY.)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use crate::_private::ipc::{ClientMessage, InitMessage, Response, ServerMessage};
|
use crate::_private::ipc::{ClientMessage, InitMessage, Response, ServerMessage};
|
||||||
use crate::_private::{bincode_ops, logging, Config, ConfigEntry, ConfigEntryGen, VERSION};
|
use crate::_private::{bincode_ops, logging, Config, ConfigEntry, ConfigEntryGen, VERSION};
|
||||||
|
use crate::drm::Connector;
|
||||||
use crate::input::acceleration::AccelProfile;
|
use crate::input::acceleration::AccelProfile;
|
||||||
use crate::input::capability::Capability;
|
use crate::input::capability::Capability;
|
||||||
use crate::input::InputDevice;
|
use crate::input::InputDevice;
|
||||||
|
|
@ -24,6 +25,8 @@ pub(crate) struct Client {
|
||||||
response: RefCell<Vec<Response>>,
|
response: RefCell<Vec<Response>>,
|
||||||
on_new_seat: RefCell<Option<Rc<dyn Fn(Seat)>>>,
|
on_new_seat: RefCell<Option<Rc<dyn Fn(Seat)>>>,
|
||||||
on_new_input_device: RefCell<Option<Rc<dyn Fn(InputDevice)>>>,
|
on_new_input_device: RefCell<Option<Rc<dyn Fn(InputDevice)>>>,
|
||||||
|
on_connector_connected: RefCell<Option<Rc<dyn Fn(Connector)>>>,
|
||||||
|
on_new_connector: RefCell<Option<Rc<dyn Fn(Connector)>>>,
|
||||||
bufs: RefCell<Vec<Vec<u8>>>,
|
bufs: RefCell<Vec<Vec<u8>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -103,6 +106,8 @@ pub unsafe extern "C" fn init(
|
||||||
response: Default::default(),
|
response: Default::default(),
|
||||||
on_new_seat: Default::default(),
|
on_new_seat: Default::default(),
|
||||||
on_new_input_device: Default::default(),
|
on_new_input_device: Default::default(),
|
||||||
|
on_connector_connected: Default::default(),
|
||||||
|
on_new_connector: Default::default(),
|
||||||
bufs: Default::default(),
|
bufs: Default::default(),
|
||||||
});
|
});
|
||||||
let init = slice::from_raw_parts(init, size);
|
let init = slice::from_raw_parts(init, size);
|
||||||
|
|
@ -471,6 +476,20 @@ impl Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ServerMessage::DelInputDevice { .. } => {}
|
ServerMessage::DelInputDevice { .. } => {}
|
||||||
|
ServerMessage::ConnectorConnect { device } => {
|
||||||
|
let handler = self.on_connector_connected.borrow_mut().clone();
|
||||||
|
if let Some(handler) = handler {
|
||||||
|
handler(device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ServerMessage::ConnectorDisconnect { .. } => {}
|
||||||
|
ServerMessage::NewConnector { device } => {
|
||||||
|
let handler = self.on_new_connector.borrow_mut().clone();
|
||||||
|
if let Some(handler) = handler {
|
||||||
|
handler(device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ServerMessage::DelConnector { .. } => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::drm::Connector;
|
||||||
use crate::input::acceleration::AccelProfile;
|
use crate::input::acceleration::AccelProfile;
|
||||||
use crate::input::capability::Capability;
|
use crate::input::capability::Capability;
|
||||||
use crate::input::InputDevice;
|
use crate::input::InputDevice;
|
||||||
|
|
@ -14,6 +15,18 @@ pub enum ServerMessage {
|
||||||
Response {
|
Response {
|
||||||
response: Response,
|
response: Response,
|
||||||
},
|
},
|
||||||
|
ConnectorConnect {
|
||||||
|
device: Connector,
|
||||||
|
},
|
||||||
|
ConnectorDisconnect {
|
||||||
|
device: Connector,
|
||||||
|
},
|
||||||
|
NewConnector {
|
||||||
|
device: Connector,
|
||||||
|
},
|
||||||
|
DelConnector {
|
||||||
|
device: Connector,
|
||||||
|
},
|
||||||
NewInputDevice {
|
NewInputDevice {
|
||||||
device: InputDevice,
|
device: InputDevice,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
4
jay-config/src/drm.rs
Normal file
4
jay-config/src/drm.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
use bincode::{Decode, Encode};
|
||||||
|
|
||||||
|
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||||
|
pub struct Connector(pub u64);
|
||||||
|
|
@ -8,6 +8,7 @@ use std::collections::HashMap;
|
||||||
mod macros;
|
mod macros;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod _private;
|
pub mod _private;
|
||||||
|
pub mod drm;
|
||||||
pub mod embedded;
|
pub mod embedded;
|
||||||
pub mod input;
|
pub mod input;
|
||||||
pub mod keyboard;
|
pub mod keyboard;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
|
use crate::drm::drm::ConnectorType;
|
||||||
use crate::fixed::Fixed;
|
use crate::fixed::Fixed;
|
||||||
use std::fmt::Debug;
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
linear_ids!(OutputIds, OutputId);
|
linear_ids!(ConnectorIds, ConnectorId);
|
||||||
linear_ids!(InputDeviceIds, InputDeviceId);
|
linear_ids!(InputDeviceIds, InputDeviceId);
|
||||||
|
|
||||||
pub trait Backend {
|
pub trait Backend {
|
||||||
|
|
@ -13,17 +14,42 @@ pub trait Backend {
|
||||||
pub struct Mode {
|
pub struct Mode {
|
||||||
pub width: i32,
|
pub width: i32,
|
||||||
pub height: i32,
|
pub height: i32,
|
||||||
pub refresh_rate: u32,
|
pub refresh_rate_millihz: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct MonitorInfo {
|
||||||
|
pub modes: Vec<Mode>,
|
||||||
|
pub manufacturer: String,
|
||||||
|
pub product: String,
|
||||||
|
pub serial_number: String,
|
||||||
|
pub initial_mode: Mode,
|
||||||
|
pub width_mm: i32,
|
||||||
|
pub height_mm: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ConnectorKernelId {
|
||||||
|
pub ty: ConnectorType,
|
||||||
|
pub id: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ConnectorKernelId {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}-{}", self.ty, self.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Connector {
|
pub trait Connector {
|
||||||
fn id(&self) -> OutputId;
|
fn id(&self) -> ConnectorId;
|
||||||
|
fn kernel_id(&self) -> ConnectorKernelId;
|
||||||
fn event(&self) -> Option<ConnectorEvent>;
|
fn event(&self) -> Option<ConnectorEvent>;
|
||||||
fn on_change(&self, cb: Rc<dyn Fn()>);
|
fn on_change(&self, cb: Rc<dyn Fn()>);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ConnectorEvent {
|
pub enum ConnectorEvent {
|
||||||
|
Connected(MonitorInfo),
|
||||||
|
Disconnected,
|
||||||
Removed,
|
Removed,
|
||||||
ModeChanged(Mode),
|
ModeChanged(Mode),
|
||||||
}
|
}
|
||||||
|
|
@ -79,7 +105,7 @@ pub enum ScrollAxis {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum InputEvent {
|
pub enum InputEvent {
|
||||||
Key(u32, KeyState),
|
Key(u32, KeyState),
|
||||||
OutputPosition(OutputId, Fixed, Fixed),
|
ConnectorPosition(ConnectorId, Fixed, Fixed),
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
Motion(Fixed, Fixed),
|
Motion(Fixed, Fixed),
|
||||||
Button(u32, KeyState),
|
Button(u32, KeyState),
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::backend::{Backend, Connector, ConnectorEvent, OutputId};
|
use crate::backend::{Backend, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId};
|
||||||
|
use crate::drm::drm::ConnectorType;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct DummyBackend {}
|
pub struct DummyBackend {}
|
||||||
|
|
@ -10,14 +11,21 @@ impl Backend for DummyBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DummyOutput {
|
pub struct DummyOutput {
|
||||||
pub id: OutputId,
|
pub id: ConnectorId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Connector for DummyOutput {
|
impl Connector for DummyOutput {
|
||||||
fn id(&self) -> OutputId {
|
fn id(&self) -> ConnectorId {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn kernel_id(&self) -> ConnectorKernelId {
|
||||||
|
ConnectorKernelId {
|
||||||
|
ty: ConnectorType::Unknown(0),
|
||||||
|
id: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn event(&self) -> Option<ConnectorEvent> {
|
fn event(&self) -> Option<ConnectorEvent> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::async_engine::{AsyncFd, SpawnedFuture};
|
use crate::async_engine::{AsyncFd, SpawnedFuture};
|
||||||
use crate::backend::{BackendEvent, Connector, ConnectorEvent, Mode, OutputId};
|
use crate::backend::{BackendEvent, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId, MonitorInfo};
|
||||||
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,
|
||||||
|
|
@ -25,6 +25,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::edid::Descriptor;
|
||||||
|
|
||||||
pub struct PendingDrmDevice {
|
pub struct PendingDrmDevice {
|
||||||
pub id: DrmId,
|
pub id: DrmId,
|
||||||
|
|
@ -72,12 +73,16 @@ pub struct MetalConnector {
|
||||||
pub id: DrmConnector,
|
pub id: DrmConnector,
|
||||||
pub master: Rc<DrmMaster>,
|
pub master: Rc<DrmMaster>,
|
||||||
|
|
||||||
pub output_id: OutputId,
|
pub connector_id: ConnectorId,
|
||||||
|
|
||||||
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 monitor_manufacturer: String,
|
||||||
|
pub monitor_name: String,
|
||||||
|
pub monitor_serial_number: String,
|
||||||
|
|
||||||
pub events: SyncQueue<ConnectorEvent>,
|
pub events: SyncQueue<ConnectorEvent>,
|
||||||
|
|
||||||
pub buffers: CloneCell<Option<Rc<[RenderBuffer; 2]>>>,
|
pub buffers: CloneCell<Option<Rc<[RenderBuffer; 2]>>>,
|
||||||
|
|
@ -114,8 +119,15 @@ impl Debug for OnChange {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Connector for MetalConnector {
|
impl Connector for MetalConnector {
|
||||||
fn id(&self) -> OutputId {
|
fn id(&self) -> ConnectorId {
|
||||||
self.output_id
|
self.connector_id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn kernel_id(&self) -> ConnectorKernelId {
|
||||||
|
ConnectorKernelId {
|
||||||
|
ty: self.connector_type,
|
||||||
|
id: self.connector_type_id,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn event(&self) -> Option<ConnectorEvent> {
|
fn event(&self) -> Option<ConnectorEvent> {
|
||||||
|
|
@ -212,28 +224,73 @@ 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 connection = ConnectorStatus::from(info.connection);
|
||||||
let events = SyncQueue::default();
|
let connector_type = ConnectorType::from(info.connector_type);
|
||||||
if let Some(mode) = &mode {
|
let mut name = String::new();
|
||||||
events.push(ConnectorEvent::ModeChanged(Mode {
|
let mut manufacturer = String::new();
|
||||||
width: mode.hdisplay as _,
|
let mut serial_number = String::new();
|
||||||
height: mode.vdisplay as _,
|
'fetch_edid: {
|
||||||
refresh_rate: mode.refresh_rate(),
|
if connection != ConnectorStatus::Connected {
|
||||||
}));
|
break 'fetch_edid;
|
||||||
|
}
|
||||||
|
let edid = match props.get("EDID") {
|
||||||
|
Ok(e) => e,
|
||||||
|
_ => {
|
||||||
|
log::warn!("Connector {}-{} is connected but has no EDID blob", connector_type, info.connector_type_id);
|
||||||
|
break 'fetch_edid;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let blob = match dev.master.getblob_vec::<u8>(DrmBlob(edid.value.get() as _)) {
|
||||||
|
Ok(b) => b,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Could not fetch edid property of connector {}-{}: {}", connector_type, info.connector_type_id, ErrorFmt(e));
|
||||||
|
break 'fetch_edid;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let edid = match crate::edid::parse(&blob) {
|
||||||
|
Ok(e) => e,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Could not parse edid property of connector {}-{}: {}", connector_type, info.connector_type_id, ErrorFmt(e));
|
||||||
|
break 'fetch_edid;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
manufacturer = edid.base_block.id_manufacturer_name.to_string();
|
||||||
|
for descriptor in &edid.base_block.descriptors {
|
||||||
|
if let Some(d) = descriptor {
|
||||||
|
match d {
|
||||||
|
Descriptor::DisplayProductSerialNumber(s) => {
|
||||||
|
serial_number = s.to_string();
|
||||||
|
}
|
||||||
|
Descriptor::DisplayProductName(s) => {
|
||||||
|
name = s.to_string();
|
||||||
|
}
|
||||||
|
_ => { },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if name.is_empty() {
|
||||||
|
log::warn!("The display attached to connector {}-{} does not have a product name descriptor", connector_type, info.connector_type_id);
|
||||||
|
}
|
||||||
|
if serial_number.is_empty() {
|
||||||
|
serial_number = edid.base_block.id_serial_number.to_string();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(MetalConnector {
|
Ok(MetalConnector {
|
||||||
id: connector,
|
id: connector,
|
||||||
master: dev.master.clone(),
|
master: dev.master.clone(),
|
||||||
output_id: state.output_ids.next(),
|
connector_id: state.connector_ids.next(),
|
||||||
crtcs,
|
crtcs,
|
||||||
mode: CloneCell::new(mode),
|
mode: CloneCell::new(info.modes.first().cloned().map(Rc::new)),
|
||||||
events,
|
monitor_manufacturer: manufacturer,
|
||||||
|
monitor_name: name,
|
||||||
|
monitor_serial_number: serial_number,
|
||||||
|
events: Default::default(),
|
||||||
modes: info.modes,
|
modes: info.modes,
|
||||||
buffers: Default::default(),
|
buffers: Default::default(),
|
||||||
next_buffer: Default::default(),
|
next_buffer: Default::default(),
|
||||||
connector_type: info.connector_type.into(),
|
connector_type,
|
||||||
connector_type_id: info.connector_type_id,
|
connector_type_id: info.connector_type_id,
|
||||||
connection: info.connection.into(),
|
connection,
|
||||||
mm_width: info.mm_width,
|
mm_width: info.mm_width,
|
||||||
mm_height: info.mm_height,
|
mm_height: info.mm_height,
|
||||||
subpixel: info.subpixel,
|
subpixel: info.subpixel,
|
||||||
|
|
@ -488,7 +545,27 @@ impl MetalBackend {
|
||||||
self.state
|
self.state
|
||||||
.backend_events
|
.backend_events
|
||||||
.push(BackendEvent::NewConnector(connector.clone()));
|
.push(BackendEvent::NewConnector(connector.clone()));
|
||||||
if connector.primary_plane.get().is_some() {
|
if connector.connection == ConnectorStatus::Connected {
|
||||||
|
if connector.primary_plane.get().is_none() {
|
||||||
|
log::error!("Connector {}-{} is connected but does not have a primary plane", connector.connector_type, connector.connector_type_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut prev_mode = None;
|
||||||
|
let mut modes = vec!();
|
||||||
|
for mode in connector.modes.iter().map(|m| m.to_backend()) {
|
||||||
|
if prev_mode.replace(mode) != Some(mode) {
|
||||||
|
modes.push(mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
connector.events.push(ConnectorEvent::Connected(MonitorInfo {
|
||||||
|
modes,
|
||||||
|
manufacturer: connector.monitor_manufacturer.clone(),
|
||||||
|
product: connector.monitor_name.clone(),
|
||||||
|
serial_number: connector.monitor_serial_number.clone(),
|
||||||
|
initial_mode: connector.mode.get().unwrap().to_backend(),
|
||||||
|
width_mm: connector.mm_width as _,
|
||||||
|
height_mm: connector.mm_height as _,
|
||||||
|
}));
|
||||||
self.start_connector(connector);
|
self.start_connector(connector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -901,7 +978,7 @@ impl MetalBackend {
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
let buffer = &buffers[connector.next_buffer.fetch_add(1) % buffers.len()];
|
let buffer = &buffers[connector.next_buffer.fetch_add(1) % buffers.len()];
|
||||||
if let Some(node) = self.state.root.outputs.get(&connector.output_id) {
|
if let Some(node) = self.state.root.outputs.get(&connector.connector_id) {
|
||||||
buffer
|
buffer
|
||||||
.egl
|
.egl
|
||||||
.render(&*node, &self.state, Some(node.global.pos.get()));
|
.render(&*node, &self.state, Some(node.global.pos.get()));
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
use crate::async_engine::{Phase, SpawnedFuture};
|
use crate::async_engine::{Phase, SpawnedFuture};
|
||||||
use crate::backend::{
|
use crate::backend::{Backend, BackendEvent, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId, InputDevice, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId, InputEvent, KeyState, Mode, MonitorInfo, ScrollAxis};
|
||||||
Backend, BackendEvent, Connector, ConnectorEvent, InputDevice, InputDeviceAccelProfile,
|
use crate::drm::drm::{ConnectorType, Drm, DrmError};
|
||||||
InputDeviceCapability, InputDeviceId, InputEvent, KeyState, Mode, OutputId, ScrollAxis,
|
|
||||||
};
|
|
||||||
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};
|
||||||
use crate::fixed::Fixed;
|
use crate::fixed::Fixed;
|
||||||
|
|
@ -394,7 +391,7 @@ impl XBackendData {
|
||||||
};
|
};
|
||||||
let images = self.create_images(window_id, WIDTH, HEIGHT).await?;
|
let images = self.create_images(window_id, WIDTH, HEIGHT).await?;
|
||||||
let output = Rc::new(XOutput {
|
let output = Rc::new(XOutput {
|
||||||
id: self.state.output_ids.next(),
|
id: self.state.connector_ids.next(),
|
||||||
_backend: self.clone(),
|
_backend: self.clone(),
|
||||||
window: window_id,
|
window: window_id,
|
||||||
events: Default::default(),
|
events: Default::default(),
|
||||||
|
|
@ -481,6 +478,20 @@ impl XBackendData {
|
||||||
self.state
|
self.state
|
||||||
.backend_events
|
.backend_events
|
||||||
.push(BackendEvent::NewConnector(output.clone()));
|
.push(BackendEvent::NewConnector(output.clone()));
|
||||||
|
output.events.push(ConnectorEvent::Connected(MonitorInfo {
|
||||||
|
modes: vec![],
|
||||||
|
manufacturer: "X.Org Foundation".to_string(),
|
||||||
|
product: format!("X-Window-{}", window_id),
|
||||||
|
serial_number: window_id.to_string(),
|
||||||
|
initial_mode: Mode {
|
||||||
|
width: WIDTH,
|
||||||
|
height: HEIGHT,
|
||||||
|
refresh_rate_millihz: 60_000, // TODO
|
||||||
|
},
|
||||||
|
width_mm: WIDTH,
|
||||||
|
height_mm: HEIGHT,
|
||||||
|
}));
|
||||||
|
output.changed();
|
||||||
self.present(&output).await;
|
self.present(&output).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -759,7 +770,7 @@ impl XBackendData {
|
||||||
self.outputs.get(&event.event),
|
self.outputs.get(&event.event),
|
||||||
self.mouse_seats.get(&event.deviceid),
|
self.mouse_seats.get(&event.deviceid),
|
||||||
) {
|
) {
|
||||||
seat.mouse_event(InputEvent::OutputPosition(
|
seat.mouse_event(InputEvent::ConnectorPosition(
|
||||||
win.id,
|
win.id,
|
||||||
Fixed::from_1616(event.event_x),
|
Fixed::from_1616(event.event_x),
|
||||||
Fixed::from_1616(event.event_y),
|
Fixed::from_1616(event.event_y),
|
||||||
|
|
@ -777,7 +788,7 @@ impl XBackendData {
|
||||||
(Some(a), Some(b)) => (a, b),
|
(Some(a), Some(b)) => (a, b),
|
||||||
_ => return Ok(()),
|
_ => return Ok(()),
|
||||||
};
|
};
|
||||||
seat.mouse_event(InputEvent::OutputPosition(
|
seat.mouse_event(InputEvent::ConnectorPosition(
|
||||||
win.id,
|
win.id,
|
||||||
Fixed::from_1616(event.event_x),
|
Fixed::from_1616(event.event_x),
|
||||||
Fixed::from_1616(event.event_y),
|
Fixed::from_1616(event.event_y),
|
||||||
|
|
@ -792,6 +803,7 @@ impl XBackendData {
|
||||||
Some(o) => o,
|
Some(o) => o,
|
||||||
_ => return Ok(()),
|
_ => return Ok(()),
|
||||||
};
|
};
|
||||||
|
output.events.push(ConnectorEvent::Disconnected);
|
||||||
output.events.push(ConnectorEvent::Removed);
|
output.events.push(ConnectorEvent::Removed);
|
||||||
output.changed();
|
output.changed();
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -820,7 +832,7 @@ impl XBackendData {
|
||||||
output.events.push(ConnectorEvent::ModeChanged(Mode {
|
output.events.push(ConnectorEvent::ModeChanged(Mode {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
refresh_rate: 60, // TODO
|
refresh_rate_millihz: 60, // TODO
|
||||||
}));
|
}));
|
||||||
output.changed();
|
output.changed();
|
||||||
}
|
}
|
||||||
|
|
@ -829,7 +841,7 @@ impl XBackendData {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct XOutput {
|
struct XOutput {
|
||||||
id: OutputId,
|
id: ConnectorId,
|
||||||
_backend: Rc<XBackendData>,
|
_backend: Rc<XBackendData>,
|
||||||
window: u32,
|
window: u32,
|
||||||
events: SyncQueue<ConnectorEvent>,
|
events: SyncQueue<ConnectorEvent>,
|
||||||
|
|
@ -859,10 +871,17 @@ impl XOutput {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Connector for XOutput {
|
impl Connector for XOutput {
|
||||||
fn id(&self) -> OutputId {
|
fn id(&self) -> ConnectorId {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn kernel_id(&self) -> ConnectorKernelId {
|
||||||
|
ConnectorKernelId {
|
||||||
|
ty: ConnectorType::EmbeddedWindow,
|
||||||
|
id: self.id.raw(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn event(&self) -> Option<ConnectorEvent> {
|
fn event(&self) -> Option<ConnectorEvent> {
|
||||||
self.events.pop()
|
self.events.pop()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,13 @@ use crate::clientmem::ClientMemError;
|
||||||
use crate::config::ConfigProxy;
|
use crate::config::ConfigProxy;
|
||||||
use crate::dbus::Dbus;
|
use crate::dbus::Dbus;
|
||||||
use crate::event_loop::{EventLoop, EventLoopError};
|
use crate::event_loop::{EventLoop, EventLoopError};
|
||||||
use crate::forker::ForkerError;
|
|
||||||
use crate::globals::Globals;
|
use crate::globals::Globals;
|
||||||
use crate::ifs::wl_output::WlOutputGlobal;
|
use crate::ifs::wl_output::WlOutputGlobal;
|
||||||
use crate::ifs::wl_surface::NoneSurfaceExt;
|
use crate::ifs::wl_surface::NoneSurfaceExt;
|
||||||
use crate::logger::Logger;
|
use crate::logger::Logger;
|
||||||
use crate::render::RenderError;
|
use crate::render::RenderError;
|
||||||
use crate::sighand::SighandError;
|
use crate::sighand::SighandError;
|
||||||
use crate::state::State;
|
use crate::state::{ConnectorData, State};
|
||||||
use crate::tree::{
|
use crate::tree::{
|
||||||
container_layout, container_render_data, float_layout, float_titles, DisplayNode, NodeIds,
|
container_layout, container_render_data, float_layout, float_titles, DisplayNode, NodeIds,
|
||||||
OutputNode, WorkspaceNode,
|
OutputNode, WorkspaceNode,
|
||||||
|
|
@ -22,12 +21,11 @@ use crate::tree::{
|
||||||
use crate::utils::clonecell::CloneCell;
|
use crate::utils::clonecell::CloneCell;
|
||||||
use crate::utils::errorfmt::ErrorFmt;
|
use crate::utils::errorfmt::ErrorFmt;
|
||||||
use crate::utils::fdcloser::FdCloser;
|
use crate::utils::fdcloser::FdCloser;
|
||||||
use crate::utils::numcell::NumCell;
|
|
||||||
use crate::utils::queue::AsyncQueue;
|
use crate::utils::queue::AsyncQueue;
|
||||||
use crate::utils::run_toplevel::RunToplevel;
|
use crate::utils::run_toplevel::RunToplevel;
|
||||||
use crate::wheel::{Wheel, WheelError};
|
use crate::wheel::{Wheel, WheelError};
|
||||||
use crate::xkbcommon::XkbContext;
|
use crate::xkbcommon::XkbContext;
|
||||||
use crate::{clientmem, forker, leaks, render, sighand, tasks, xwayland};
|
use crate::{backend, clientmem, forker, leaks, render, sighand, tasks, xwayland};
|
||||||
use forker::ForkerProxy;
|
use forker::ForkerProxy;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
@ -36,8 +34,12 @@ use std::sync::Arc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
pub fn start_compositor(global: GlobalArgs, args: RunArgs) {
|
pub fn start_compositor(global: GlobalArgs, args: RunArgs) {
|
||||||
|
let forker = match ForkerProxy::create() {
|
||||||
|
Ok(f) => Rc::new(f),
|
||||||
|
Err(e) => fatal!("Could not create a forker process: {}", ErrorFmt(e)),
|
||||||
|
};
|
||||||
let logger = Logger::install_compositor(global.log_level.into());
|
let logger = Logger::install_compositor(global.log_level.into());
|
||||||
if let Err(e) = main_(logger.clone(), &args) {
|
if let Err(e) = main_(forker, logger.clone(), &args) {
|
||||||
let e = ErrorFmt(e);
|
let e = ErrorFmt(e);
|
||||||
log::error!("A fatal error occurred: {}", e);
|
log::error!("A fatal error occurred: {}", e);
|
||||||
eprintln!("A fatal error occurred: {}", e);
|
eprintln!("A fatal error occurred: {}", e);
|
||||||
|
|
@ -62,12 +64,9 @@ enum MainError {
|
||||||
AsyncError(#[from] AsyncError),
|
AsyncError(#[from] AsyncError),
|
||||||
#[error("The render backend caused an error")]
|
#[error("The render backend caused an error")]
|
||||||
RenderError(#[from] RenderError),
|
RenderError(#[from] RenderError),
|
||||||
#[error("The ol' forker caused an error")]
|
|
||||||
ForkerError(#[from] ForkerError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main_(logger: Arc<Logger>, _args: &RunArgs) -> Result<(), MainError> {
|
fn main_(forker: Rc<ForkerProxy>, logger: Arc<Logger>, _args: &RunArgs) -> Result<(), MainError> {
|
||||||
let forker = Rc::new(ForkerProxy::create()?);
|
|
||||||
leaks::init();
|
leaks::init();
|
||||||
render::init()?;
|
render::init()?;
|
||||||
clientmem::init()?;
|
clientmem::init()?;
|
||||||
|
|
@ -90,17 +89,14 @@ fn main_(logger: Arc<Logger>, _args: &RunArgs) -> Result<(), MainError> {
|
||||||
cursors: Default::default(),
|
cursors: Default::default(),
|
||||||
wheel,
|
wheel,
|
||||||
clients: Clients::new(),
|
clients: Clients::new(),
|
||||||
next_name: NumCell::new(1),
|
|
||||||
globals: Globals::new(),
|
globals: Globals::new(),
|
||||||
output_ids: Default::default(),
|
connector_ids: Default::default(),
|
||||||
root: Rc::new(DisplayNode::new(node_ids.next())),
|
root: Rc::new(DisplayNode::new(node_ids.next())),
|
||||||
workspaces: Default::default(),
|
workspaces: Default::default(),
|
||||||
dummy_output: Default::default(),
|
dummy_output: Default::default(),
|
||||||
node_ids,
|
node_ids,
|
||||||
backend_events: AsyncQueue::new(),
|
backend_events: AsyncQueue::new(),
|
||||||
output_handlers: Default::default(),
|
|
||||||
seat_ids: Default::default(),
|
seat_ids: Default::default(),
|
||||||
outputs: Default::default(),
|
|
||||||
seat_queue: Default::default(),
|
seat_queue: Default::default(),
|
||||||
slow_clients: AsyncQueue::new(),
|
slow_clients: AsyncQueue::new(),
|
||||||
none_surface_ext: Rc::new(NoneSurfaceExt),
|
none_surface_ext: Rc::new(NoneSurfaceExt),
|
||||||
|
|
@ -116,16 +112,29 @@ fn main_(logger: Arc<Logger>, _args: &RunArgs) -> Result<(), MainError> {
|
||||||
dbus: Dbus::new(&engine, &run_toplevel),
|
dbus: Dbus::new(&engine, &run_toplevel),
|
||||||
fdcloser: FdCloser::new(),
|
fdcloser: FdCloser::new(),
|
||||||
logger,
|
logger,
|
||||||
|
connectors: Default::default(),
|
||||||
});
|
});
|
||||||
{
|
{
|
||||||
let dummy_output = Rc::new(OutputNode {
|
let dummy_output = Rc::new(OutputNode {
|
||||||
id: state.node_ids.next(),
|
id: state.node_ids.next(),
|
||||||
global: Rc::new(WlOutputGlobal::new(
|
global: Rc::new(WlOutputGlobal::new(
|
||||||
state.globals.name(),
|
state.globals.name(),
|
||||||
Rc::new(DummyOutput {
|
&Rc::new(ConnectorData {
|
||||||
id: state.output_ids.next(),
|
connector: Rc::new(DummyOutput { id: state.connector_ids.next() }),
|
||||||
|
monitor_info: Default::default(),
|
||||||
|
handler: Cell::new(None),
|
||||||
|
node: Default::default()
|
||||||
}),
|
}),
|
||||||
0,
|
0,
|
||||||
|
&backend::Mode {
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
refresh_rate_millihz: 0,
|
||||||
|
},
|
||||||
|
"none",
|
||||||
|
"none",
|
||||||
|
0,
|
||||||
|
0,
|
||||||
)),
|
)),
|
||||||
workspaces: Default::default(),
|
workspaces: Default::default(),
|
||||||
workspace: Default::default(),
|
workspace: Default::default(),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
mod handler;
|
mod handler;
|
||||||
|
|
||||||
use crate::backend::InputDeviceId;
|
use crate::backend::{ConnectorId, InputDeviceId};
|
||||||
use crate::config::handler::ConfigProxyHandler;
|
use crate::config::handler::ConfigProxyHandler;
|
||||||
use crate::ifs::wl_seat::SeatId;
|
use crate::ifs::wl_seat::SeatId;
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
|
|
@ -8,6 +8,7 @@ use crate::utils::numcell::NumCell;
|
||||||
use crate::utils::ptr_ext::PtrExt;
|
use crate::utils::ptr_ext::PtrExt;
|
||||||
use jay_config::_private::ipc::{InitMessage, ServerMessage, V1InitMessage};
|
use jay_config::_private::ipc::{InitMessage, ServerMessage, V1InitMessage};
|
||||||
use jay_config::_private::{bincode_ops, ConfigEntry, VERSION};
|
use jay_config::_private::{bincode_ops, ConfigEntry, VERSION};
|
||||||
|
use jay_config::drm::Connector;
|
||||||
use jay_config::input::InputDevice;
|
use jay_config::input::InputDevice;
|
||||||
use jay_config::keyboard::ModifiedKeySym;
|
use jay_config::keyboard::ModifiedKeySym;
|
||||||
use jay_config::Seat;
|
use jay_config::Seat;
|
||||||
|
|
@ -38,6 +39,30 @@ impl ConfigProxy {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_connector(&self, connector: ConnectorId) {
|
||||||
|
self.handler.send(&ServerMessage::NewConnector {
|
||||||
|
device: Connector(connector.raw() as _),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn del_connector(&self, connector: ConnectorId) {
|
||||||
|
self.handler.send(&ServerMessage::DelConnector {
|
||||||
|
device: Connector(connector.raw() as _),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn connector_connected(&self, connector: ConnectorId) {
|
||||||
|
self.handler.send(&ServerMessage::ConnectorConnect {
|
||||||
|
device: Connector(connector.raw() as _),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn connector_disconnected(&self, connector: ConnectorId) {
|
||||||
|
self.handler.send(&ServerMessage::ConnectorDisconnect {
|
||||||
|
device: Connector(connector.raw() as _),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new_input_device(&self, dev: InputDeviceId) {
|
pub fn new_input_device(&self, dev: InputDeviceId) {
|
||||||
self.handler.send(&ServerMessage::NewInputDevice {
|
self.handler.send(&ServerMessage::NewInputDevice {
|
||||||
device: InputDevice(dev.raw() as _),
|
device: InputDevice(dev.raw() as _),
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,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::backend;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum DrmError {
|
pub enum DrmError {
|
||||||
|
|
@ -597,13 +598,21 @@ impl DrmModeInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn refresh_rate(&self) -> u32 {
|
pub fn to_backend(&self) -> backend::Mode {
|
||||||
let clock_mhz = self.clock as u64 * 1_000_000;
|
backend::Mode {
|
||||||
|
width: self.hdisplay as _,
|
||||||
|
height: self.vdisplay as _,
|
||||||
|
refresh_rate_millihz: self.refresh_rate_millihz(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn refresh_rate_millihz(&self) -> u32 {
|
||||||
|
let clock_millihz = self.clock as u64 * 1_000_000;
|
||||||
let htotal = self.htotal as u64;
|
let htotal = self.htotal as u64;
|
||||||
let vtotal = self.vtotal as u64;
|
let vtotal = self.vtotal as u64;
|
||||||
(((clock_mhz / htotal) + (vtotal / 2)) / vtotal) as u32
|
(((clock_millihz / htotal) + (vtotal / 2)) / vtotal) as u32
|
||||||
// simplifies to
|
// simplifies to
|
||||||
// clock_mhz / (htotal * vtotal) + 1/2
|
// clock_millihz / (htotal * vtotal) + 1/2
|
||||||
// why round up (+1/2) instead of down?
|
// why round up (+1/2) instead of down?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -725,6 +734,7 @@ pub enum ConnectorType {
|
||||||
WRITEBACK,
|
WRITEBACK,
|
||||||
SPI,
|
SPI,
|
||||||
USB,
|
USB,
|
||||||
|
EmbeddedWindow,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for ConnectorType {
|
impl Display for ConnectorType {
|
||||||
|
|
@ -751,6 +761,7 @@ impl Display for ConnectorType {
|
||||||
Self::WRITEBACK => "Writeback",
|
Self::WRITEBACK => "Writeback",
|
||||||
Self::SPI => "SPI",
|
Self::SPI => "SPI",
|
||||||
Self::USB => "USB",
|
Self::USB => "USB",
|
||||||
|
Self::EmbeddedWindow => "EmbeddedWindow",
|
||||||
};
|
};
|
||||||
f.write_str(s)
|
f.write_str(s)
|
||||||
}
|
}
|
||||||
|
|
@ -808,6 +819,7 @@ impl Into<u32> for ConnectorType {
|
||||||
Self::WRITEBACK => sys::DRM_MODE_CONNECTOR_WRITEBACK,
|
Self::WRITEBACK => sys::DRM_MODE_CONNECTOR_WRITEBACK,
|
||||||
Self::SPI => sys::DRM_MODE_CONNECTOR_SPI,
|
Self::SPI => sys::DRM_MODE_CONNECTOR_SPI,
|
||||||
Self::USB => sys::DRM_MODE_CONNECTOR_USB,
|
Self::USB => sys::DRM_MODE_CONNECTOR_USB,
|
||||||
|
Self::EmbeddedWindow => sys::DRM_MODE_CONNECTOR_Unknown,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
use crate::backend;
|
use crate::backend;
|
||||||
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;
|
||||||
use crate::leaks::Tracker;
|
use crate::leaks::Tracker;
|
||||||
use crate::object::Object;
|
use crate::object::Object;
|
||||||
use crate::rect::Rect;
|
use crate::rect::Rect;
|
||||||
|
use crate::state::ConnectorData;
|
||||||
use crate::tree::OutputNode;
|
use crate::tree::OutputNode;
|
||||||
use crate::utils::buffd::MsgParser;
|
use crate::utils::buffd::MsgParser;
|
||||||
use crate::utils::buffd::MsgParserError;
|
use crate::utils::buffd::MsgParserError;
|
||||||
|
|
@ -53,21 +53,38 @@ const MODE_PREFERRED: u32 = 2;
|
||||||
|
|
||||||
pub struct WlOutputGlobal {
|
pub struct WlOutputGlobal {
|
||||||
name: GlobalName,
|
name: GlobalName,
|
||||||
pub connector: Rc<dyn Connector>,
|
pub connector: Rc<ConnectorData>,
|
||||||
pub pos: Cell<Rect>,
|
pub pos: Cell<Rect>,
|
||||||
|
pub manufacturer: String,
|
||||||
|
pub display: String,
|
||||||
pub mode: Cell<backend::Mode>,
|
pub mode: Cell<backend::Mode>,
|
||||||
pub node: CloneCell<Option<Rc<OutputNode>>>,
|
pub node: CloneCell<Option<Rc<OutputNode>>>,
|
||||||
|
pub width_mm: i32,
|
||||||
|
pub height_mm: i32,
|
||||||
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, connector: Rc<dyn Connector>, x1: i32) -> Self {
|
pub fn new(
|
||||||
|
name: GlobalName,
|
||||||
|
connector: &Rc<ConnectorData>,
|
||||||
|
x1: i32,
|
||||||
|
mode: &backend::Mode,
|
||||||
|
manufacturer: &str,
|
||||||
|
product: &str,
|
||||||
|
width_mm: i32,
|
||||||
|
height_mm: i32,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
connector: connector.clone(),
|
connector: connector.clone(),
|
||||||
pos: Cell::new(Rect::new_empty(x1, 0)),
|
pos: Cell::new(Rect::new_sized(x1, 0, mode.width, mode.height).unwrap()),
|
||||||
mode: Default::default(),
|
manufacturer: manufacturer.to_string(),
|
||||||
|
display: product.to_string(),
|
||||||
|
mode: Cell::new(*mode),
|
||||||
node: Default::default(),
|
node: Default::default(),
|
||||||
|
width_mm,
|
||||||
|
height_mm,
|
||||||
bindings: Default::default(),
|
bindings: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -163,24 +180,25 @@ impl WlOutput {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
x: pos.x1(),
|
x: pos.x1(),
|
||||||
y: pos.y1(),
|
y: pos.y1(),
|
||||||
physical_width: pos.width(),
|
physical_width: self.global.width_mm,
|
||||||
physical_height: pos.height(),
|
physical_height: self.global.height_mm,
|
||||||
subpixel: SP_UNKNOWN,
|
subpixel: SP_UNKNOWN,
|
||||||
make: "jay",
|
make: &self.global.manufacturer,
|
||||||
model: "jay",
|
model: &self.global.display,
|
||||||
transform: TF_NORMAL,
|
transform: TF_NORMAL,
|
||||||
};
|
};
|
||||||
self.client.event(event);
|
self.client.event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_mode(&self) {
|
fn send_mode(&self) {
|
||||||
|
let mode = self.global.mode.get();
|
||||||
let pos = self.global.pos.get();
|
let pos = self.global.pos.get();
|
||||||
let event = Mode {
|
let event = Mode {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
flags: MODE_CURRENT,
|
flags: MODE_CURRENT,
|
||||||
width: pos.width(),
|
width: mode.width,
|
||||||
height: pos.height(),
|
height: mode.height,
|
||||||
refresh: 60_000_000,
|
refresh: mode.refresh_rate_millihz as _,
|
||||||
};
|
};
|
||||||
self.client.event(event);
|
self.client.event(event);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::client::{Client, ClientError};
|
use crate::client::{Client, ClientError};
|
||||||
use crate::leaks::Tracker;
|
use crate::leaks::Tracker;
|
||||||
use crate::object::Object;
|
use crate::object::Object;
|
||||||
|
use crate::rect::{Rect, Region, RegionBuilder};
|
||||||
use crate::utils::buffd::MsgParser;
|
use crate::utils::buffd::MsgParser;
|
||||||
use crate::utils::buffd::MsgParserError;
|
use crate::utils::buffd::MsgParserError;
|
||||||
use crate::wire::wl_region::*;
|
use crate::wire::wl_region::*;
|
||||||
|
|
@ -8,7 +9,6 @@ use crate::wire::WlRegionId;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use crate::rect::{Rect, Region, RegionBuilder};
|
|
||||||
|
|
||||||
pub struct WlRegion {
|
pub struct WlRegion {
|
||||||
id: WlRegionId,
|
id: WlRegionId,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::backend::{InputEvent, KeyState, OutputId, ScrollAxis};
|
use crate::backend::{ConnectorId, InputEvent, KeyState, ScrollAxis};
|
||||||
use crate::client::{Client, ClientId};
|
use crate::client::{Client, ClientId};
|
||||||
use crate::fixed::Fixed;
|
use crate::fixed::Fixed;
|
||||||
use crate::ifs::ipc;
|
use crate::ifs::ipc;
|
||||||
|
|
@ -113,19 +113,28 @@ impl WlSeatGlobal {
|
||||||
pub fn event(self: &Rc<Self>, event: InputEvent) {
|
pub fn event(self: &Rc<Self>, event: InputEvent) {
|
||||||
match event {
|
match event {
|
||||||
InputEvent::Key(k, s) => self.key_event(k, s),
|
InputEvent::Key(k, s) => self.key_event(k, s),
|
||||||
InputEvent::OutputPosition(o, x, y) => self.output_position_event(o, x, y),
|
InputEvent::ConnectorPosition(o, x, y) => self.connector_position_event(o, x, y),
|
||||||
InputEvent::Motion(dx, dy) => self.motion_event(dx, dy),
|
InputEvent::Motion(dx, dy) => self.motion_event(dx, dy),
|
||||||
InputEvent::Button(b, s) => self.pointer_owner.button(self, b, s),
|
InputEvent::Button(b, s) => self.pointer_owner.button(self, b, s),
|
||||||
InputEvent::Scroll(d, a) => self.pointer_owner.scroll(self, d, a),
|
InputEvent::Scroll(d, a) => self.pointer_owner.scroll(self, d, a),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn output_position_event(self: &Rc<Self>, output: OutputId, mut x: Fixed, mut y: Fixed) {
|
fn connector_position_event(
|
||||||
let output = match self.state.outputs.get(&output) {
|
self: &Rc<Self>,
|
||||||
|
connector: ConnectorId,
|
||||||
|
mut x: Fixed,
|
||||||
|
mut y: Fixed,
|
||||||
|
) {
|
||||||
|
let output = match self.state.connectors.get(&connector) {
|
||||||
Some(o) => o,
|
Some(o) => o,
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
let pos = output.position();
|
let node = match output.node.get() {
|
||||||
|
Some(n) => n,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
let pos = node.global.pos.get();
|
||||||
x += Fixed::from_int(pos.x1());
|
x += Fixed::from_int(pos.x1());
|
||||||
y += Fixed::from_int(pos.y1());
|
y += Fixed::from_int(pos.y1());
|
||||||
self.set_new_position(x, y);
|
self.set_new_position(x, y);
|
||||||
|
|
|
||||||
|
|
@ -75,11 +75,13 @@ impl ZwlrLayerShellV1 {
|
||||||
break 'get_output output;
|
break 'get_output output;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let outputs = self.client.state.outputs.lock();
|
let outputs = self.client.state.connectors.lock();
|
||||||
match outputs.values().next() {
|
for output in outputs.values() {
|
||||||
Some(ou) => ou.node.get().unwrap(),
|
if let Some(node) = output.node.get() {
|
||||||
_ => return Err(GetLayerSurfaceError::NoOutputs),
|
break 'get_output node;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return Err(GetLayerSurfaceError::NoOutputs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
log::info!("output = {:?}", output.global.pos.get());
|
log::info!("output = {:?}", output.global.pos.get());
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::utils::errorfmt::ErrorFmt;
|
use crate::utils::errorfmt::ErrorFmt;
|
||||||
use crate::utils::oserror::OsError;
|
use crate::utils::oserror::OsError;
|
||||||
use crate::utils::ptr_ext::MutPtrExt;
|
use crate::utils::ptr_ext::MutPtrExt;
|
||||||
|
use backtrace::Backtrace;
|
||||||
use bstr::{BStr, BString, ByteSlice};
|
use bstr::{BStr, BString, ByteSlice};
|
||||||
use log::{Level, Log, Metadata, Record};
|
use log::{Level, Log, Metadata, Record};
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
|
|
@ -29,8 +30,7 @@ impl Logger {
|
||||||
Ok(fd) => fd,
|
Ok(fd) => fd,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let e = OsError::from(e);
|
let e = OsError::from(e);
|
||||||
eprintln!("Error: Could not dup stderr: {}", ErrorFmt(e));
|
fatal!("Error: Could not dup stderr: {}", ErrorFmt(e));
|
||||||
std::process::exit(1);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Self::install(level, b"", file)
|
Self::install(level, b"", file)
|
||||||
|
|
@ -55,13 +55,31 @@ impl Logger {
|
||||||
Err(Errno(c::EEXIST)) => {}
|
Err(Errno(c::EEXIST)) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let e: OsError = e.into();
|
let e: OsError = e.into();
|
||||||
eprintln!("Error: Could not create log file: {}", ErrorFmt(e));
|
fatal!("Error: Could not create log file: {}", ErrorFmt(e));
|
||||||
std::process::exit(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unreachable!();
|
unreachable!();
|
||||||
};
|
};
|
||||||
|
std::panic::set_hook(Box::new(|p| {
|
||||||
|
if let Some(loc) = p.location() {
|
||||||
|
log::error!(
|
||||||
|
"Panic at {} line {} column {}",
|
||||||
|
loc.file(),
|
||||||
|
loc.line(),
|
||||||
|
loc.column()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
log::error!("Panic at unknown location");
|
||||||
|
}
|
||||||
|
if let Some(msg) = p.payload().downcast_ref::<&str>() {
|
||||||
|
log::error!("Message: {}", msg);
|
||||||
|
}
|
||||||
|
if let Some(msg) = p.payload().downcast_ref::<String>() {
|
||||||
|
log::error!("Message: {}", msg);
|
||||||
|
}
|
||||||
|
log::error!("Backtrace:\n{:?}", Backtrace::new());
|
||||||
|
}));
|
||||||
Self::install(level, path.as_bytes(), file)
|
Self::install(level, path.as_bytes(), file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
c_variadic,
|
c_variadic,
|
||||||
thread_local,
|
thread_local,
|
||||||
label_break_value,
|
label_break_value,
|
||||||
try_blocks,
|
|
||||||
generic_associated_types,
|
generic_associated_types,
|
||||||
extern_types
|
extern_types
|
||||||
)]
|
)]
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ pub struct Rect {
|
||||||
|
|
||||||
type Container = SmallVec<[Rect; 1]>;
|
type Container = SmallVec<[Rect; 1]>;
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Region {
|
pub struct Region {
|
||||||
rects: Container,
|
rects: Container,
|
||||||
extents: Rect,
|
extents: Rect,
|
||||||
|
|
@ -75,6 +75,7 @@ impl Rect {
|
||||||
Some(Self { x1, y1, x2, y2 })
|
Some(Self { x1, y1, x2, y2 })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
fn new_unchecked(x1: i32, y1: i32, x2: i32, y2: i32) -> Self {
|
fn new_unchecked(x1: i32, y1: i32, x2: i32, y2: i32) -> Self {
|
||||||
Self { x1, y1, x2, y2 }
|
Self { x1, y1, x2, y2 }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,21 @@
|
||||||
use crate::rect::{Container, Rect, Region};
|
use crate::rect::{Container, Rect, Region};
|
||||||
use crate::utils::windows::WindowsExt;
|
use crate::utils::windows::WindowsExt;
|
||||||
|
use once_cell::unsync::Lazy;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::{BinaryHeap};
|
use std::collections::BinaryHeap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[thread_local]
|
||||||
|
static EMPTY: Lazy<Rc<Region>> = Lazy::new(|| {
|
||||||
|
Rc::new(Region {
|
||||||
|
rects: Default::default(),
|
||||||
|
extents: Default::default(),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
impl Region {
|
impl Region {
|
||||||
pub fn new(rect: Rect) -> Rc<Self> {
|
pub fn new(rect: Rect) -> Rc<Self> {
|
||||||
let mut rects = SmallVec::new();
|
let mut rects = SmallVec::new();
|
||||||
|
|
@ -17,9 +26,13 @@ impl Region {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn empty() -> Rc<Self> {
|
||||||
|
EMPTY.clone()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_rects(rects: &[Rect]) -> Rc<Self> {
|
pub fn from_rects(rects: &[Rect]) -> Rc<Self> {
|
||||||
if rects.is_empty() {
|
if rects.is_empty() {
|
||||||
return Rc::new(Self::default());
|
return Self::empty();
|
||||||
}
|
}
|
||||||
if rects.len() == 1 {
|
if rects.len() == 1 {
|
||||||
return Self::new(rects[0]);
|
return Self::new(rects[0]);
|
||||||
|
|
@ -531,13 +544,22 @@ impl Default for BuilderOp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct RegionBuilder {
|
pub struct RegionBuilder {
|
||||||
base: Rc<Region>,
|
base: Rc<Region>,
|
||||||
op: BuilderOp,
|
op: BuilderOp,
|
||||||
pending: Vec<Rect>,
|
pending: Vec<Rect>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for RegionBuilder {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
base: Region::empty(),
|
||||||
|
op: Default::default(),
|
||||||
|
pending: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl RegionBuilder {
|
impl RegionBuilder {
|
||||||
pub fn add(&mut self, rect: Rect) {
|
pub fn add(&mut self, rect: Rect) {
|
||||||
self.set_op(BuilderOp::Add);
|
self.set_op(BuilderOp::Add);
|
||||||
|
|
@ -556,7 +578,7 @@ impl RegionBuilder {
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.pending.clear();
|
self.pending.clear();
|
||||||
self.base = Rc::new(Region::default());
|
self.base = Region::empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_op(&mut self, op: BuilderOp) {
|
fn set_op(&mut self, op: BuilderOp) {
|
||||||
|
|
|
||||||
19
src/state.rs
19
src/state.rs
|
|
@ -1,7 +1,5 @@
|
||||||
use crate::async_engine::{AsyncEngine, SpawnedFuture};
|
use crate::async_engine::{AsyncEngine, SpawnedFuture};
|
||||||
use crate::backend::{
|
use crate::backend::{Backend, BackendEvent, Connector, ConnectorId, ConnectorIds, InputDevice, InputDeviceId, InputDeviceIds, MonitorInfo};
|
||||||
Backend, BackendEvent, InputDevice, InputDeviceId, InputDeviceIds, OutputId, OutputIds,
|
|
||||||
};
|
|
||||||
use crate::client::{Client, Clients};
|
use crate::client::{Client, Clients};
|
||||||
use crate::config::ConfigProxy;
|
use crate::config::ConfigProxy;
|
||||||
use crate::cursor::ServerCursors;
|
use crate::cursor::ServerCursors;
|
||||||
|
|
@ -9,7 +7,6 @@ use crate::dbus::Dbus;
|
||||||
use crate::event_loop::EventLoop;
|
use crate::event_loop::EventLoop;
|
||||||
use crate::forker::ForkerProxy;
|
use crate::forker::ForkerProxy;
|
||||||
use crate::globals::{Globals, GlobalsError, WaylandGlobal};
|
use crate::globals::{Globals, GlobalsError, WaylandGlobal};
|
||||||
use crate::ifs::wl_output::WlOutputGlobal;
|
|
||||||
use crate::ifs::wl_seat::{SeatIds, WlSeatGlobal};
|
use crate::ifs::wl_seat::{SeatIds, WlSeatGlobal};
|
||||||
use crate::ifs::wl_surface::NoneSurfaceExt;
|
use crate::ifs::wl_surface::NoneSurfaceExt;
|
||||||
use crate::logger::Logger;
|
use crate::logger::Logger;
|
||||||
|
|
@ -25,7 +22,6 @@ use crate::utils::copyhashmap::CopyHashMap;
|
||||||
use crate::utils::errorfmt::ErrorFmt;
|
use crate::utils::errorfmt::ErrorFmt;
|
||||||
use crate::utils::fdcloser::FdCloser;
|
use crate::utils::fdcloser::FdCloser;
|
||||||
use crate::utils::linkedlist::LinkedList;
|
use crate::utils::linkedlist::LinkedList;
|
||||||
use crate::utils::numcell::NumCell;
|
|
||||||
use crate::utils::queue::AsyncQueue;
|
use crate::utils::queue::AsyncQueue;
|
||||||
use crate::wheel::Wheel;
|
use crate::wheel::Wheel;
|
||||||
use crate::xkbcommon::{XkbContext, XkbKeymap};
|
use crate::xkbcommon::{XkbContext, XkbKeymap};
|
||||||
|
|
@ -45,9 +41,8 @@ pub struct State {
|
||||||
pub cursors: CloneCell<Option<Rc<ServerCursors>>>,
|
pub cursors: CloneCell<Option<Rc<ServerCursors>>>,
|
||||||
pub wheel: Rc<Wheel>,
|
pub wheel: Rc<Wheel>,
|
||||||
pub clients: Clients,
|
pub clients: Clients,
|
||||||
pub next_name: NumCell<u32>,
|
|
||||||
pub globals: Globals,
|
pub globals: Globals,
|
||||||
pub output_ids: OutputIds,
|
pub connector_ids: ConnectorIds,
|
||||||
pub seat_ids: SeatIds,
|
pub seat_ids: SeatIds,
|
||||||
pub input_device_ids: InputDeviceIds,
|
pub input_device_ids: InputDeviceIds,
|
||||||
pub node_ids: NodeIds,
|
pub node_ids: NodeIds,
|
||||||
|
|
@ -55,9 +50,7 @@ pub struct State {
|
||||||
pub workspaces: CopyHashMap<String, Rc<WorkspaceNode>>,
|
pub workspaces: CopyHashMap<String, Rc<WorkspaceNode>>,
|
||||||
pub dummy_output: CloneCell<Option<Rc<OutputNode>>>,
|
pub dummy_output: CloneCell<Option<Rc<OutputNode>>>,
|
||||||
pub backend_events: AsyncQueue<BackendEvent>,
|
pub backend_events: AsyncQueue<BackendEvent>,
|
||||||
pub output_handlers: RefCell<AHashMap<OutputId, SpawnedFuture<()>>>,
|
|
||||||
pub input_device_handlers: RefCell<AHashMap<InputDeviceId, InputDeviceData>>,
|
pub input_device_handlers: RefCell<AHashMap<InputDeviceId, InputDeviceData>>,
|
||||||
pub outputs: CopyHashMap<OutputId, Rc<WlOutputGlobal>>,
|
|
||||||
pub seat_queue: LinkedList<Rc<WlSeatGlobal>>,
|
pub seat_queue: LinkedList<Rc<WlSeatGlobal>>,
|
||||||
pub slow_clients: AsyncQueue<Rc<Client>>,
|
pub slow_clients: AsyncQueue<Rc<Client>>,
|
||||||
pub none_surface_ext: Rc<NoneSurfaceExt>,
|
pub none_surface_ext: Rc<NoneSurfaceExt>,
|
||||||
|
|
@ -71,6 +64,7 @@ pub struct State {
|
||||||
pub dbus: Dbus,
|
pub dbus: Dbus,
|
||||||
pub fdcloser: Arc<FdCloser>,
|
pub fdcloser: Arc<FdCloser>,
|
||||||
pub logger: Arc<Logger>,
|
pub logger: Arc<Logger>,
|
||||||
|
pub connectors: CopyHashMap<ConnectorId, Rc<ConnectorData>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct InputDeviceData {
|
pub struct InputDeviceData {
|
||||||
|
|
@ -84,6 +78,13 @@ pub struct DeviceHandlerData {
|
||||||
pub device: Rc<dyn InputDevice>,
|
pub device: Rc<dyn InputDevice>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct ConnectorData {
|
||||||
|
pub connector: Rc<dyn Connector>,
|
||||||
|
pub monitor_info: CloneCell<Option<Rc<MonitorInfo>>>,
|
||||||
|
pub handler: Cell<Option<SpawnedFuture<()>>>,
|
||||||
|
pub node: CloneCell<Option<Rc<OutputNode>>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
pub fn set_render_ctx(&self, ctx: &Rc<RenderContext>) {
|
pub fn set_render_ctx(&self, ctx: &Rc<RenderContext>) {
|
||||||
let cursors = match ServerCursors::load(ctx) {
|
let cursors = match ServerCursors::load(ctx) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
mod backend;
|
mod backend;
|
||||||
|
mod connector;
|
||||||
mod input_device;
|
mod input_device;
|
||||||
mod output;
|
|
||||||
mod slow_clients;
|
mod slow_clients;
|
||||||
mod start_backend;
|
mod start_backend;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::backend::{BackendEvent, Connector};
|
use crate::backend::{BackendEvent};
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
use crate::tasks::input_device;
|
use crate::tasks::{connector, input_device};
|
||||||
use crate::tasks::output::OutputHandler;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct BackendEventHandler {
|
pub struct BackendEventHandler {
|
||||||
|
|
@ -18,18 +17,8 @@ impl BackendEventHandler {
|
||||||
|
|
||||||
fn handle_event(&mut self, event: BackendEvent) {
|
fn handle_event(&mut self, event: BackendEvent) {
|
||||||
match event {
|
match event {
|
||||||
BackendEvent::NewConnector(output) => self.handle_new_output(output),
|
BackendEvent::NewConnector(connector) => connector::handle(&self.state, &connector),
|
||||||
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 Connector>) {
|
|
||||||
let id = output.id();
|
|
||||||
let oh = OutputHandler {
|
|
||||||
state: self.state.clone(),
|
|
||||||
output,
|
|
||||||
};
|
|
||||||
let future = self.state.eng.spawn(oh.handle());
|
|
||||||
self.state.output_handlers.borrow_mut().insert(id, future);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
128
src/tasks/connector.rs
Normal file
128
src/tasks/connector.rs
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
use crate::backend::{Connector, ConnectorEvent, ConnectorId, MonitorInfo};
|
||||||
|
use crate::ifs::wl_output::WlOutputGlobal;
|
||||||
|
use crate::rect::Rect;
|
||||||
|
use crate::state::{ConnectorData, State};
|
||||||
|
use crate::tree::{OutputNode, OutputRenderData};
|
||||||
|
use crate::utils::asyncevent::AsyncEvent;
|
||||||
|
use crate::utils::clonecell::CloneCell;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub fn handle(state: &Rc<State>, connector: &Rc<dyn Connector>) {
|
||||||
|
let id = connector.id();
|
||||||
|
let data = Rc::new(ConnectorData {
|
||||||
|
connector: connector.clone(),
|
||||||
|
monitor_info: Default::default(),
|
||||||
|
handler: Default::default(),
|
||||||
|
node: Default::default(),
|
||||||
|
});
|
||||||
|
let oh = ConnectorHandler {
|
||||||
|
id,
|
||||||
|
state: state.clone(),
|
||||||
|
data: data.clone(),
|
||||||
|
};
|
||||||
|
let future = state.eng.spawn(oh.handle());
|
||||||
|
data.handler.set(Some(future));
|
||||||
|
state.connectors.set(id, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ConnectorHandler {
|
||||||
|
id: ConnectorId,
|
||||||
|
state: Rc<State>,
|
||||||
|
data: Rc<ConnectorData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConnectorHandler {
|
||||||
|
async fn handle(self) {
|
||||||
|
let ae = Rc::new(AsyncEvent::default());
|
||||||
|
{
|
||||||
|
let ae = ae.clone();
|
||||||
|
self.data.connector.on_change(Rc::new(move || ae.trigger()));
|
||||||
|
}
|
||||||
|
if let Some(config) = self.state.config.get() {
|
||||||
|
config.new_connector(self.id);
|
||||||
|
}
|
||||||
|
'outer: loop {
|
||||||
|
while let Some(event) = self.data.connector.event() {
|
||||||
|
match event {
|
||||||
|
ConnectorEvent::Removed => break 'outer,
|
||||||
|
ConnectorEvent::Connected(mi) => self.handle_connected(&ae, mi).await,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ae.triggered().await;
|
||||||
|
}
|
||||||
|
if let Some(config) = self.state.config.get() {
|
||||||
|
config.del_connector(self.id);
|
||||||
|
}
|
||||||
|
self.data.handler.set(None);
|
||||||
|
self.state.connectors.remove(&self.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_connected(&self, ae: &Rc<AsyncEvent>, info: MonitorInfo) {
|
||||||
|
log::info!("Connector {} connected: {:#?}", self.data.connector.kernel_id(), info);
|
||||||
|
self.data.monitor_info.set(Some(Rc::new(info.clone())));
|
||||||
|
let name = self.state.globals.name();
|
||||||
|
let x1 = self
|
||||||
|
.state
|
||||||
|
.root
|
||||||
|
.outputs
|
||||||
|
.lock()
|
||||||
|
.values()
|
||||||
|
.map(|o| o.global.pos.get().x2())
|
||||||
|
.max()
|
||||||
|
.unwrap_or(0);
|
||||||
|
let global = Rc::new(WlOutputGlobal::new(
|
||||||
|
name,
|
||||||
|
&self.data,
|
||||||
|
x1,
|
||||||
|
&info.initial_mode,
|
||||||
|
&info.manufacturer,
|
||||||
|
&info.product,
|
||||||
|
info.width_mm,
|
||||||
|
info.height_mm,
|
||||||
|
));
|
||||||
|
let on = Rc::new(OutputNode {
|
||||||
|
id: self.state.node_ids.next(),
|
||||||
|
workspaces: Default::default(),
|
||||||
|
workspace: CloneCell::new(None),
|
||||||
|
seat_state: Default::default(),
|
||||||
|
global: global.clone(),
|
||||||
|
layers: Default::default(),
|
||||||
|
render_data: RefCell::new(OutputRenderData {
|
||||||
|
active_workspace: Rect::new_empty(0, 0),
|
||||||
|
inactive_workspaces: Default::default(),
|
||||||
|
titles: Default::default(),
|
||||||
|
}),
|
||||||
|
state: self.state.clone(),
|
||||||
|
is_dummy: false,
|
||||||
|
});
|
||||||
|
self.data.node.set(Some(on.clone()));
|
||||||
|
global.node.set(Some(on.clone()));
|
||||||
|
if let Some(config) = self.state.config.get() {
|
||||||
|
config.connector_connected(self.id);
|
||||||
|
}
|
||||||
|
on.ensure_workspace();
|
||||||
|
self.state.root.outputs.set(self.id, on.clone());
|
||||||
|
self.state.add_global(&global);
|
||||||
|
'outer: loop {
|
||||||
|
while let Some(event) = self.data.connector.event() {
|
||||||
|
match event {
|
||||||
|
ConnectorEvent::Disconnected => break 'outer,
|
||||||
|
ConnectorEvent::ModeChanged(mode) => {
|
||||||
|
on.update_mode(mode);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ae.triggered().await;
|
||||||
|
}
|
||||||
|
if let Some(config) = self.state.config.get() {
|
||||||
|
config.connector_disconnected(self.id);
|
||||||
|
}
|
||||||
|
self.data.node.take();
|
||||||
|
global.node.set(None);
|
||||||
|
let _ = self.state.remove_global(&*global);
|
||||||
|
self.state.root.outputs.remove(&self.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,98 +0,0 @@
|
||||||
use crate::backend::{Connector, ConnectorEvent};
|
|
||||||
use crate::ifs::wl_output::WlOutputGlobal;
|
|
||||||
use crate::rect::Rect;
|
|
||||||
use crate::state::State;
|
|
||||||
use crate::tree::{OutputNode, OutputRenderData, WorkspaceNode};
|
|
||||||
use crate::utils::asyncevent::AsyncEvent;
|
|
||||||
use crate::utils::clonecell::CloneCell;
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
pub struct OutputHandler {
|
|
||||||
pub state: Rc<State>,
|
|
||||||
pub output: Rc<dyn Connector>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl OutputHandler {
|
|
||||||
pub async fn handle(self) {
|
|
||||||
let ae = Rc::new(AsyncEvent::default());
|
|
||||||
{
|
|
||||||
let ae = ae.clone();
|
|
||||||
self.output.on_change(Rc::new(move || ae.trigger()));
|
|
||||||
}
|
|
||||||
let name = self.state.globals.name();
|
|
||||||
let x1 = self
|
|
||||||
.state
|
|
||||||
.root
|
|
||||||
.outputs
|
|
||||||
.lock()
|
|
||||||
.values()
|
|
||||||
.map(|o| o.global.pos.get().x2())
|
|
||||||
.max()
|
|
||||||
.unwrap_or(0);
|
|
||||||
let global = Rc::new(WlOutputGlobal::new(name, self.output.clone(), x1));
|
|
||||||
let on = Rc::new(OutputNode {
|
|
||||||
id: self.state.node_ids.next(),
|
|
||||||
workspaces: Default::default(),
|
|
||||||
workspace: CloneCell::new(None),
|
|
||||||
seat_state: Default::default(),
|
|
||||||
global: global.clone(),
|
|
||||||
layers: Default::default(),
|
|
||||||
render_data: RefCell::new(OutputRenderData {
|
|
||||||
active_workspace: Rect::new_empty(0, 0),
|
|
||||||
inactive_workspaces: Default::default(),
|
|
||||||
titles: Default::default(),
|
|
||||||
}),
|
|
||||||
state: self.state.clone(),
|
|
||||||
is_dummy: false,
|
|
||||||
});
|
|
||||||
global.node.set(Some(on.clone()));
|
|
||||||
let name = 'name: {
|
|
||||||
for i in 1.. {
|
|
||||||
let name = i.to_string();
|
|
||||||
if !self.state.workspaces.contains(&name) {
|
|
||||||
break 'name name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unreachable!();
|
|
||||||
};
|
|
||||||
let workspace = Rc::new(WorkspaceNode {
|
|
||||||
id: self.state.node_ids.next(),
|
|
||||||
output: CloneCell::new(on.clone()),
|
|
||||||
position: Default::default(),
|
|
||||||
container: Default::default(),
|
|
||||||
stacked: Default::default(),
|
|
||||||
seat_state: Default::default(),
|
|
||||||
name: name.clone(),
|
|
||||||
output_link: Default::default(),
|
|
||||||
});
|
|
||||||
self.state.workspaces.set(name, workspace.clone());
|
|
||||||
workspace
|
|
||||||
.output_link
|
|
||||||
.set(Some(on.workspaces.add_last(workspace.clone())));
|
|
||||||
on.show_workspace(&workspace);
|
|
||||||
on.update_render_data();
|
|
||||||
self.state.root.outputs.set(self.output.id(), on.clone());
|
|
||||||
self.state.add_global(&global);
|
|
||||||
self.state.outputs.set(self.output.id(), global.clone());
|
|
||||||
'outer: loop {
|
|
||||||
while let Some(event) = self.output.event() {
|
|
||||||
match event {
|
|
||||||
ConnectorEvent::Removed => break 'outer,
|
|
||||||
ConnectorEvent::ModeChanged(mode) => {
|
|
||||||
on.update_mode(mode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ae.triggered().await;
|
|
||||||
}
|
|
||||||
global.node.set(None);
|
|
||||||
self.state.outputs.remove(&self.output.id());
|
|
||||||
let _ = self.state.remove_global(&*global);
|
|
||||||
self.state
|
|
||||||
.output_handlers
|
|
||||||
.borrow_mut()
|
|
||||||
.remove(&self.output.id());
|
|
||||||
self.state.root.outputs.remove(&self.output.id());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::backend::{KeyState, OutputId, ScrollAxis};
|
use crate::backend::{ConnectorId, KeyState, ScrollAxis};
|
||||||
use crate::client::{Client, ClientId};
|
use crate::client::{Client, ClientId};
|
||||||
use crate::cursor::KnownCursor;
|
use crate::cursor::KnownCursor;
|
||||||
use crate::fixed::Fixed;
|
use crate::fixed::Fixed;
|
||||||
|
|
@ -356,7 +356,7 @@ tree_id!(ToplevelNodeId);
|
||||||
|
|
||||||
pub struct DisplayNode {
|
pub struct DisplayNode {
|
||||||
pub id: NodeId,
|
pub id: NodeId,
|
||||||
pub outputs: CopyHashMap<OutputId, Rc<OutputNode>>,
|
pub outputs: CopyHashMap<ConnectorId, Rc<OutputNode>>,
|
||||||
pub stacked: LinkedList<Rc<dyn Node>>,
|
pub stacked: LinkedList<Rc<dyn Node>>,
|
||||||
pub xstacked: LinkedList<Rc<Xwindow>>,
|
pub xstacked: LinkedList<Rc<Xwindow>>,
|
||||||
pub seat_state: NodeSeatState,
|
pub seat_state: NodeSeatState,
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,37 @@ impl OutputNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ensure_workspace(self: &Rc<Self>) {
|
||||||
|
if !self.workspaces.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let name = 'name: {
|
||||||
|
for i in 1.. {
|
||||||
|
let name = i.to_string();
|
||||||
|
if !self.state.workspaces.contains(&name) {
|
||||||
|
break 'name name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
let workspace = Rc::new(WorkspaceNode {
|
||||||
|
id: self.state.node_ids.next(),
|
||||||
|
output: CloneCell::new(self.clone()),
|
||||||
|
position: Default::default(),
|
||||||
|
container: Default::default(),
|
||||||
|
stacked: Default::default(),
|
||||||
|
seat_state: Default::default(),
|
||||||
|
name: name.clone(),
|
||||||
|
output_link: Default::default(),
|
||||||
|
});
|
||||||
|
self.state.workspaces.set(name, workspace.clone());
|
||||||
|
workspace
|
||||||
|
.output_link
|
||||||
|
.set(Some(self.workspaces.add_last(workspace.clone())));
|
||||||
|
self.show_workspace(&workspace);
|
||||||
|
self.update_render_data();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn show_workspace(&self, ws: &Rc<WorkspaceNode>) {
|
pub fn show_workspace(&self, ws: &Rc<WorkspaceNode>) {
|
||||||
self.workspace.set(Some(ws.clone()));
|
self.workspace.set(Some(ws.clone()));
|
||||||
ws.clone().change_extents(&self.workspace_rect());
|
ws.clone().change_extents(&self.workspace_rect());
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,10 @@ impl<T> LinkedList<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.last().is_none()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn last(&self) -> Option<NodeRef<T>> {
|
pub fn last(&self) -> Option<NodeRef<T>> {
|
||||||
unsafe { self.endpoint(self.root.data.as_ref().prev.get()) }
|
unsafe { self.endpoint(self.root.data.as_ref().prev.get()) }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue