wayland: implement wp-drm-lease-v1
This commit is contained in:
parent
e92c92bf49
commit
abbc847144
27 changed files with 797 additions and 19 deletions
|
|
@ -1,5 +1,7 @@
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- Needs jay-compositor release.
|
||||||
|
|
||||||
# 1.1.0
|
# 1.1.0
|
||||||
|
|
||||||
- Needs jay-config release.
|
- Needs jay-config release.
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,10 @@ You can explicitly opt into giving applications access to privileged protocols v
|
||||||
|
|
||||||
Jay's shortcut system allows you to execute an action when a key is pressed and to execute a different action when the key is released.
|
Jay's shortcut system allows you to execute an action when a key is pressed and to execute a different action when the key is released.
|
||||||
|
|
||||||
|
## VR
|
||||||
|
|
||||||
|
Jay's supports leasing VR headsets to applications.
|
||||||
|
|
||||||
## Protocol Support
|
## Protocol Support
|
||||||
|
|
||||||
Jay supports the following wayland protocols:
|
Jay supports the following wayland protocols:
|
||||||
|
|
@ -139,6 +143,7 @@ Jay supports the following wayland protocols:
|
||||||
| wp_alpha_modifier_v1 | 1 | |
|
| wp_alpha_modifier_v1 | 1 | |
|
||||||
| wp_content_type_manager_v1 | 1 | |
|
| wp_content_type_manager_v1 | 1 | |
|
||||||
| wp_cursor_shape_manager_v1 | 1 | |
|
| wp_cursor_shape_manager_v1 | 1 | |
|
||||||
|
| wp_drm_lease_device_v1 | 1 | |
|
||||||
| wp_fractional_scale_manager_v1 | 1 | |
|
| wp_fractional_scale_manager_v1 | 1 | |
|
||||||
| wp_linux_drm_syncobj_manager_v1 | 1 | |
|
| wp_linux_drm_syncobj_manager_v1 | 1 | |
|
||||||
| wp_presentation | 1 | |
|
| wp_presentation | 1 | |
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
- Add support for wp-security-manager-v1.
|
- Add support for wp-security-manager-v1.
|
||||||
- Add support for xdg-dialog-v1.
|
- Add support for xdg-dialog-v1.
|
||||||
- Add support for ext-transient-seat-v1.
|
- Add support for ext-transient-seat-v1.
|
||||||
|
- Add support for wp-drm-lease-v1.
|
||||||
|
|
||||||
# 1.1.0 (2024-04-22)
|
# 1.1.0 (2024-04-22)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::SpawnedFuture,
|
async_engine::SpawnedFuture,
|
||||||
client::{ClientCaps, CAP_LAYER_SHELL},
|
client::{ClientCaps, CAPS_DEFAULT},
|
||||||
state::State,
|
state::State,
|
||||||
utils::{errorfmt::ErrorFmt, oserror::OsError, xrd::xrd},
|
utils::{errorfmt::ErrorFmt, oserror::OsError, xrd::xrd},
|
||||||
},
|
},
|
||||||
|
|
@ -154,7 +154,7 @@ impl Acceptor {
|
||||||
state.eng.spawn(accept(
|
state.eng.spawn(accept(
|
||||||
acc.socket.insecure.clone(),
|
acc.socket.insecure.clone(),
|
||||||
state.clone(),
|
state.clone(),
|
||||||
CAP_LAYER_SHELL,
|
CAPS_DEFAULT,
|
||||||
)),
|
)),
|
||||||
];
|
];
|
||||||
state.acceptor.set(Some(acc.clone()));
|
state.acceptor.set(Some(acc.clone()));
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use {
|
||||||
gfx_api::{GfxFramebuffer, SyncFile},
|
gfx_api::{GfxFramebuffer, SyncFile},
|
||||||
ifs::wl_seat::wl_pointer::{CONTINUOUS, FINGER, HORIZONTAL_SCROLL, VERTICAL_SCROLL, WHEEL},
|
ifs::wl_seat::wl_pointer::{CONTINUOUS, FINGER, HORIZONTAL_SCROLL, VERTICAL_SCROLL, WHEEL},
|
||||||
libinput::consts::DeviceCapability,
|
libinput::consts::DeviceCapability,
|
||||||
video::drm::{ConnectorType, DrmError, DrmVersion},
|
video::drm::{ConnectorType, DrmConnector, DrmError, DrmVersion},
|
||||||
},
|
},
|
||||||
jay_config::video::GfxApi,
|
jay_config::video::GfxApi,
|
||||||
std::{
|
std::{
|
||||||
|
|
@ -94,6 +94,9 @@ pub trait Connector {
|
||||||
fn set_non_desktop_override(&self, non_desktop: Option<bool>) {
|
fn set_non_desktop_override(&self, non_desktop: Option<bool>) {
|
||||||
let _ = non_desktop;
|
let _ = non_desktop;
|
||||||
}
|
}
|
||||||
|
fn drm_object_id(&self) -> Option<DrmConnector> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
||||||
|
|
@ -1246,6 +1246,10 @@ impl Connector for MetalConnector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn drm_object_id(&self) -> Option<DrmConnector> {
|
||||||
|
Some(self.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MetalCrtc {
|
pub struct MetalCrtc {
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,12 @@ bitflags! {
|
||||||
CAP_LAYER_SHELL = 1 << 6,
|
CAP_LAYER_SHELL = 1 << 6,
|
||||||
CAP_SCREENCOPY_MANAGER = 1 << 7,
|
CAP_SCREENCOPY_MANAGER = 1 << 7,
|
||||||
CAP_SEAT_MANAGER = 1 << 8,
|
CAP_SEAT_MANAGER = 1 << 8,
|
||||||
|
CAP_DRM_LEASE = 1 << 9,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const CAPS_DEFAULT: ClientCaps = ClientCaps(CAP_LAYER_SHELL.0 | CAP_DRM_LEASE.0);
|
||||||
|
pub const CAPS_DEFAULT_SANDBOXED: ClientCaps = ClientCaps(CAP_DRM_LEASE.0);
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
pub struct ClientId(u64);
|
pub struct ClientId(u64);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ use {
|
||||||
xdg_surface::{xdg_toplevel::XdgToplevel, XdgSurface},
|
xdg_surface::{xdg_toplevel::XdgToplevel, XdgSurface},
|
||||||
WlSurface,
|
WlSurface,
|
||||||
},
|
},
|
||||||
|
wp_drm_lease_connector_v1::WpDrmLeaseConnectorV1,
|
||||||
wp_linux_drm_syncobj_timeline_v1::WpLinuxDrmSyncobjTimelineV1,
|
wp_linux_drm_syncobj_timeline_v1::WpLinuxDrmSyncobjTimelineV1,
|
||||||
xdg_positioner::XdgPositioner,
|
xdg_positioner::XdgPositioner,
|
||||||
xdg_wm_base::XdgWmBase,
|
xdg_wm_base::XdgWmBase,
|
||||||
|
|
@ -32,8 +33,9 @@ use {
|
||||||
wire::{
|
wire::{
|
||||||
JayOutputId, JayScreencastId, JayToplevelId, JayWorkspaceId, WlBufferId,
|
JayOutputId, JayScreencastId, JayToplevelId, JayWorkspaceId, WlBufferId,
|
||||||
WlDataSourceId, WlOutputId, WlPointerId, WlRegionId, WlRegistryId, WlSeatId,
|
WlDataSourceId, WlOutputId, WlPointerId, WlRegionId, WlRegistryId, WlSeatId,
|
||||||
WlSurfaceId, WpLinuxDrmSyncobjTimelineV1Id, XdgPositionerId, XdgSurfaceId,
|
WlSurfaceId, WpDrmLeaseConnectorV1Id, WpLinuxDrmSyncobjTimelineV1Id, XdgPositionerId,
|
||||||
XdgToplevelId, XdgWmBaseId, ZwlrDataControlSourceV1Id, ZwpPrimarySelectionSourceV1Id,
|
XdgSurfaceId, XdgToplevelId, XdgWmBaseId, ZwlrDataControlSourceV1Id,
|
||||||
|
ZwpPrimarySelectionSourceV1Id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
std::{cell::RefCell, mem, rc::Rc},
|
std::{cell::RefCell, mem, rc::Rc},
|
||||||
|
|
@ -62,6 +64,7 @@ pub struct Objects {
|
||||||
pub timelines: CopyHashMap<WpLinuxDrmSyncobjTimelineV1Id, Rc<WpLinuxDrmSyncobjTimelineV1>>,
|
pub timelines: CopyHashMap<WpLinuxDrmSyncobjTimelineV1Id, Rc<WpLinuxDrmSyncobjTimelineV1>>,
|
||||||
pub zwlr_data_sources: CopyHashMap<ZwlrDataControlSourceV1Id, Rc<ZwlrDataControlSourceV1>>,
|
pub zwlr_data_sources: CopyHashMap<ZwlrDataControlSourceV1Id, Rc<ZwlrDataControlSourceV1>>,
|
||||||
pub jay_toplevels: CopyHashMap<JayToplevelId, Rc<JayToplevel>>,
|
pub jay_toplevels: CopyHashMap<JayToplevelId, Rc<JayToplevel>>,
|
||||||
|
pub drm_lease_outputs: CopyHashMap<WpDrmLeaseConnectorV1Id, Rc<WpDrmLeaseConnectorV1>>,
|
||||||
ids: RefCell<Vec<usize>>,
|
ids: RefCell<Vec<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -92,6 +95,7 @@ impl Objects {
|
||||||
timelines: Default::default(),
|
timelines: Default::default(),
|
||||||
zwlr_data_sources: Default::default(),
|
zwlr_data_sources: Default::default(),
|
||||||
jay_toplevels: Default::default(),
|
jay_toplevels: Default::default(),
|
||||||
|
drm_lease_outputs: Default::default(),
|
||||||
ids: RefCell::new(vec![]),
|
ids: RefCell::new(vec![]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -126,6 +130,7 @@ impl Objects {
|
||||||
self.timelines.clear();
|
self.timelines.clear();
|
||||||
self.zwlr_data_sources.clear();
|
self.zwlr_data_sources.clear();
|
||||||
self.jay_toplevels.clear();
|
self.jay_toplevels.clear();
|
||||||
|
self.drm_lease_outputs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn id<T>(&self, client_data: &Client) -> Result<T, ClientError>
|
pub fn id<T>(&self, client_data: &Client) -> Result<T, ClientError>
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,10 @@ pub mod wp_content_type_manager_v1;
|
||||||
pub mod wp_content_type_v1;
|
pub mod wp_content_type_v1;
|
||||||
pub mod wp_cursor_shape_device_v1;
|
pub mod wp_cursor_shape_device_v1;
|
||||||
pub mod wp_cursor_shape_manager_v1;
|
pub mod wp_cursor_shape_manager_v1;
|
||||||
|
pub mod wp_drm_lease_connector_v1;
|
||||||
|
pub mod wp_drm_lease_device_v1;
|
||||||
|
pub mod wp_drm_lease_request_v1;
|
||||||
|
pub mod wp_drm_lease_v1;
|
||||||
pub mod wp_fractional_scale_manager_v1;
|
pub mod wp_fractional_scale_manager_v1;
|
||||||
pub mod wp_linux_drm_syncobj_manager_v1;
|
pub mod wp_linux_drm_syncobj_manager_v1;
|
||||||
pub mod wp_linux_drm_syncobj_timeline_v1;
|
pub mod wp_linux_drm_syncobj_timeline_v1;
|
||||||
|
|
|
||||||
93
src/ifs/wp_drm_lease_connector_v1.rs
Normal file
93
src/ifs/wp_drm_lease_connector_v1.rs
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
backend::ConnectorId as BackendConnectorId,
|
||||||
|
client::{Client, ClientError},
|
||||||
|
ifs::wp_drm_lease_device_v1::WpDrmLeaseDeviceV1,
|
||||||
|
leaks::Tracker,
|
||||||
|
object::{Object, Version},
|
||||||
|
utils::bindings::Bindings,
|
||||||
|
wire::{wp_drm_lease_connector_v1::*, WpDrmLeaseConnectorV1Id},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct WpDrmLeaseConnectorV1 {
|
||||||
|
pub id: WpDrmLeaseConnectorV1Id,
|
||||||
|
pub client: Rc<Client>,
|
||||||
|
pub tracker: Tracker<Self>,
|
||||||
|
pub version: Version,
|
||||||
|
pub device: Rc<WpDrmLeaseDeviceV1>,
|
||||||
|
pub connector_id: BackendConnectorId,
|
||||||
|
pub bindings: Rc<Bindings<Self>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WpDrmLeaseConnectorV1 {
|
||||||
|
fn detach(&self) {
|
||||||
|
self.bindings.remove(&self.client, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_name(&self, name: &str) {
|
||||||
|
self.client.event(Name {
|
||||||
|
self_id: self.id,
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn send_description(&self, description: &str) {
|
||||||
|
self.client.event(Description {
|
||||||
|
self_id: self.id,
|
||||||
|
description,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_connector_id(&self, connector_id: u32) {
|
||||||
|
self.client.event(ConnectorId {
|
||||||
|
self_id: self.id,
|
||||||
|
connector_id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_done(&self) {
|
||||||
|
self.client.event(Done { self_id: self.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_withdrawn(&self) {
|
||||||
|
self.client.event(Withdrawn { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WpDrmLeaseConnectorV1RequestHandler for WpDrmLeaseConnectorV1 {
|
||||||
|
type Error = WpDrmLeaseConnectorV1Error;
|
||||||
|
|
||||||
|
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.detach();
|
||||||
|
self.client.remove_obj(self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_base! {
|
||||||
|
self = WpDrmLeaseConnectorV1;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for WpDrmLeaseConnectorV1 {
|
||||||
|
fn break_loops(&self) {
|
||||||
|
self.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dedicated_add_obj!(
|
||||||
|
WpDrmLeaseConnectorV1,
|
||||||
|
WpDrmLeaseConnectorV1Id,
|
||||||
|
drm_lease_outputs
|
||||||
|
);
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum WpDrmLeaseConnectorV1Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientError(Box<ClientError>),
|
||||||
|
}
|
||||||
|
efrom!(WpDrmLeaseConnectorV1Error, ClientError);
|
||||||
228
src/ifs/wp_drm_lease_device_v1.rs
Normal file
228
src/ifs/wp_drm_lease_device_v1.rs
Normal file
|
|
@ -0,0 +1,228 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
backend::DrmDeviceId,
|
||||||
|
client::{Client, ClientCaps, ClientError, CAP_DRM_LEASE},
|
||||||
|
globals::{Global, GlobalName},
|
||||||
|
ifs::{
|
||||||
|
wp_drm_lease_connector_v1::WpDrmLeaseConnectorV1,
|
||||||
|
wp_drm_lease_request_v1::WpDrmLeaseRequestV1,
|
||||||
|
},
|
||||||
|
leaks::Tracker,
|
||||||
|
object::{Object, Version},
|
||||||
|
state::OutputData,
|
||||||
|
utils::{bindings::Bindings, errorfmt::ErrorFmt, oserror::OsError},
|
||||||
|
video::drm::{Drm, DrmError},
|
||||||
|
wire::{wp_drm_lease_device_v1::*, WpDrmLeaseDeviceV1Id},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
thiserror::Error,
|
||||||
|
uapi::{c, OwnedFd},
|
||||||
|
};
|
||||||
|
|
||||||
|
mod removed_device;
|
||||||
|
|
||||||
|
pub struct WpDrmLeaseDeviceV1Global {
|
||||||
|
pub name: GlobalName,
|
||||||
|
pub device: DrmDeviceId,
|
||||||
|
pub bindings: Rc<Bindings<WpDrmLeaseDeviceV1>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WpDrmLeaseDeviceV1Global {
|
||||||
|
fn bind_(
|
||||||
|
self: Rc<Self>,
|
||||||
|
id: WpDrmLeaseDeviceV1Id,
|
||||||
|
client: &Rc<Client>,
|
||||||
|
version: Version,
|
||||||
|
) -> Result<(), WpDrmLeaseDeviceV1Error> {
|
||||||
|
let obj = Rc::new(WpDrmLeaseDeviceV1 {
|
||||||
|
id,
|
||||||
|
client: client.clone(),
|
||||||
|
tracker: Default::default(),
|
||||||
|
version,
|
||||||
|
bindings: self.bindings.clone(),
|
||||||
|
device: self.device,
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
});
|
||||||
|
track!(client, obj);
|
||||||
|
client.add_client_obj(&obj)?;
|
||||||
|
if let Some(dev) = client.state.drm_devs.get(&self.device) {
|
||||||
|
if let Some(node) = &dev.devnode {
|
||||||
|
match reopen_card(node) {
|
||||||
|
Ok(f) => obj.send_drm_fd(&f),
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Could not open master device: {}", ErrorFmt(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for c in dev.connectors.lock().keys() {
|
||||||
|
if let Some(o) = client.state.outputs.get(c) {
|
||||||
|
if o.monitor_info.non_desktop {
|
||||||
|
obj.create_connector(&o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj.send_done();
|
||||||
|
self.bindings.add(client, &obj);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
global_base!(
|
||||||
|
WpDrmLeaseDeviceV1Global,
|
||||||
|
WpDrmLeaseDeviceV1,
|
||||||
|
WpDrmLeaseDeviceV1Error
|
||||||
|
);
|
||||||
|
|
||||||
|
simple_add_global!(WpDrmLeaseDeviceV1Global);
|
||||||
|
|
||||||
|
impl Global for WpDrmLeaseDeviceV1Global {
|
||||||
|
fn singleton(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn version(&self) -> u32 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn break_loops(&self) {
|
||||||
|
self.bindings.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn required_caps(&self) -> ClientCaps {
|
||||||
|
CAP_DRM_LEASE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WpDrmLeaseDeviceV1 {
|
||||||
|
pub id: WpDrmLeaseDeviceV1Id,
|
||||||
|
pub client: Rc<Client>,
|
||||||
|
pub tracker: Tracker<Self>,
|
||||||
|
pub version: Version,
|
||||||
|
pub bindings: Rc<Bindings<Self>>,
|
||||||
|
pub device: DrmDeviceId,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WpDrmLeaseDeviceV1 {
|
||||||
|
fn detach(&self) {
|
||||||
|
self.destroyed.set(true);
|
||||||
|
self.bindings.remove(&self.client, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_connector(self: &Rc<Self>, output: &Rc<OutputData>) {
|
||||||
|
let id = match self.client.new_id() {
|
||||||
|
Ok(i) => i,
|
||||||
|
Err(e) => {
|
||||||
|
self.client.error(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let obj = Rc::new(WpDrmLeaseConnectorV1 {
|
||||||
|
id,
|
||||||
|
client: self.client.clone(),
|
||||||
|
tracker: Default::default(),
|
||||||
|
version: self.version,
|
||||||
|
device: self.clone(),
|
||||||
|
connector_id: output.connector.connector.id(),
|
||||||
|
bindings: output.lease_connectors.clone(),
|
||||||
|
});
|
||||||
|
self.client.add_server_obj(&obj);
|
||||||
|
self.send_connector(&obj);
|
||||||
|
obj.send_name(&output.connector.name);
|
||||||
|
if let Some(id) = output.connector.connector.drm_object_id() {
|
||||||
|
obj.send_connector_id(id.0);
|
||||||
|
}
|
||||||
|
obj.send_done();
|
||||||
|
output.lease_connectors.add(&self.client, &obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_drm_fd(&self, fd: &Rc<OwnedFd>) {
|
||||||
|
self.client.event(DrmFd {
|
||||||
|
self_id: self.id,
|
||||||
|
fd: fd.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_connector(&self, c: &Rc<WpDrmLeaseConnectorV1>) {
|
||||||
|
self.client.event(Connector {
|
||||||
|
self_id: self.id,
|
||||||
|
id: c.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_done(&self) {
|
||||||
|
self.client.event(Done { self_id: self.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_released(&self) {
|
||||||
|
self.client.event(Released { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WpDrmLeaseDeviceV1RequestHandler for WpDrmLeaseDeviceV1 {
|
||||||
|
type Error = WpDrmLeaseDeviceV1Error;
|
||||||
|
|
||||||
|
fn create_lease_request(
|
||||||
|
&self,
|
||||||
|
req: CreateLeaseRequest,
|
||||||
|
_slf: &Rc<Self>,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
let obj = Rc::new(WpDrmLeaseRequestV1 {
|
||||||
|
id: req.id,
|
||||||
|
client: self.client.clone(),
|
||||||
|
tracker: Default::default(),
|
||||||
|
version: self.version,
|
||||||
|
device: self.device,
|
||||||
|
connectors: Default::default(),
|
||||||
|
});
|
||||||
|
self.client.add_client_obj(&obj)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn release(&self, _req: Release, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.detach();
|
||||||
|
self.send_released();
|
||||||
|
self.client.remove_obj(self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_base! {
|
||||||
|
self = WpDrmLeaseDeviceV1;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for WpDrmLeaseDeviceV1 {
|
||||||
|
fn break_loops(&self) {
|
||||||
|
self.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simple_add_obj!(WpDrmLeaseDeviceV1);
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum WpDrmLeaseDeviceV1Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientError(Box<ClientError>),
|
||||||
|
}
|
||||||
|
efrom!(WpDrmLeaseDeviceV1Error, ClientError);
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
enum ReopenError {
|
||||||
|
#[error("Could not open the dev node")]
|
||||||
|
OpenNode(#[source] OsError),
|
||||||
|
#[error("Could not drop DRM master")]
|
||||||
|
DropMaster(#[source] DrmError),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reopen_card(devnode: &str) -> Result<Rc<OwnedFd>, ReopenError> {
|
||||||
|
let fd = uapi::open(devnode, c::O_RDWR | c::O_CLOEXEC, 0)
|
||||||
|
.map_err(|e| ReopenError::OpenNode(e.into()))?;
|
||||||
|
let fd = Rc::new(fd);
|
||||||
|
let drm = Drm::open_existing(fd.clone());
|
||||||
|
if drm.is_master() {
|
||||||
|
drm.drop_master().map_err(ReopenError::DropMaster)?;
|
||||||
|
}
|
||||||
|
Ok(fd)
|
||||||
|
}
|
||||||
80
src/ifs/wp_drm_lease_device_v1/removed_device.rs
Normal file
80
src/ifs/wp_drm_lease_device_v1/removed_device.rs
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
backend::DrmDeviceId,
|
||||||
|
client::{Client, ClientCaps, ClientError, CAP_DRM_LEASE},
|
||||||
|
globals::{Global, GlobalName, RemovableWaylandGlobal},
|
||||||
|
ifs::wp_drm_lease_device_v1::{WpDrmLeaseDeviceV1, WpDrmLeaseDeviceV1Global},
|
||||||
|
object::Version,
|
||||||
|
utils::bindings::Bindings,
|
||||||
|
wire::WpDrmLeaseDeviceV1Id,
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RemovedWpDrmLeaseDeviceV1Global {
|
||||||
|
name: GlobalName,
|
||||||
|
bindings: Rc<Bindings<WpDrmLeaseDeviceV1>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RemovedWpDrmLeaseDeviceV1Global {
|
||||||
|
fn bind_(
|
||||||
|
self: Rc<Self>,
|
||||||
|
id: WpDrmLeaseDeviceV1Id,
|
||||||
|
client: &Rc<Client>,
|
||||||
|
version: Version,
|
||||||
|
) -> Result<(), RemovedWpDrmLeaseDeviceV1Error> {
|
||||||
|
let dev = Rc::new(WpDrmLeaseDeviceV1 {
|
||||||
|
id,
|
||||||
|
client: client.clone(),
|
||||||
|
tracker: Default::default(),
|
||||||
|
version,
|
||||||
|
bindings: self.bindings.clone(),
|
||||||
|
device: DrmDeviceId::from_raw(0),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
});
|
||||||
|
track!(client, dev);
|
||||||
|
client.add_client_obj(&dev)?;
|
||||||
|
dev.send_done();
|
||||||
|
dev.bindings.add(client, &dev);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
global_base!(
|
||||||
|
RemovedWpDrmLeaseDeviceV1Global,
|
||||||
|
WpDrmLeaseDeviceV1,
|
||||||
|
RemovedWpDrmLeaseDeviceV1Error
|
||||||
|
);
|
||||||
|
|
||||||
|
simple_add_global!(RemovedWpDrmLeaseDeviceV1Global);
|
||||||
|
|
||||||
|
impl Global for RemovedWpDrmLeaseDeviceV1Global {
|
||||||
|
fn singleton(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn version(&self) -> u32 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn required_caps(&self) -> ClientCaps {
|
||||||
|
CAP_DRM_LEASE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RemovableWaylandGlobal for WpDrmLeaseDeviceV1Global {
|
||||||
|
fn create_replacement(&self) -> Rc<dyn Global> {
|
||||||
|
Rc::new(RemovedWpDrmLeaseDeviceV1Global {
|
||||||
|
name: self.name,
|
||||||
|
bindings: Default::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum RemovedWpDrmLeaseDeviceV1Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientError(Box<ClientError>),
|
||||||
|
}
|
||||||
|
efrom!(RemovedWpDrmLeaseDeviceV1Error, ClientError);
|
||||||
84
src/ifs/wp_drm_lease_request_v1.rs
Normal file
84
src/ifs/wp_drm_lease_request_v1.rs
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
backend::{ConnectorId, DrmDeviceId},
|
||||||
|
client::{Client, ClientError},
|
||||||
|
ifs::wp_drm_lease_v1::{WpDrmLeaseV1, WpDrmLeaseV1Lessee},
|
||||||
|
leaks::Tracker,
|
||||||
|
object::{Object, Version},
|
||||||
|
utils::copyhashmap::CopyHashMap,
|
||||||
|
wire::{wp_drm_lease_request_v1::*, WpDrmLeaseConnectorV1Id, WpDrmLeaseRequestV1Id},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct WpDrmLeaseRequestV1 {
|
||||||
|
pub id: WpDrmLeaseRequestV1Id,
|
||||||
|
pub client: Rc<Client>,
|
||||||
|
pub tracker: Tracker<Self>,
|
||||||
|
pub version: Version,
|
||||||
|
pub device: DrmDeviceId,
|
||||||
|
pub connectors: CopyHashMap<WpDrmLeaseConnectorV1Id, ConnectorId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WpDrmLeaseRequestV1RequestHandler for WpDrmLeaseRequestV1 {
|
||||||
|
type Error = WpDrmLeaseRequestV1Error;
|
||||||
|
|
||||||
|
fn request_connector(&self, req: RequestConnector, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let c = self.client.lookup(req.connector)?;
|
||||||
|
if self.device != c.device.device {
|
||||||
|
return Err(WpDrmLeaseRequestV1Error::MismatchedDevice(c.id));
|
||||||
|
}
|
||||||
|
if self.connectors.contains(&c.id) {
|
||||||
|
return Err(WpDrmLeaseRequestV1Error::RepeatedDevice(c.id));
|
||||||
|
}
|
||||||
|
self.connectors.set(c.id, c.connector_id);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn submit(&self, req: Submit, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.client.remove_obj(self)?;
|
||||||
|
let obj = Rc::new(WpDrmLeaseV1 {
|
||||||
|
id: req.id,
|
||||||
|
client: self.client.clone(),
|
||||||
|
tracker: Default::default(),
|
||||||
|
version: self.version,
|
||||||
|
finished: Cell::new(false),
|
||||||
|
lease: Default::default(),
|
||||||
|
});
|
||||||
|
self.client.add_client_obj(&obj)?;
|
||||||
|
if self.connectors.is_empty() {
|
||||||
|
return Err(WpDrmLeaseRequestV1Error::EmptyLease);
|
||||||
|
}
|
||||||
|
let Some(dev) = self.client.state.drm_devs.get(&self.device) else {
|
||||||
|
obj.send_finished();
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
let lessee = Rc::new(WpDrmLeaseV1Lessee { obj });
|
||||||
|
let connectors: Vec<_> = self.connectors.lock().values().copied().collect();
|
||||||
|
dev.dev.clone().create_lease(lessee, &connectors);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_base! {
|
||||||
|
self = WpDrmLeaseRequestV1;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for WpDrmLeaseRequestV1 {}
|
||||||
|
|
||||||
|
simple_add_obj!(WpDrmLeaseRequestV1);
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum WpDrmLeaseRequestV1Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientError(Box<ClientError>),
|
||||||
|
#[error("Connector {0} does not belong to this device")]
|
||||||
|
MismatchedDevice(WpDrmLeaseConnectorV1Id),
|
||||||
|
#[error("Connector {0} is already part of this request")]
|
||||||
|
RepeatedDevice(WpDrmLeaseConnectorV1Id),
|
||||||
|
#[error("Lease request is empty")]
|
||||||
|
EmptyLease,
|
||||||
|
}
|
||||||
|
efrom!(WpDrmLeaseRequestV1Error, ClientError);
|
||||||
92
src/ifs/wp_drm_lease_v1.rs
Normal file
92
src/ifs/wp_drm_lease_v1.rs
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
backend::{BackendDrmLease, BackendDrmLessee},
|
||||||
|
client::{Client, ClientError},
|
||||||
|
leaks::Tracker,
|
||||||
|
object::{Object, Version},
|
||||||
|
utils::clonecell::CloneCell,
|
||||||
|
wire::{wp_drm_lease_v1::*, WpDrmLeaseV1Id},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
thiserror::Error,
|
||||||
|
uapi::OwnedFd,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct WpDrmLeaseV1Lessee {
|
||||||
|
pub obj: Rc<WpDrmLeaseV1>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BackendDrmLessee for WpDrmLeaseV1Lessee {
|
||||||
|
fn created(&self, lease: Rc<dyn BackendDrmLease>) {
|
||||||
|
if !self.obj.finished.get() {
|
||||||
|
self.obj.send_lease_fd(lease.fd());
|
||||||
|
self.obj.lease.set(Some(lease));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for WpDrmLeaseV1Lessee {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if !self.obj.finished.get() {
|
||||||
|
self.obj.detach();
|
||||||
|
self.obj.send_finished();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WpDrmLeaseV1 {
|
||||||
|
pub id: WpDrmLeaseV1Id,
|
||||||
|
pub client: Rc<Client>,
|
||||||
|
pub tracker: Tracker<Self>,
|
||||||
|
pub version: Version,
|
||||||
|
pub finished: Cell<bool>,
|
||||||
|
pub lease: CloneCell<Option<Rc<dyn BackendDrmLease>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WpDrmLeaseV1 {
|
||||||
|
fn detach(&self) {
|
||||||
|
self.finished.set(true);
|
||||||
|
self.lease.take();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_lease_fd(&self, fd: &Rc<OwnedFd>) {
|
||||||
|
self.client.event(LeaseFd {
|
||||||
|
self_id: self.id,
|
||||||
|
leased_fd: fd.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_finished(&self) {
|
||||||
|
self.client.event(Finished { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WpDrmLeaseV1RequestHandler for WpDrmLeaseV1 {
|
||||||
|
type Error = WpDrmLeaseV1Error;
|
||||||
|
|
||||||
|
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.detach();
|
||||||
|
self.client.remove_obj(self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_base! {
|
||||||
|
self = WpDrmLeaseV1;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for WpDrmLeaseV1 {
|
||||||
|
fn break_loops(&self) {
|
||||||
|
self.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simple_add_obj!(WpDrmLeaseV1);
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum WpDrmLeaseV1Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientError(Box<ClientError>),
|
||||||
|
}
|
||||||
|
efrom!(WpDrmLeaseV1Error, ClientError);
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
client::{Client, ClientCaps, ClientError},
|
client::{Client, ClientError, CAPS_DEFAULT_SANDBOXED},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::{Object, Version},
|
object::{Object, Version},
|
||||||
wire::{wp_security_context_v1::*, WpSecurityContextV1Id},
|
wire::{wp_security_context_v1::*, WpSecurityContextV1Id},
|
||||||
|
|
@ -80,7 +80,7 @@ impl WpSecurityContextV1RequestHandler for WpSecurityContextV1 {
|
||||||
fn commit(&self, _req: Commit, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn commit(&self, _req: Commit, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
self.check_committed()?;
|
self.check_committed()?;
|
||||||
self.committed.set(true);
|
self.committed.set(true);
|
||||||
let caps = ClientCaps::none() & self.client.bounding_caps;
|
let caps = CAPS_DEFAULT_SANDBOXED & self.client.bounding_caps;
|
||||||
self.client.state.security_context_acceptors.spawn(
|
self.client.state.security_context_acceptors.spawn(
|
||||||
&self.client.state,
|
&self.client.state,
|
||||||
self.sandbox_engine.take(),
|
self.sandbox_engine.take(),
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,8 @@ use {
|
||||||
zwp_input_popup_surface_v2::ZwpInputPopupSurfaceV2,
|
zwp_input_popup_surface_v2::ZwpInputPopupSurfaceV2,
|
||||||
NoneSurfaceExt, WlSurface,
|
NoneSurfaceExt, WlSurface,
|
||||||
},
|
},
|
||||||
|
wp_drm_lease_connector_v1::WpDrmLeaseConnectorV1,
|
||||||
|
wp_drm_lease_device_v1::WpDrmLeaseDeviceV1Global,
|
||||||
wp_linux_drm_syncobj_manager_v1::WpLinuxDrmSyncobjManagerV1Global,
|
wp_linux_drm_syncobj_manager_v1::WpLinuxDrmSyncobjManagerV1Global,
|
||||||
zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1,
|
zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1,
|
||||||
zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1,
|
zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1,
|
||||||
|
|
@ -59,8 +61,8 @@ use {
|
||||||
WorkspaceNode,
|
WorkspaceNode,
|
||||||
},
|
},
|
||||||
utils::{
|
utils::{
|
||||||
activation_token::ActivationToken, asyncevent::AsyncEvent, clonecell::CloneCell,
|
activation_token::ActivationToken, asyncevent::AsyncEvent, bindings::Bindings,
|
||||||
copyhashmap::CopyHashMap, errorfmt::ErrorFmt, fdcloser::FdCloser,
|
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, fdcloser::FdCloser,
|
||||||
linkedlist::LinkedList, numcell::NumCell, queue::AsyncQueue, refcounted::RefCounted,
|
linkedlist::LinkedList, numcell::NumCell, queue::AsyncQueue, refcounted::RefCounted,
|
||||||
run_toplevel::RunToplevel,
|
run_toplevel::RunToplevel,
|
||||||
},
|
},
|
||||||
|
|
@ -269,6 +271,7 @@ pub struct OutputData {
|
||||||
pub connector: Rc<ConnectorData>,
|
pub connector: Rc<ConnectorData>,
|
||||||
pub monitor_info: MonitorInfo,
|
pub monitor_info: MonitorInfo,
|
||||||
pub node: Option<Rc<OutputNode>>,
|
pub node: Option<Rc<OutputNode>>,
|
||||||
|
pub lease_connectors: Rc<Bindings<WpDrmLeaseConnectorV1>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DrmDevData {
|
pub struct DrmDevData {
|
||||||
|
|
@ -280,6 +283,7 @@ pub struct DrmDevData {
|
||||||
pub vendor: Option<String>,
|
pub vendor: Option<String>,
|
||||||
pub model: Option<String>,
|
pub model: Option<String>,
|
||||||
pub pci_id: Option<PciId>,
|
pub pci_id: Option<PciId>,
|
||||||
|
pub lease_global: Rc<WpDrmLeaseDeviceV1Global>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DrmDevData {
|
impl DrmDevData {
|
||||||
|
|
|
||||||
|
|
@ -175,6 +175,7 @@ impl ConnectorHandler {
|
||||||
connector: self.data.clone(),
|
connector: self.data.clone(),
|
||||||
monitor_info: info,
|
monitor_info: info,
|
||||||
node: Some(on.clone()),
|
node: Some(on.clone()),
|
||||||
|
lease_connectors: Default::default(),
|
||||||
});
|
});
|
||||||
self.state.outputs.set(self.id, output_data);
|
self.state.outputs.set(self.id, output_data);
|
||||||
on.schedule_update_render_data();
|
on.schedule_update_render_data();
|
||||||
|
|
@ -293,9 +294,6 @@ impl ConnectorHandler {
|
||||||
seat.set_position((tpos.x1() + tpos.x2()) / 2, (tpos.y1() + tpos.y2()) / 2);
|
seat.set_position((tpos.x1() + tpos.x2()) / 2, (tpos.y1() + tpos.y2()) / 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(dev) = &self.data.drm_dev {
|
|
||||||
dev.connectors.remove(&self.id);
|
|
||||||
}
|
|
||||||
self.state
|
self.state
|
||||||
.remove_output_scale(on.global.persistent.scale.get());
|
.remove_output_scale(on.global.persistent.scale.get());
|
||||||
let _ = self.state.remove_global(&*global);
|
let _ = self.state.remove_global(&*global);
|
||||||
|
|
@ -308,8 +306,26 @@ impl ConnectorHandler {
|
||||||
connector: self.data.clone(),
|
connector: self.data.clone(),
|
||||||
monitor_info,
|
monitor_info,
|
||||||
node: None,
|
node: None,
|
||||||
|
lease_connectors: Default::default(),
|
||||||
});
|
});
|
||||||
self.state.outputs.set(self.id, output_data);
|
self.state.outputs.set(self.id, output_data.clone());
|
||||||
|
let advertise = || {
|
||||||
|
if let Some(dev) = &self.data.drm_dev {
|
||||||
|
for binding in dev.lease_global.bindings.lock().values() {
|
||||||
|
binding.create_connector(&output_data);
|
||||||
|
binding.send_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let withdraw = || {
|
||||||
|
for (_, con) in output_data.lease_connectors.lock().drain() {
|
||||||
|
con.send_withdrawn();
|
||||||
|
if !con.device.destroyed.get() {
|
||||||
|
con.device.send_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
advertise();
|
||||||
if let Some(config) = self.state.config.get() {
|
if let Some(config) = self.state.config.get() {
|
||||||
config.connector_connected(self.id);
|
config.connector_connected(self.id);
|
||||||
}
|
}
|
||||||
|
|
@ -317,13 +333,14 @@ impl ConnectorHandler {
|
||||||
while let Some(event) = self.data.connector.event() {
|
while let Some(event) = self.data.connector.event() {
|
||||||
match event {
|
match event {
|
||||||
ConnectorEvent::Disconnected => break 'outer,
|
ConnectorEvent::Disconnected => break 'outer,
|
||||||
ConnectorEvent::Available => {}
|
ConnectorEvent::Available => advertise(),
|
||||||
ConnectorEvent::Unavailable => {}
|
ConnectorEvent::Unavailable => withdraw(),
|
||||||
ev => unreachable!("received unexpected event {:?}", ev),
|
ev => unreachable!("received unexpected event {:?}", ev),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.data.async_event.triggered().await;
|
self.data.async_event.triggered().await;
|
||||||
}
|
}
|
||||||
|
withdraw();
|
||||||
self.state.outputs.remove(&self.id);
|
self.state.outputs.remove(&self.id);
|
||||||
if let Some(config) = self.state.config.get() {
|
if let Some(config) = self.state.config.get() {
|
||||||
config.connector_disconnected(self.id);
|
config.connector_disconnected(self.id);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
backend::{BackendDrmDevice, DrmDeviceId, DrmEvent},
|
backend::{BackendDrmDevice, DrmDeviceId, DrmEvent},
|
||||||
|
ifs::wp_drm_lease_device_v1::WpDrmLeaseDeviceV1Global,
|
||||||
state::{DrmDevData, State},
|
state::{DrmDevData, State},
|
||||||
tasks::udev_utils::udev_props,
|
tasks::udev_utils::udev_props,
|
||||||
utils::asyncevent::AsyncEvent,
|
utils::asyncevent::AsyncEvent,
|
||||||
|
|
@ -11,6 +12,12 @@ use {
|
||||||
pub fn handle(state: &Rc<State>, dev: Rc<dyn BackendDrmDevice>) {
|
pub fn handle(state: &Rc<State>, dev: Rc<dyn BackendDrmDevice>) {
|
||||||
let id = dev.id();
|
let id = dev.id();
|
||||||
let props = udev_props(dev.dev_t(), 1);
|
let props = udev_props(dev.dev_t(), 1);
|
||||||
|
let lease_global = Rc::new(WpDrmLeaseDeviceV1Global {
|
||||||
|
name: state.globals.name(),
|
||||||
|
device: id,
|
||||||
|
bindings: Default::default(),
|
||||||
|
});
|
||||||
|
state.add_global(&lease_global);
|
||||||
let data = Rc::new(DrmDevData {
|
let data = Rc::new(DrmDevData {
|
||||||
dev: dev.clone(),
|
dev: dev.clone(),
|
||||||
handler: Cell::new(None),
|
handler: Cell::new(None),
|
||||||
|
|
@ -20,6 +27,7 @@ pub fn handle(state: &Rc<State>, dev: Rc<dyn BackendDrmDevice>) {
|
||||||
vendor: props.vendor,
|
vendor: props.vendor,
|
||||||
model: props.model,
|
model: props.model,
|
||||||
pci_id: props.pci_id,
|
pci_id: props.pci_id,
|
||||||
|
lease_global,
|
||||||
});
|
});
|
||||||
let oh = DrvDevHandler {
|
let oh = DrvDevHandler {
|
||||||
id,
|
id,
|
||||||
|
|
@ -66,6 +74,8 @@ impl DrvDevHandler {
|
||||||
if let Some(config) = self.state.config.get() {
|
if let Some(config) = self.state.config.get() {
|
||||||
config.del_drm_dev(self.id);
|
config.del_drm_dev(self.id);
|
||||||
}
|
}
|
||||||
|
self.data.lease_global.bindings.clear();
|
||||||
|
let _ = self.state.remove_global(&*self.data.lease_global);
|
||||||
self.data.handler.set(None);
|
self.data.handler.set(None);
|
||||||
self.state.drm_devs.remove(&self.id);
|
self.state.drm_devs.remove(&self.id);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
pub mod activation_token;
|
pub mod activation_token;
|
||||||
pub mod array;
|
pub mod array;
|
||||||
pub mod asyncevent;
|
pub mod asyncevent;
|
||||||
|
pub mod bindings;
|
||||||
pub mod bitfield;
|
pub mod bitfield;
|
||||||
pub mod bitflags;
|
pub mod bitflags;
|
||||||
pub mod buf;
|
pub mod buf;
|
||||||
|
|
|
||||||
39
src/utils/bindings.rs
Normal file
39
src/utils/bindings.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
client::{Client, ClientId},
|
||||||
|
object::{Object, ObjectId},
|
||||||
|
utils::copyhashmap::{CopyHashMap, Locked},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Bindings<P> {
|
||||||
|
bindings: CopyHashMap<(ClientId, ObjectId), Rc<P>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P> Default for Bindings<P> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
bindings: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Object> Bindings<P> {
|
||||||
|
pub fn add(&self, client: &Client, obj: &Rc<P>) {
|
||||||
|
let prev = self.bindings.set((client.id, obj.id()), obj.clone());
|
||||||
|
assert!(prev.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(&self, client: &Client, obj: &P) {
|
||||||
|
self.bindings.remove(&(client.id, obj.id()));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&self) {
|
||||||
|
self.bindings.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lock(&self) -> Locked<(ClientId, ObjectId), Rc<P>> {
|
||||||
|
self.bindings.lock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -163,7 +163,7 @@ static ERRORS: Lazy<&'static [Option<&'static str>]> = Lazy::new(|| {
|
||||||
res.leak()
|
res.leak()
|
||||||
});
|
});
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub struct OsError(pub c::c_int);
|
pub struct OsError(pub c::c_int);
|
||||||
|
|
||||||
impl From<Errno> for OsError {
|
impl From<Errno> for OsError {
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,8 @@ use crate::{
|
||||||
video::{
|
video::{
|
||||||
dmabuf::DmaBuf,
|
dmabuf::DmaBuf,
|
||||||
drm::sys::{
|
drm::sys::{
|
||||||
drm_format_modifier, drm_format_modifier_blob, get_version, revoke_lease,
|
auth_magic, drm_format_modifier, drm_format_modifier_blob, drop_master, get_version,
|
||||||
DRM_CAP_CURSOR_HEIGHT, DRM_CAP_CURSOR_WIDTH, FORMAT_BLOB_CURRENT,
|
revoke_lease, DRM_CAP_CURSOR_HEIGHT, DRM_CAP_CURSOR_WIDTH, FORMAT_BLOB_CURRENT,
|
||||||
},
|
},
|
||||||
Modifier, INVALID_MODIFIER,
|
Modifier, INVALID_MODIFIER,
|
||||||
},
|
},
|
||||||
|
|
@ -139,6 +139,8 @@ pub enum DrmError {
|
||||||
ImportSyncFile(#[source] OsError),
|
ImportSyncFile(#[source] OsError),
|
||||||
#[error("Could not create a lease")]
|
#[error("Could not create a lease")]
|
||||||
CreateLease(#[source] OsError),
|
CreateLease(#[source] OsError),
|
||||||
|
#[error("Could not drop DRM master")]
|
||||||
|
DropMaster(#[source] OsError),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_node_name(fd: c::c_int) -> Result<Ustring, DrmError> {
|
fn render_node_name(fd: c::c_int) -> Result<Ustring, DrmError> {
|
||||||
|
|
@ -175,7 +177,6 @@ pub struct Drm {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drm {
|
impl Drm {
|
||||||
#[cfg_attr(not(feature = "it"), allow(dead_code))]
|
|
||||||
pub fn open_existing(fd: Rc<OwnedFd>) -> Self {
|
pub fn open_existing(fd: Rc<OwnedFd>) -> Self {
|
||||||
Self { fd }
|
Self { fd }
|
||||||
}
|
}
|
||||||
|
|
@ -213,6 +214,14 @@ impl Drm {
|
||||||
pub fn version(&self) -> Result<DrmVersion, DrmError> {
|
pub fn version(&self) -> Result<DrmVersion, DrmError> {
|
||||||
get_version(self.fd.raw()).map_err(DrmError::Version)
|
get_version(self.fd.raw()).map_err(DrmError::Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn drop_master(&self) -> Result<(), DrmError> {
|
||||||
|
drop_master(self.fd.raw()).map_err(DrmError::DropMaster)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_master(&self) -> bool {
|
||||||
|
auth_magic(self.fd.raw(), 0) != Err(OsError(c::EACCES))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct InFormat {
|
pub struct InFormat {
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,10 @@ pub unsafe fn ioctl<T>(fd: c::c_int, request: c::c_ulong, t: &mut T) -> Result<c
|
||||||
|
|
||||||
pub const DRM_IOCTL_BASE: u64 = b'd' as u64;
|
pub const DRM_IOCTL_BASE: u64 = b'd' as u64;
|
||||||
|
|
||||||
|
pub const fn drm_io(nr: u64) -> u64 {
|
||||||
|
uapi::_IO(DRM_IOCTL_BASE, nr)
|
||||||
|
}
|
||||||
|
|
||||||
pub const fn drm_iow<T>(nr: u64) -> u64 {
|
pub const fn drm_iow<T>(nr: u64) -> u64 {
|
||||||
uapi::_IOW::<T>(DRM_IOCTL_BASE, nr)
|
uapi::_IOW::<T>(DRM_IOCTL_BASE, nr)
|
||||||
}
|
}
|
||||||
|
|
@ -1369,3 +1373,28 @@ pub fn sync_ioc_merge(left: c::c_int, right: c::c_int) -> Result<OwnedFd, OsErro
|
||||||
}
|
}
|
||||||
Ok(OwnedFd::new(res.fence))
|
Ok(OwnedFd::new(res.fence))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DRM_IOCTL_DROP_MASTER: u64 = drm_io(0x1f);
|
||||||
|
|
||||||
|
pub fn drop_master(fd: c::c_int) -> Result<(), OsError> {
|
||||||
|
let mut res = 0u8;
|
||||||
|
unsafe {
|
||||||
|
ioctl(fd, DRM_IOCTL_DROP_MASTER, &mut res)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
const DRM_IOCTL_AUTH_MAGIC: u64 = drm_iow::<drm_auth>(0x11);
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct drm_auth {
|
||||||
|
magic: c::c_uint,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn auth_magic(fd: c::c_int, magic: c::c_uint) -> Result<(), OsError> {
|
||||||
|
let mut res = drm_auth { magic };
|
||||||
|
unsafe {
|
||||||
|
ioctl(fd, DRM_IOCTL_AUTH_MAGIC, &mut res)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
||||||
23
wire/wp_drm_lease_connector_v1.txt
Normal file
23
wire/wp_drm_lease_connector_v1.txt
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
request destroy {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event name {
|
||||||
|
name: str,
|
||||||
|
}
|
||||||
|
|
||||||
|
event description {
|
||||||
|
description: str,
|
||||||
|
}
|
||||||
|
|
||||||
|
event connector_id {
|
||||||
|
connector_id: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
event done {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event withdrawn {
|
||||||
|
|
||||||
|
}
|
||||||
23
wire/wp_drm_lease_device_v1.txt
Normal file
23
wire/wp_drm_lease_device_v1.txt
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
request create_lease_request {
|
||||||
|
id: id(wp_drm_lease_request_v1),
|
||||||
|
}
|
||||||
|
|
||||||
|
request release {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event drm_fd {
|
||||||
|
fd: fd,
|
||||||
|
}
|
||||||
|
|
||||||
|
event connector {
|
||||||
|
id: id(wp_drm_lease_connector_v1),
|
||||||
|
}
|
||||||
|
|
||||||
|
event done {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event released {
|
||||||
|
|
||||||
|
}
|
||||||
7
wire/wp_drm_lease_request_v1.txt
Normal file
7
wire/wp_drm_lease_request_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request request_connector {
|
||||||
|
connector: id(wp_drm_lease_connector_v1),
|
||||||
|
}
|
||||||
|
|
||||||
|
request submit {
|
||||||
|
id: id(wp_drm_lease_v1),
|
||||||
|
}
|
||||||
11
wire/wp_drm_lease_v1.txt
Normal file
11
wire/wp_drm_lease_v1.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
request destroy {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event lease_fd {
|
||||||
|
leased_fd: fd,
|
||||||
|
}
|
||||||
|
|
||||||
|
event finished {
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue