Merge pull request #501 from mahkoh/jorth/output-management
Implement jay-head-v1
This commit is contained in:
commit
2c116e2a16
108 changed files with 4701 additions and 82 deletions
21
Cargo.lock
generated
21
Cargo.lock
generated
|
|
@ -627,6 +627,7 @@ dependencies = [
|
||||||
"tiny-skia",
|
"tiny-skia",
|
||||||
"tracy-client-sys",
|
"tracy-client-sys",
|
||||||
"uapi",
|
"uapi",
|
||||||
|
"with_builtin_macros",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1740,6 +1741,26 @@ dependencies = [
|
||||||
"bitflags 2.8.0",
|
"bitflags 2.8.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "with_builtin_macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24deb3cd6e530e7617b12b1f0f1ce160a3a71d92feb351c4db5156d1d10e398a"
|
||||||
|
dependencies = [
|
||||||
|
"with_builtin_macros-proc_macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "with_builtin_macros-proc_macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2259ae9b1285596f1ee52ce8f627013c65853d4d7f271cb10bfe2d048769804a"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.7.35"
|
version = "0.7.35"
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ tiny-skia = { version = "0.11.4", default-features = false, features = ["std"] }
|
||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
cfg-if = "1.0.0"
|
cfg-if = "1.0.0"
|
||||||
opera = "1.0.1"
|
opera = "1.0.1"
|
||||||
|
with_builtin_macros = "0.1.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
repc = "0.1.1"
|
repc = "0.1.1"
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,7 @@ pub struct MonitorInfo {
|
||||||
pub width_mm: i32,
|
pub width_mm: i32,
|
||||||
pub height_mm: i32,
|
pub height_mm: i32,
|
||||||
pub non_desktop: bool,
|
pub non_desktop: bool,
|
||||||
|
pub non_desktop_effective: bool,
|
||||||
pub vrr_capable: bool,
|
pub vrr_capable: bool,
|
||||||
pub transfer_functions: Vec<BackendTransferFunction>,
|
pub transfer_functions: Vec<BackendTransferFunction>,
|
||||||
pub color_spaces: Vec<BackendColorSpace>,
|
pub color_spaces: Vec<BackendColorSpace>,
|
||||||
|
|
@ -124,6 +125,13 @@ impl Display for ConnectorKernelId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
ConnectorCaps: u32;
|
||||||
|
CONCAP_CONNECTOR = 1 << 0,
|
||||||
|
CONCAP_MODE_SETTING = 1 << 1,
|
||||||
|
CONCAP_PHYSICAL_DISPLAY = 1 << 2,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Connector: Any {
|
pub trait Connector: Any {
|
||||||
fn id(&self) -> ConnectorId;
|
fn id(&self) -> ConnectorId;
|
||||||
fn kernel_id(&self) -> ConnectorKernelId;
|
fn kernel_id(&self) -> ConnectorKernelId;
|
||||||
|
|
@ -132,6 +140,9 @@ pub trait Connector: Any {
|
||||||
fn damage(&self);
|
fn damage(&self);
|
||||||
fn drm_dev(&self) -> Option<DrmDeviceId>;
|
fn drm_dev(&self) -> Option<DrmDeviceId>;
|
||||||
fn effectively_locked(&self) -> bool;
|
fn effectively_locked(&self) -> bool;
|
||||||
|
fn caps(&self) -> ConnectorCaps {
|
||||||
|
ConnectorCaps::none()
|
||||||
|
}
|
||||||
fn drm_feedback(&self) -> Option<Rc<DrmFeedback>> {
|
fn drm_feedback(&self) -> Option<Rc<DrmFeedback>> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,10 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
backend::{
|
backend::{
|
||||||
BackendColorSpace, BackendConnectorState, BackendTransferFunction, Connector,
|
BackendColorSpace, BackendConnectorState, BackendTransferFunction, Connector,
|
||||||
ConnectorKernelId, Mode,
|
ConnectorId, ConnectorKernelId, Mode,
|
||||||
},
|
},
|
||||||
backends::metal::MetalError,
|
backends::metal::MetalError,
|
||||||
|
state::State,
|
||||||
utils::{errorfmt::ErrorFmt, hash_map_ext::HashMapExt},
|
utils::{errorfmt::ErrorFmt, hash_map_ext::HashMapExt},
|
||||||
video::drm::DrmError,
|
video::drm::DrmError,
|
||||||
},
|
},
|
||||||
|
|
@ -149,50 +150,74 @@ pub trait BackendAppliedConnectorTransaction {
|
||||||
fn rollback(self: Box<Self>) -> Result<(), BackendConnectorTransactionError>;
|
fn rollback(self: Box<Self>) -> Result<(), BackendConnectorTransactionError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
struct Common {
|
||||||
|
state: Rc<State>,
|
||||||
|
states: AHashMap<ConnectorId, BackendConnectorState>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ConnectorTransaction {
|
pub struct ConnectorTransaction {
|
||||||
|
common: Common,
|
||||||
parts:
|
parts:
|
||||||
AHashMap<Box<dyn BackendConnectorTransactionTypeDyn>, Box<dyn BackendConnectorTransaction>>,
|
AHashMap<Box<dyn BackendConnectorTransactionTypeDyn>, Box<dyn BackendConnectorTransaction>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct PreparedConnectorTransaction {
|
pub struct PreparedConnectorTransaction {
|
||||||
|
common: Common,
|
||||||
parts: Vec<Box<dyn BackendPreparedConnectorTransaction>>,
|
parts: Vec<Box<dyn BackendPreparedConnectorTransaction>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct AppliedConnectorTransaction {
|
pub struct AppliedConnectorTransaction {
|
||||||
|
common: Common,
|
||||||
parts: Vec<Box<dyn BackendAppliedConnectorTransaction>>,
|
parts: Vec<Box<dyn BackendAppliedConnectorTransaction>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConnectorTransaction {
|
impl ConnectorTransaction {
|
||||||
|
pub fn new(state: &Rc<State>) -> Self {
|
||||||
|
Self {
|
||||||
|
common: Common {
|
||||||
|
state: state.clone(),
|
||||||
|
states: Default::default(),
|
||||||
|
},
|
||||||
|
parts: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add(
|
pub fn add(
|
||||||
&mut self,
|
&mut self,
|
||||||
connector: &Rc<dyn Connector>,
|
connector: &Rc<dyn Connector>,
|
||||||
change: BackendConnectorState,
|
mut state: BackendConnectorState,
|
||||||
) -> Result<(), BackendConnectorTransactionError> {
|
) -> Result<(), BackendConnectorTransactionError> {
|
||||||
|
state.serial = self.common.state.backend_connector_state_serials.next();
|
||||||
let ty = connector.transaction_type();
|
let ty = connector.transaction_type();
|
||||||
let tran = match self.parts.entry(ty) {
|
let tran = match self.parts.entry(ty) {
|
||||||
Entry::Occupied(v) => v.into_mut(),
|
Entry::Occupied(v) => v.into_mut(),
|
||||||
Entry::Vacant(v) => v.insert(connector.create_transaction()?),
|
Entry::Vacant(v) => v.insert(connector.create_transaction()?),
|
||||||
};
|
};
|
||||||
tran.add(connector, change)
|
tran.add(connector, state)?;
|
||||||
|
self.common.states.insert(connector.id(), state);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prepare(
|
pub fn prepare(
|
||||||
&mut self,
|
mut self,
|
||||||
) -> Result<PreparedConnectorTransaction, BackendConnectorTransactionError> {
|
) -> Result<PreparedConnectorTransaction, BackendConnectorTransactionError> {
|
||||||
let mut new = vec![];
|
let mut new = vec![];
|
||||||
for tran in self.parts.drain_values() {
|
for tran in self.parts.drain_values() {
|
||||||
new.push(tran.prepare()?);
|
new.push(tran.prepare()?);
|
||||||
}
|
}
|
||||||
Ok(PreparedConnectorTransaction { parts: new })
|
Ok(PreparedConnectorTransaction {
|
||||||
|
common: self.common,
|
||||||
|
parts: new,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PreparedConnectorTransaction {
|
impl PreparedConnectorTransaction {
|
||||||
pub fn apply(self) -> Result<AppliedConnectorTransaction, BackendConnectorTransactionError> {
|
pub fn apply(self) -> Result<AppliedConnectorTransaction, BackendConnectorTransactionError> {
|
||||||
let mut applied = AppliedConnectorTransaction::default();
|
let mut applied = AppliedConnectorTransaction {
|
||||||
|
common: self.common,
|
||||||
|
parts: vec![],
|
||||||
|
};
|
||||||
for tran in self.parts {
|
for tran in self.parts {
|
||||||
applied.parts.push(tran.apply()?);
|
applied.parts.push(tran.apply()?);
|
||||||
}
|
}
|
||||||
|
|
@ -205,6 +230,11 @@ impl AppliedConnectorTransaction {
|
||||||
for tran in self.parts.drain(..) {
|
for tran in self.parts.drain(..) {
|
||||||
tran.commit();
|
tran.commit();
|
||||||
}
|
}
|
||||||
|
for (connector_id, state) in self.common.states.drain() {
|
||||||
|
if let Some(c) = self.common.state.connectors.get(&connector_id) {
|
||||||
|
c.set_state(&self.common.state, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,10 @@ use {
|
||||||
async_engine::{Phase, SpawnedFuture},
|
async_engine::{Phase, SpawnedFuture},
|
||||||
backend::{
|
backend::{
|
||||||
BackendColorSpace, BackendConnectorState, BackendDrmDevice, BackendDrmLease,
|
BackendColorSpace, BackendConnectorState, BackendDrmDevice, BackendDrmLease,
|
||||||
BackendDrmLessee, BackendEvent, BackendLuminance, BackendTransferFunction, Connector,
|
BackendDrmLessee, BackendEvent, BackendLuminance, BackendTransferFunction,
|
||||||
ConnectorEvent, ConnectorId, ConnectorKernelId, DrmDeviceId, HardwareCursor,
|
CONCAP_CONNECTOR, CONCAP_MODE_SETTING, CONCAP_PHYSICAL_DISPLAY, Connector,
|
||||||
HardwareCursorUpdate, Mode, MonitorInfo,
|
ConnectorCaps, ConnectorEvent, ConnectorId, ConnectorKernelId, DrmDeviceId,
|
||||||
|
HardwareCursor, HardwareCursorUpdate, Mode, MonitorInfo,
|
||||||
transaction::{
|
transaction::{
|
||||||
BackendConnectorTransaction, BackendConnectorTransactionError,
|
BackendConnectorTransaction, BackendConnectorTransactionError,
|
||||||
BackendConnectorTransactionType, BackendConnectorTransactionTypeDyn,
|
BackendConnectorTransactionType, BackendConnectorTransactionTypeDyn,
|
||||||
|
|
@ -726,7 +727,7 @@ impl MetalConnector {
|
||||||
match &event {
|
match &event {
|
||||||
ConnectorEvent::Connected(ty) => match state {
|
ConnectorEvent::Connected(ty) => match state {
|
||||||
FrontState::Disconnected => {
|
FrontState::Disconnected => {
|
||||||
let non_desktop = ty.non_desktop;
|
let non_desktop = ty.non_desktop_effective;
|
||||||
self.on_change.send_event(event);
|
self.on_change.send_event(event);
|
||||||
set_state(FrontState::Connected { non_desktop });
|
set_state(FrontState::Connected { non_desktop });
|
||||||
}
|
}
|
||||||
|
|
@ -854,6 +855,10 @@ impl Connector for MetalConnector {
|
||||||
fb.locked
|
fb.locked
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn caps(&self) -> ConnectorCaps {
|
||||||
|
CONCAP_CONNECTOR | CONCAP_MODE_SETTING | CONCAP_PHYSICAL_DISPLAY
|
||||||
|
}
|
||||||
|
|
||||||
fn drm_feedback(&self) -> Option<Rc<DrmFeedback>> {
|
fn drm_feedback(&self) -> Option<Rc<DrmFeedback>> {
|
||||||
self.drm_feedback.get()
|
self.drm_feedback.get()
|
||||||
}
|
}
|
||||||
|
|
@ -1910,7 +1915,8 @@ impl MetalBackend {
|
||||||
output_id: dd.output_id.clone(),
|
output_id: dd.output_id.clone(),
|
||||||
width_mm: dd.mm_width as _,
|
width_mm: dd.mm_width as _,
|
||||||
height_mm: dd.mm_height as _,
|
height_mm: dd.mm_height as _,
|
||||||
non_desktop: dd.non_desktop_effective,
|
non_desktop: dd.non_desktop,
|
||||||
|
non_desktop_effective: dd.non_desktop_effective,
|
||||||
vrr_capable: dd.vrr_capable,
|
vrr_capable: dd.vrr_capable,
|
||||||
transfer_functions,
|
transfer_functions,
|
||||||
color_spaces,
|
color_spaces,
|
||||||
|
|
|
||||||
|
|
@ -597,6 +597,7 @@ impl XBackend {
|
||||||
width_mm: output.width.get(),
|
width_mm: output.width.get(),
|
||||||
height_mm: output.height.get(),
|
height_mm: output.height.get(),
|
||||||
non_desktop: false,
|
non_desktop: false,
|
||||||
|
non_desktop_effective: false,
|
||||||
vrr_capable: false,
|
vrr_capable: false,
|
||||||
transfer_functions: vec![],
|
transfer_functions: vec![],
|
||||||
color_spaces: vec![],
|
color_spaces: vec![],
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ bitflags! {
|
||||||
CAP_INPUT_METHOD = 1 << 10,
|
CAP_INPUT_METHOD = 1 << 10,
|
||||||
CAP_WORKSPACE = 1 << 11,
|
CAP_WORKSPACE = 1 << 11,
|
||||||
CAP_FOREIGN_TOPLEVEL_MANAGER = 1 << 12,
|
CAP_FOREIGN_TOPLEVEL_MANAGER = 1 << 12,
|
||||||
|
CAP_HEAD_MANAGER = 1 << 13,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const CAPS_DEFAULT: ClientCaps = ClientCaps(CAP_LAYER_SHELL.0 | CAP_DRM_LEASE.0);
|
pub const CAPS_DEFAULT: ClientCaps = ClientCaps(CAP_LAYER_SHELL.0 | CAP_DRM_LEASE.0);
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ use {
|
||||||
ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
|
ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
|
||||||
ext_image_capture_source_v1::ExtImageCaptureSourceV1,
|
ext_image_capture_source_v1::ExtImageCaptureSourceV1,
|
||||||
ext_image_copy::ext_image_copy_capture_session_v1::ExtImageCopyCaptureSessionV1,
|
ext_image_copy::ext_image_copy_capture_session_v1::ExtImageCopyCaptureSessionV1,
|
||||||
|
head_management::jay_head_error_v1::JayHeadErrorV1,
|
||||||
ipc::{
|
ipc::{
|
||||||
data_control::{
|
data_control::{
|
||||||
ext_data_control_source_v1::ExtDataControlSourceV1,
|
ext_data_control_source_v1::ExtDataControlSourceV1,
|
||||||
|
|
@ -41,12 +42,13 @@ use {
|
||||||
},
|
},
|
||||||
wire::{
|
wire::{
|
||||||
ExtDataControlSourceV1Id, ExtForeignToplevelHandleV1Id, ExtImageCaptureSourceV1Id,
|
ExtDataControlSourceV1Id, ExtForeignToplevelHandleV1Id, ExtImageCaptureSourceV1Id,
|
||||||
ExtImageCopyCaptureSessionV1Id, ExtWorkspaceGroupHandleV1Id, JayOutputId,
|
ExtImageCopyCaptureSessionV1Id, ExtWorkspaceGroupHandleV1Id, JayHeadErrorV1Id,
|
||||||
JayScreencastId, JayToplevelId, JayWorkspaceId, WlBufferId, WlDataSourceId, WlOutputId,
|
JayOutputId, JayScreencastId, JayToplevelId, JayWorkspaceId, WlBufferId,
|
||||||
WlPointerId, WlRegionId, WlRegistryId, WlSeatId, WlSurfaceId, WpDrmLeaseConnectorV1Id,
|
WlDataSourceId, WlOutputId, WlPointerId, WlRegionId, WlRegistryId, WlSeatId,
|
||||||
WpImageDescriptionV1Id, WpLinuxDrmSyncobjTimelineV1Id, XdgPopupId, XdgPositionerId,
|
WlSurfaceId, WpDrmLeaseConnectorV1Id, WpImageDescriptionV1Id,
|
||||||
XdgSurfaceId, XdgToplevelId, XdgWmBaseId, ZwlrDataControlSourceV1Id,
|
WpLinuxDrmSyncobjTimelineV1Id, XdgPopupId, XdgPositionerId, XdgSurfaceId,
|
||||||
ZwpPrimarySelectionSourceV1Id, ZwpTabletToolV2Id,
|
XdgToplevelId, XdgWmBaseId, ZwlrDataControlSourceV1Id, ZwpPrimarySelectionSourceV1Id,
|
||||||
|
ZwpTabletToolV2Id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
std::{cell::RefCell, rc::Rc},
|
std::{cell::RefCell, rc::Rc},
|
||||||
|
|
@ -87,6 +89,7 @@ pub struct Objects {
|
||||||
pub ext_workspace_groups:
|
pub ext_workspace_groups:
|
||||||
CopyHashMap<ExtWorkspaceGroupHandleV1Id, Rc<ExtWorkspaceGroupHandleV1>>,
|
CopyHashMap<ExtWorkspaceGroupHandleV1Id, Rc<ExtWorkspaceGroupHandleV1>>,
|
||||||
pub wp_image_description: CopyHashMap<WpImageDescriptionV1Id, Rc<WpImageDescriptionV1>>,
|
pub wp_image_description: CopyHashMap<WpImageDescriptionV1Id, Rc<WpImageDescriptionV1>>,
|
||||||
|
pub jay_head_errors: CopyHashMap<JayHeadErrorV1Id, Rc<JayHeadErrorV1>>,
|
||||||
ids: RefCell<Vec<usize>>,
|
ids: RefCell<Vec<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -126,6 +129,7 @@ impl Objects {
|
||||||
ext_data_sources: Default::default(),
|
ext_data_sources: Default::default(),
|
||||||
ext_workspace_groups: Default::default(),
|
ext_workspace_groups: Default::default(),
|
||||||
wp_image_description: Default::default(),
|
wp_image_description: Default::default(),
|
||||||
|
jay_head_errors: Default::default(),
|
||||||
ids: RefCell::new(vec![]),
|
ids: RefCell::new(vec![]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -168,6 +172,7 @@ impl Objects {
|
||||||
self.ext_copy_sessions.clear();
|
self.ext_copy_sessions.clear();
|
||||||
self.ext_data_sources.clear();
|
self.ext_data_sources.clear();
|
||||||
self.ext_workspace_groups.clear();
|
self.ext_workspace_groups.clear();
|
||||||
|
self.jay_head_errors.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn id<T>(&self, client_data: &Client) -> Result<T, ClientError>
|
pub fn id<T>(&self, client_data: &Client) -> Result<T, ClientError>
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,9 @@ use {
|
||||||
format::XRGB8888,
|
format::XRGB8888,
|
||||||
globals::Globals,
|
globals::Globals,
|
||||||
ifs::{
|
ifs::{
|
||||||
|
head_management::{
|
||||||
|
HeadManagers, HeadState, jay_head_manager_session_v1::handle_jay_head_manager_done,
|
||||||
|
},
|
||||||
jay_screencast::{perform_screencast_realloc, perform_toplevel_screencasts},
|
jay_screencast::{perform_screencast_realloc, perform_toplevel_screencasts},
|
||||||
wl_output::{OutputId, PersistentOutputState, WlOutputGlobal},
|
wl_output::{OutputId, PersistentOutputState, WlOutputGlobal},
|
||||||
wl_seat::handle_position_hint_requests,
|
wl_seat::handle_position_hint_requests,
|
||||||
|
|
@ -62,6 +65,7 @@ use {
|
||||||
numcell::NumCell,
|
numcell::NumCell,
|
||||||
oserror::OsError,
|
oserror::OsError,
|
||||||
queue::AsyncQueue,
|
queue::AsyncQueue,
|
||||||
|
rc_eq::RcEq,
|
||||||
refcounted::RefCounted,
|
refcounted::RefCounted,
|
||||||
run_toplevel::RunToplevel,
|
run_toplevel::RunToplevel,
|
||||||
tri::Try,
|
tri::Try,
|
||||||
|
|
@ -72,7 +76,10 @@ use {
|
||||||
},
|
},
|
||||||
ahash::AHashSet,
|
ahash::AHashSet,
|
||||||
forker::ForkerProxy,
|
forker::ForkerProxy,
|
||||||
jay_config::{_private::DEFAULT_SEAT_NAME, video::GfxApi},
|
jay_config::{
|
||||||
|
_private::DEFAULT_SEAT_NAME,
|
||||||
|
video::{GfxApi, Transform},
|
||||||
|
},
|
||||||
std::{cell::Cell, env, future::Future, ops::Deref, rc::Rc, sync::Arc, time::Duration},
|
std::{cell::Cell, env, future::Future, ops::Deref, rc::Rc, sync::Arc, time::Duration},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
uapi::c,
|
uapi::c,
|
||||||
|
|
@ -339,6 +346,9 @@ fn start_compositor2(
|
||||||
node_at_tree: Default::default(),
|
node_at_tree: Default::default(),
|
||||||
position_hint_requests: Default::default(),
|
position_hint_requests: Default::default(),
|
||||||
backend_connector_state_serials: Default::default(),
|
backend_connector_state_serials: Default::default(),
|
||||||
|
head_names: Default::default(),
|
||||||
|
head_managers: Default::default(),
|
||||||
|
head_managers_async: Default::default(),
|
||||||
});
|
});
|
||||||
state.tracker.register(ClientId::from_raw(0));
|
state.tracker.register(ClientId::from_raw(0));
|
||||||
create_dummy_output(&state);
|
create_dummy_output(&state);
|
||||||
|
|
@ -523,6 +533,11 @@ fn start_global_event_handlers(state: &Rc<State>) -> Vec<SpawnedFuture<()>> {
|
||||||
"position hint requests",
|
"position hint requests",
|
||||||
handle_position_hint_requests(state.clone()),
|
handle_position_hint_requests(state.clone()),
|
||||||
),
|
),
|
||||||
|
eng.spawn2(
|
||||||
|
"jay head manager send done",
|
||||||
|
Phase::Layout,
|
||||||
|
handle_jay_head_manager_done(state.clone()),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -602,9 +617,6 @@ fn create_dummy_output(state: &Rc<State>) {
|
||||||
tearing_mode: Cell::new(&TearingMode::Never),
|
tearing_mode: Cell::new(&TearingMode::Never),
|
||||||
brightness: Cell::new(None),
|
brightness: Cell::new(None),
|
||||||
});
|
});
|
||||||
let connector = Rc::new(DummyOutput {
|
|
||||||
id: state.connector_ids.next(),
|
|
||||||
}) as Rc<dyn Connector>;
|
|
||||||
let mode = backend::Mode {
|
let mode = backend::Mode {
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
|
|
@ -622,11 +634,42 @@ fn create_dummy_output(state: &Rc<State>) {
|
||||||
color_space: Default::default(),
|
color_space: Default::default(),
|
||||||
transfer_function: Default::default(),
|
transfer_function: Default::default(),
|
||||||
};
|
};
|
||||||
|
let id = state.connector_ids.next();
|
||||||
|
let connector = Rc::new(DummyOutput { id }) as Rc<dyn Connector>;
|
||||||
|
let name = Rc::new("Dummy".to_string());
|
||||||
|
let head_name = state.head_names.next();
|
||||||
|
let head_state = HeadState {
|
||||||
|
name: RcEq(name.clone()),
|
||||||
|
position: (0, 0),
|
||||||
|
size: (0, 0),
|
||||||
|
active: false,
|
||||||
|
connected: false,
|
||||||
|
transform: Transform::None,
|
||||||
|
scale: Default::default(),
|
||||||
|
wl_output: None,
|
||||||
|
connector_enabled: true,
|
||||||
|
in_compositor_space: false,
|
||||||
|
mode: Default::default(),
|
||||||
|
monitor_info: None,
|
||||||
|
inherent_non_desktop: false,
|
||||||
|
override_non_desktop: None,
|
||||||
|
vrr: false,
|
||||||
|
vrr_mode: VrrMode::Never.to_config(),
|
||||||
|
tearing_enabled: backend_state.tearing,
|
||||||
|
tearing_active: false,
|
||||||
|
tearing_mode: TearingMode::Never.to_config(),
|
||||||
|
format: XRGB8888,
|
||||||
|
color_space: backend_state.color_space,
|
||||||
|
transfer_function: backend_state.transfer_function,
|
||||||
|
supported_formats: Default::default(),
|
||||||
|
brightness: None,
|
||||||
|
};
|
||||||
let connector_data = Rc::new(ConnectorData {
|
let connector_data = Rc::new(ConnectorData {
|
||||||
|
id,
|
||||||
connector,
|
connector,
|
||||||
handler: Cell::new(None),
|
handler: Cell::new(None),
|
||||||
connected: Cell::new(true),
|
connected: Cell::new(true),
|
||||||
name: "Dummy".to_string(),
|
name,
|
||||||
drm_dev: None,
|
drm_dev: None,
|
||||||
async_event: Default::default(),
|
async_event: Default::default(),
|
||||||
damaged: Cell::new(false),
|
damaged: Cell::new(false),
|
||||||
|
|
@ -634,6 +677,7 @@ fn create_dummy_output(state: &Rc<State>) {
|
||||||
needs_vblank_emulation: Cell::new(false),
|
needs_vblank_emulation: Cell::new(false),
|
||||||
damage_intersect: Default::default(),
|
damage_intersect: Default::default(),
|
||||||
state: Cell::new(backend_state),
|
state: Cell::new(backend_state),
|
||||||
|
head_managers: HeadManagers::new(head_name, head_state),
|
||||||
});
|
});
|
||||||
let schedule = Rc::new(OutputSchedule::new(
|
let schedule = Rc::new(OutputSchedule::new(
|
||||||
&state.ring,
|
&state.ring,
|
||||||
|
|
@ -692,6 +736,7 @@ fn create_dummy_output(state: &Rc<State>) {
|
||||||
tray_items: Default::default(),
|
tray_items: Default::default(),
|
||||||
ext_workspace_groups: Default::default(),
|
ext_workspace_groups: Default::default(),
|
||||||
pinned: Default::default(),
|
pinned: Default::default(),
|
||||||
|
tearing: Default::default(),
|
||||||
});
|
});
|
||||||
let dummy_workspace = Rc::new(WorkspaceNode {
|
let dummy_workspace = Rc::new(WorkspaceNode {
|
||||||
id: state.node_ids.next(),
|
id: state.node_ids.next(),
|
||||||
|
|
|
||||||
|
|
@ -1175,7 +1175,7 @@ impl ConfigProxyHandler {
|
||||||
fn handle_connector_name(&self, connector: Connector) -> Result<(), CphError> {
|
fn handle_connector_name(&self, connector: Connector) -> Result<(), CphError> {
|
||||||
let connector = self.get_connector(connector)?;
|
let connector = self.get_connector(connector)?;
|
||||||
self.respond(Response::GetConnectorName {
|
self.respond(Response::GetConnectorName {
|
||||||
name: connector.name.clone(),
|
name: connector.name.deref().clone(),
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -1375,8 +1375,7 @@ impl ConfigProxyHandler {
|
||||||
match connector {
|
match connector {
|
||||||
Some(c) => {
|
Some(c) => {
|
||||||
let connector = self.get_output_node(c)?;
|
let connector = self.get_output_node(c)?;
|
||||||
connector.global.persistent.vrr_mode.set(mode);
|
connector.set_vrr_mode(mode);
|
||||||
connector.update_presentation_type();
|
|
||||||
}
|
}
|
||||||
_ => self.state.default_vrr_mode.set(mode),
|
_ => self.state.default_vrr_mode.set(mode),
|
||||||
}
|
}
|
||||||
|
|
@ -1414,8 +1413,7 @@ impl ConfigProxyHandler {
|
||||||
match connector {
|
match connector {
|
||||||
Some(c) => {
|
Some(c) => {
|
||||||
let connector = self.get_output_node(c)?;
|
let connector = self.get_output_node(c)?;
|
||||||
connector.global.persistent.tearing_mode.set(mode);
|
connector.set_tearing_mode(mode);
|
||||||
connector.update_presentation_type();
|
|
||||||
}
|
}
|
||||||
_ => self.state.default_tearing_mode.set(mode),
|
_ => self.state.default_tearing_mode.set(mode),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ use {
|
||||||
ext_image_copy::ext_image_copy_capture_manager_v1::ExtImageCopyCaptureManagerV1Global,
|
ext_image_copy::ext_image_copy_capture_manager_v1::ExtImageCopyCaptureManagerV1Global,
|
||||||
ext_output_image_capture_source_manager_v1::ExtOutputImageCaptureSourceManagerV1Global,
|
ext_output_image_capture_source_manager_v1::ExtOutputImageCaptureSourceManagerV1Global,
|
||||||
ext_session_lock_manager_v1::ExtSessionLockManagerV1Global,
|
ext_session_lock_manager_v1::ExtSessionLockManagerV1Global,
|
||||||
|
head_management::jay_head_manager_v1::JayHeadManagerV1Global,
|
||||||
ipc::{
|
ipc::{
|
||||||
data_control::{
|
data_control::{
|
||||||
ext_data_control_manager_v1::ExtDataControlManagerV1Global,
|
ext_data_control_manager_v1::ExtDataControlManagerV1Global,
|
||||||
|
|
@ -225,6 +226,7 @@ impl Globals {
|
||||||
add_singleton!(ExtWorkspaceManagerV1Global);
|
add_singleton!(ExtWorkspaceManagerV1Global);
|
||||||
add_singleton!(WpColorManagerV1Global);
|
add_singleton!(WpColorManagerV1Global);
|
||||||
add_singleton!(XdgToplevelTagManagerV1Global);
|
add_singleton!(XdgToplevelTagManagerV1Global);
|
||||||
|
add_singleton!(JayHeadManagerV1Global);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_backend_singletons(&self, backend: &Rc<dyn Backend>) {
|
pub fn add_backend_singletons(&self, backend: &Rc<dyn Backend>) {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ pub mod ext_image_copy;
|
||||||
pub mod ext_output_image_capture_source_manager_v1;
|
pub mod ext_output_image_capture_source_manager_v1;
|
||||||
pub mod ext_session_lock_manager_v1;
|
pub mod ext_session_lock_manager_v1;
|
||||||
pub mod ext_session_lock_v1;
|
pub mod ext_session_lock_v1;
|
||||||
|
pub mod head_management;
|
||||||
pub mod ipc;
|
pub mod ipc;
|
||||||
pub mod jay_client_query;
|
pub mod jay_client_query;
|
||||||
pub mod jay_color_management;
|
pub mod jay_color_management;
|
||||||
|
|
|
||||||
531
src/ifs/head_management.rs
Normal file
531
src/ifs/head_management.rs
Normal file
|
|
@ -0,0 +1,531 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
backend::{
|
||||||
|
BackendColorSpace, BackendTransferFunction, ConnectorId, Mode, MonitorInfo,
|
||||||
|
transaction::BackendConnectorTransactionError,
|
||||||
|
},
|
||||||
|
client::ClientId,
|
||||||
|
format::Format,
|
||||||
|
globals::GlobalName,
|
||||||
|
ifs::head_management::{
|
||||||
|
head_management_macros::HeadExts, jay_head_manager_session_v1::JayHeadManagerSessionV1,
|
||||||
|
jay_head_v1::JayHeadV1,
|
||||||
|
},
|
||||||
|
scale::Scale,
|
||||||
|
state::OutputData,
|
||||||
|
tree::OutputNode,
|
||||||
|
utils::{copyhashmap::CopyHashMap, hash_map_ext::HashMapExt, rc_eq::RcEq},
|
||||||
|
wire::JayHeadManagerSessionV1Id,
|
||||||
|
},
|
||||||
|
jay_config::video::{TearingMode, Transform, VrrMode},
|
||||||
|
std::{
|
||||||
|
cell::{Cell, RefCell},
|
||||||
|
rc::Rc,
|
||||||
|
},
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod head_management_macros;
|
||||||
|
pub mod jay_head_error_v1;
|
||||||
|
mod jay_head_ext;
|
||||||
|
pub mod jay_head_manager_session_v1;
|
||||||
|
pub mod jay_head_manager_v1;
|
||||||
|
mod jay_head_transaction_result_v1;
|
||||||
|
mod jay_head_v1;
|
||||||
|
|
||||||
|
linear_ids!(HeadNames, HeadName, u64);
|
||||||
|
|
||||||
|
struct Head {
|
||||||
|
session: Rc<JayHeadManagerSessionV1>,
|
||||||
|
common: Rc<HeadCommon>,
|
||||||
|
head: Rc<JayHeadV1>,
|
||||||
|
ext: HeadExts,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
enum HeadTransactionError {
|
||||||
|
#[error("The connector {} has been removed", .0)]
|
||||||
|
HeadRemoved(ConnectorId),
|
||||||
|
#[error("The display connected to connector {} has changed", .0)]
|
||||||
|
MonitorChanged(ConnectorId),
|
||||||
|
#[error("The transaction has already failed")]
|
||||||
|
AlreadyFailed,
|
||||||
|
#[error(transparent)]
|
||||||
|
Backend(#[from] BackendConnectorTransactionError),
|
||||||
|
}
|
||||||
|
|
||||||
|
struct HeadCommon {
|
||||||
|
mgr: Rc<HeadMgrCommon>,
|
||||||
|
name: HeadName,
|
||||||
|
id: ConnectorId,
|
||||||
|
removed: Cell<bool>,
|
||||||
|
|
||||||
|
shared: Rc<RefCell<HeadState>>,
|
||||||
|
snapshot_state: RefCell<HeadState>,
|
||||||
|
transaction_state: RefCell<HeadState>,
|
||||||
|
pending: RefCell<Vec<HeadOp>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
pub struct HeadState {
|
||||||
|
pub name: RcEq<String>,
|
||||||
|
pub wl_output: Option<GlobalName>,
|
||||||
|
pub connector_enabled: bool,
|
||||||
|
pub active: bool,
|
||||||
|
pub connected: bool,
|
||||||
|
pub in_compositor_space: bool,
|
||||||
|
pub position: (i32, i32),
|
||||||
|
pub size: (i32, i32),
|
||||||
|
pub mode: Mode,
|
||||||
|
pub transform: Transform,
|
||||||
|
pub scale: Scale,
|
||||||
|
pub monitor_info: Option<RcEq<MonitorInfo>>,
|
||||||
|
pub inherent_non_desktop: bool,
|
||||||
|
pub override_non_desktop: Option<bool>,
|
||||||
|
pub vrr: bool,
|
||||||
|
pub vrr_mode: VrrMode,
|
||||||
|
pub tearing_enabled: bool,
|
||||||
|
pub tearing_active: bool,
|
||||||
|
pub tearing_mode: TearingMode,
|
||||||
|
pub format: &'static Format,
|
||||||
|
pub color_space: BackendColorSpace,
|
||||||
|
pub transfer_function: BackendTransferFunction,
|
||||||
|
pub supported_formats: RcEq<Vec<&'static Format>>,
|
||||||
|
pub brightness: Option<f64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadState {
|
||||||
|
fn update_in_compositor_space(&mut self, wl_output: Option<GlobalName>) {
|
||||||
|
self.in_compositor_space = false;
|
||||||
|
self.wl_output = None;
|
||||||
|
if !self.connector_enabled {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let Some(mi) = &self.monitor_info else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if mi.non_desktop {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if self.override_non_desktop == Some(true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.in_compositor_space = true;
|
||||||
|
self.wl_output = wl_output;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_size(&mut self) {
|
||||||
|
self.size =
|
||||||
|
OutputNode::calculate_extents_(self.mode, self.transform, self.scale, self.position)
|
||||||
|
.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum HeadOp {
|
||||||
|
SetPosition(i32, i32),
|
||||||
|
SetConnectorEnabled(bool),
|
||||||
|
SetTransform(Transform),
|
||||||
|
SetScale(Scale),
|
||||||
|
SetMode(usize),
|
||||||
|
SetNonDesktopOverride(Option<bool>),
|
||||||
|
SetVrrMode(VrrMode),
|
||||||
|
SetTearingMode(TearingMode),
|
||||||
|
SetFormat(&'static Format),
|
||||||
|
SetTransferFunction(BackendTransferFunction),
|
||||||
|
SetColorSpace(BackendColorSpace),
|
||||||
|
SetBrightness(Option<f64>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
|
||||||
|
enum HeadMgrState {
|
||||||
|
#[default]
|
||||||
|
Init,
|
||||||
|
Started,
|
||||||
|
StopScheduled,
|
||||||
|
Stopped,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct HeadMgrCommon {
|
||||||
|
state: Cell<HeadMgrState>,
|
||||||
|
in_transaction: Cell<bool>,
|
||||||
|
transaction_failed: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadCommon {
|
||||||
|
fn assert_removed(&self) -> Result<(), HeadCommonError> {
|
||||||
|
if self.removed.get() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(HeadCommonError::NotYetRemoved)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_in_transaction(&self) -> Result<(), HeadCommonError> {
|
||||||
|
if self.mgr.in_transaction.get() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(HeadCommonError::NotInTransaction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_op(&self, op: HeadOp) -> Result<(), HeadCommonError> {
|
||||||
|
self.assert_in_transaction()?;
|
||||||
|
self.pending.borrow_mut().push(op);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadMgrCommon {
|
||||||
|
fn assert_stopped(&self) -> Result<(), HeadCommonError> {
|
||||||
|
if self.state.get() == HeadMgrState::Stopped {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(HeadCommonError::NotYetStopped)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum HeadCommonError {
|
||||||
|
#[error("Head has not yet been removed")]
|
||||||
|
NotYetRemoved,
|
||||||
|
#[error("Manager is not inside a transaction")]
|
||||||
|
NotInTransaction,
|
||||||
|
#[error("Manager has not yet been stopped")]
|
||||||
|
NotYetStopped,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HeadManagers {
|
||||||
|
name: HeadName,
|
||||||
|
state: Rc<RefCell<HeadState>>,
|
||||||
|
managers: CopyHashMap<(ClientId, JayHeadManagerSessionV1Id), Rc<Head>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! skip_in_transaction {
|
||||||
|
($mgr:expr) => {
|
||||||
|
if $mgr.common.mgr.in_transaction.get() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadManagers {
|
||||||
|
pub fn new(name: HeadName, state: HeadState) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
state: Rc::new(RefCell::new(state)),
|
||||||
|
managers: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_removed(&self) {
|
||||||
|
for head in self.managers.lock().drain_values() {
|
||||||
|
skip_in_transaction!(head);
|
||||||
|
head.session.heads.remove(&self.name);
|
||||||
|
head.head.send_removed();
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_output_connected(&self, output: &OutputData) {
|
||||||
|
let state = &mut *self.state.borrow_mut();
|
||||||
|
state.connected = true;
|
||||||
|
state.monitor_info = Some(RcEq(output.monitor_info.clone()));
|
||||||
|
state.inherent_non_desktop = output.monitor_info.non_desktop;
|
||||||
|
state.update_in_compositor_space(output.node.as_ref().map(|n| n.global.name));
|
||||||
|
if let Some(n) = &output.node {
|
||||||
|
state.position = n.global.pos.get().position();
|
||||||
|
state.size = n.global.pos.get().size();
|
||||||
|
state.mode = n.global.mode.get();
|
||||||
|
state.transform = n.global.persistent.transform.get();
|
||||||
|
state.vrr_mode = n.global.persistent.vrr_mode.get().to_config();
|
||||||
|
state.tearing_mode = n.global.persistent.tearing_mode.get().to_config();
|
||||||
|
}
|
||||||
|
for head in self.managers.lock().values() {
|
||||||
|
skip_in_transaction!(head);
|
||||||
|
if let Some(ext) = &head.ext.connector_info_v1 {
|
||||||
|
ext.send_connected(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
if let Some(ext) = &head.ext.physical_display_info_v1 {
|
||||||
|
ext.send_info(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
if let Some(ext) = &head.ext.mode_info_v1 {
|
||||||
|
ext.send_mode(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
if let Some(ext) = &head.ext.mode_setter_v1 {
|
||||||
|
ext.send_modes(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
if let Some(ext) = &head.ext.compositor_space_info_v1 {
|
||||||
|
ext.send_inside_outside(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
if let Some(ext) = &head.ext.core_info_v1 {
|
||||||
|
ext.send_wl_output(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
if let Some(ext) = &head.ext.non_desktop_info_v1 {
|
||||||
|
ext.send_state(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
if let Some(ext) = &head.ext.vrr_state_v1 {
|
||||||
|
ext.send_state(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
if let Some(ext) = &head.ext.jay_vrr_mode_info_v1 {
|
||||||
|
ext.send_mode(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
if let Some(ext) = &head.ext.jay_tearing_mode_info_v1 {
|
||||||
|
ext.send_mode(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
if let Some(ext) = &head.ext.drm_color_space_setter_v1 {
|
||||||
|
ext.send_supported(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
if let Some(ext) = &head.ext.brightness_info_v1 {
|
||||||
|
ext.send_implied_default_brightness(state);
|
||||||
|
ext.send_brightness(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_output_disconnected(&self) {
|
||||||
|
let state = &mut *self.state.borrow_mut();
|
||||||
|
state.connected = false;
|
||||||
|
state.monitor_info = None;
|
||||||
|
state.update_in_compositor_space(None);
|
||||||
|
for head in self.managers.lock().values() {
|
||||||
|
skip_in_transaction!(head);
|
||||||
|
if let Some(ext) = &head.ext.compositor_space_info_v1 {
|
||||||
|
ext.send_inside_outside(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
if let Some(ext) = &head.ext.connector_info_v1 {
|
||||||
|
ext.send_connected(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
if let Some(ext) = &head.ext.core_info_v1 {
|
||||||
|
ext.send_wl_output(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
if let Some(ext) = &head.ext.physical_display_info_v1 {
|
||||||
|
ext.send_info(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
if let Some(ext) = &head.ext.vrr_state_v1 {
|
||||||
|
ext.send_state(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
if let Some(ext) = &head.ext.drm_color_space_setter_v1 {
|
||||||
|
ext.send_supported(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_position_size_change(&self, node: &OutputNode) {
|
||||||
|
let state = &mut *self.state.borrow_mut();
|
||||||
|
let pos = node.global.pos.get();
|
||||||
|
state.position = pos.position();
|
||||||
|
state.size = pos.size();
|
||||||
|
state.mode = node.global.mode.get();
|
||||||
|
for head in self.managers.lock().values() {
|
||||||
|
skip_in_transaction!(head);
|
||||||
|
if let Some(ext) = &head.ext.compositor_space_info_v1 {
|
||||||
|
ext.send_position(state);
|
||||||
|
ext.send_size(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
if let Some(ext) = &head.ext.mode_info_v1 {
|
||||||
|
ext.send_mode(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_transform_change(&self, transform: Transform) {
|
||||||
|
let state = &mut *self.state.borrow_mut();
|
||||||
|
state.transform = transform;
|
||||||
|
for head in self.managers.lock().values() {
|
||||||
|
skip_in_transaction!(head);
|
||||||
|
if let Some(ext) = &head.ext.compositor_space_info_v1 {
|
||||||
|
ext.send_transform(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_scale_change(&self, scale: Scale) {
|
||||||
|
let state = &mut *self.state.borrow_mut();
|
||||||
|
state.scale = scale;
|
||||||
|
for head in self.managers.lock().values() {
|
||||||
|
skip_in_transaction!(head);
|
||||||
|
if let Some(ext) = &head.ext.compositor_space_info_v1 {
|
||||||
|
ext.send_scale(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_enabled_change(&self, enabled: bool) {
|
||||||
|
let state = &mut *self.state.borrow_mut();
|
||||||
|
state.connector_enabled = enabled;
|
||||||
|
state.update_in_compositor_space(state.wl_output);
|
||||||
|
for head in self.managers.lock().values() {
|
||||||
|
skip_in_transaction!(head);
|
||||||
|
if let Some(ext) = &head.ext.compositor_space_info_v1 {
|
||||||
|
ext.send_enabled(state);
|
||||||
|
ext.send_inside_outside(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_active_change(&self, active: bool) {
|
||||||
|
let state = &mut *self.state.borrow_mut();
|
||||||
|
state.active = active;
|
||||||
|
for head in self.managers.lock().values() {
|
||||||
|
skip_in_transaction!(head);
|
||||||
|
if let Some(ext) = &head.ext.connector_info_v1 {
|
||||||
|
ext.send_active(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_non_desktop_override_changed(&self, overrd: Option<bool>) {
|
||||||
|
let state = &mut *self.state.borrow_mut();
|
||||||
|
state.override_non_desktop = overrd;
|
||||||
|
for head in self.managers.lock().values() {
|
||||||
|
skip_in_transaction!(head);
|
||||||
|
if let Some(ext) = &head.ext.non_desktop_info_v1 {
|
||||||
|
ext.send_state(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_vrr_change(&self, vrr: bool) {
|
||||||
|
let state = &mut *self.state.borrow_mut();
|
||||||
|
state.vrr = vrr;
|
||||||
|
for head in self.managers.lock().values() {
|
||||||
|
skip_in_transaction!(head);
|
||||||
|
if let Some(ext) = &head.ext.vrr_state_v1 {
|
||||||
|
ext.send_state(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_vrr_mode_change(&self, vrr_mode: VrrMode) {
|
||||||
|
let state = &mut *self.state.borrow_mut();
|
||||||
|
state.vrr_mode = vrr_mode;
|
||||||
|
for head in self.managers.lock().values() {
|
||||||
|
skip_in_transaction!(head);
|
||||||
|
if let Some(ext) = &head.ext.jay_vrr_mode_info_v1 {
|
||||||
|
ext.send_mode(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_tearing_enabled_change(&self, enabled: bool) {
|
||||||
|
let state = &mut *self.state.borrow_mut();
|
||||||
|
state.tearing_enabled = enabled;
|
||||||
|
for head in self.managers.lock().values() {
|
||||||
|
skip_in_transaction!(head);
|
||||||
|
if let Some(ext) = &head.ext.tearing_state_v1 {
|
||||||
|
ext.send_enabled(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_tearing_active_change(&self, active: bool) {
|
||||||
|
let state = &mut *self.state.borrow_mut();
|
||||||
|
state.tearing_active = active;
|
||||||
|
for head in self.managers.lock().values() {
|
||||||
|
skip_in_transaction!(head);
|
||||||
|
if let Some(ext) = &head.ext.tearing_state_v1 {
|
||||||
|
ext.send_active(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_tearing_mode_change(&self, tearing_mode: TearingMode) {
|
||||||
|
let state = &mut *self.state.borrow_mut();
|
||||||
|
state.tearing_mode = tearing_mode;
|
||||||
|
for head in self.managers.lock().values() {
|
||||||
|
skip_in_transaction!(head);
|
||||||
|
if let Some(ext) = &head.ext.jay_tearing_mode_info_v1 {
|
||||||
|
ext.send_mode(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_format_change(&self, format: &'static Format) {
|
||||||
|
let state = &mut *self.state.borrow_mut();
|
||||||
|
state.format = format;
|
||||||
|
for head in self.managers.lock().values() {
|
||||||
|
skip_in_transaction!(head);
|
||||||
|
if let Some(ext) = &head.ext.format_info_v1 {
|
||||||
|
ext.send_format(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_colors_change(
|
||||||
|
&self,
|
||||||
|
color_space: BackendColorSpace,
|
||||||
|
transfer_function: BackendTransferFunction,
|
||||||
|
) {
|
||||||
|
let state = &mut *self.state.borrow_mut();
|
||||||
|
state.color_space = color_space;
|
||||||
|
state.transfer_function = transfer_function;
|
||||||
|
for head in self.managers.lock().values() {
|
||||||
|
skip_in_transaction!(head);
|
||||||
|
if let Some(ext) = &head.ext.drm_color_space_info_v1 {
|
||||||
|
ext.send_state(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
if let Some(ext) = &head.ext.brightness_info_v1 {
|
||||||
|
ext.send_implied_default_brightness(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_formats_change(&self, formats: &Rc<Vec<&'static Format>>) {
|
||||||
|
let state = &mut *self.state.borrow_mut();
|
||||||
|
state.supported_formats.0 = formats.clone();
|
||||||
|
for head in self.managers.lock().values() {
|
||||||
|
skip_in_transaction!(head);
|
||||||
|
if let Some(ext) = &head.ext.format_setter_v1 {
|
||||||
|
ext.send_supported_formats(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_brightness_change(&self, brightness: Option<f64>) {
|
||||||
|
let state = &mut *self.state.borrow_mut();
|
||||||
|
state.brightness = brightness;
|
||||||
|
for head in self.managers.lock().values() {
|
||||||
|
skip_in_transaction!(head);
|
||||||
|
if let Some(ext) = &head.ext.brightness_info_v1 {
|
||||||
|
ext.send_brightness(state);
|
||||||
|
head.session.schedule_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
415
src/ifs/head_management/head_management_macros.rs
Normal file
415
src/ifs/head_management/head_management_macros.rs
Normal file
|
|
@ -0,0 +1,415 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
client::ClientError,
|
||||||
|
ifs::head_management::{
|
||||||
|
Head, HeadState,
|
||||||
|
jay_head_manager_session_v1::{JayHeadManagerSessionV1, JayHeadManagerSessionV1Error},
|
||||||
|
jay_head_manager_v1::JayHeadManagerV1,
|
||||||
|
jay_head_v1::JayHeadV1,
|
||||||
|
},
|
||||||
|
object::{ObjectId, Version},
|
||||||
|
state::ConnectorData,
|
||||||
|
utils::clonecell::CloneCell,
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
macro_rules! error_ {
|
||||||
|
($error_name:ident, $($tt:tt)*) => {
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum $error_name {
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientError(Box<crate::client::ClientError>),
|
||||||
|
#[error(transparent)]
|
||||||
|
Common(#[from] super::super::HeadCommonError),
|
||||||
|
$($tt)*
|
||||||
|
}
|
||||||
|
efrom!($error_name, ClientError, crate::client::ClientError);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_head_ext {
|
||||||
|
(
|
||||||
|
$snake:ident,
|
||||||
|
$camel:ident,
|
||||||
|
$macro_name:ident,
|
||||||
|
$mgr_module:ident,
|
||||||
|
$mgr_name:ident,
|
||||||
|
$mgr_id_name:ident,
|
||||||
|
$head_module:ident,
|
||||||
|
$head_name:ident,
|
||||||
|
$head_id_name:ident,
|
||||||
|
$version:expr,
|
||||||
|
$(filter = $filter:ident,)?
|
||||||
|
$(after_announce = $after_announce:ident,)?
|
||||||
|
$(after_transaction = $after_transaction:ident,)?
|
||||||
|
) => {
|
||||||
|
pub(in super::super) struct $mgr_name {
|
||||||
|
pub(in super::super) id: crate::wire::$mgr_id_name,
|
||||||
|
pub(in super::super) client: std::rc::Rc<crate::client::Client>,
|
||||||
|
pub(in super::super) tracker: crate::leaks::Tracker<Self>,
|
||||||
|
pub(in super::super) version: crate::object::Version,
|
||||||
|
pub(in super::super) common: std::rc::Rc<super::super::HeadMgrCommon>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $mgr_name {
|
||||||
|
pub(in super::super) const VERSION: crate::object::Version = crate::object::Version($version);
|
||||||
|
pub(in super::super) const NAME: &str = concat!("jay_head_manager_ext_", stringify!($snake));
|
||||||
|
}
|
||||||
|
|
||||||
|
object_base! {
|
||||||
|
self = $mgr_name;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::object::Object for $mgr_name {}
|
||||||
|
|
||||||
|
simple_add_obj!($mgr_name);
|
||||||
|
|
||||||
|
pub(in super::super) struct $head_name {
|
||||||
|
pub(in super::super) id: crate::wire::$head_id_name,
|
||||||
|
pub(in super::super) client: std::rc::Rc<crate::client::Client>,
|
||||||
|
pub(in super::super) tracker: crate::leaks::Tracker<Self>,
|
||||||
|
pub(in super::super) version: crate::object::Version,
|
||||||
|
pub(in super::super) common: std::rc::Rc<super::super::HeadCommon>,
|
||||||
|
}
|
||||||
|
|
||||||
|
object_base! {
|
||||||
|
self = $head_name;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::object::Object for $head_name {}
|
||||||
|
|
||||||
|
simple_add_obj!($head_name);
|
||||||
|
|
||||||
|
impl $mgr_name {
|
||||||
|
pub(in super::super) fn announce(
|
||||||
|
&self,
|
||||||
|
#[allow(clippy::allow_attributes, unused_variables)]
|
||||||
|
connector: &crate::state::ConnectorData,
|
||||||
|
common: &std::rc::Rc<super::super::HeadCommon>,
|
||||||
|
) -> Result<Option<std::rc::Rc<$head_name>>, crate::client::ClientError> {
|
||||||
|
$(
|
||||||
|
if !self.$filter(connector, common) {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
)?
|
||||||
|
let obj = std::rc::Rc::new($head_name {
|
||||||
|
id: self.client.new_id()?,
|
||||||
|
client: self.client.clone(),
|
||||||
|
tracker: Default::default(),
|
||||||
|
version: self.version,
|
||||||
|
common: common.clone(),
|
||||||
|
});
|
||||||
|
track!(self.client, obj);
|
||||||
|
self.client.add_server_obj(&obj);
|
||||||
|
self.send_head(&obj);
|
||||||
|
Ok(Some(obj))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_head(&self, obj: &$head_name) {
|
||||||
|
self.client.event(crate::wire::$mgr_module::Head {
|
||||||
|
self_id: self.id,
|
||||||
|
head: obj.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $head_name {
|
||||||
|
pub(in super::super) fn after_announce_wrapper(
|
||||||
|
&self,
|
||||||
|
#[allow(clippy::allow_attributes, unused_variables)]
|
||||||
|
shared: &super::super::HeadState,
|
||||||
|
) {
|
||||||
|
$(
|
||||||
|
self.$after_announce(shared);
|
||||||
|
)?
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn after_transaction_wrapper(
|
||||||
|
&self,
|
||||||
|
#[allow(clippy::allow_attributes, unused_variables)]
|
||||||
|
shared: &super::super::HeadState,
|
||||||
|
#[allow(clippy::allow_attributes, unused_variables)]
|
||||||
|
tran: &super::super::HeadState,
|
||||||
|
) {
|
||||||
|
$(
|
||||||
|
self.$after_transaction(shared, tran);
|
||||||
|
)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
macro_rules! declare_extension_type_macro {
|
||||||
|
(
|
||||||
|
($dollar:tt),
|
||||||
|
$snake:ident,
|
||||||
|
$camel:ident,
|
||||||
|
$macro_name:ident,
|
||||||
|
$macro_name_int:ident,
|
||||||
|
$mgr_module:ident,
|
||||||
|
$mgr_name:ident,
|
||||||
|
$mgr_id_name:ident,
|
||||||
|
$mgr_request_handler:ident,
|
||||||
|
$head_module:ident,
|
||||||
|
$head_name:ident,
|
||||||
|
$head_id_name:ident,
|
||||||
|
$head_request_handler:ident,
|
||||||
|
$error_name:ident,
|
||||||
|
) => {
|
||||||
|
macro_rules! $macro_name {
|
||||||
|
(
|
||||||
|
version = $version:expr,
|
||||||
|
$dollar(filter = $filter:ident,)?
|
||||||
|
$dollar(after_announce = $after_announce:ident,)?
|
||||||
|
$dollar(after_transaction = $after_transaction:ident,)?
|
||||||
|
) => {
|
||||||
|
$macro_name_int! {
|
||||||
|
($),
|
||||||
|
version = $version,
|
||||||
|
$dollar(filter = $filter,)?
|
||||||
|
$dollar(after_announce = $after_announce,)?
|
||||||
|
$dollar(after_transaction = $after_transaction,)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! $macro_name_int {
|
||||||
|
(
|
||||||
|
($dollar2:tt),
|
||||||
|
version = $version:expr,
|
||||||
|
$dollar(filter = $filter:ident,)?
|
||||||
|
$dollar(after_announce = $after_announce:ident,)?
|
||||||
|
$dollar(after_transaction = $after_transaction:ident,)?
|
||||||
|
) => {
|
||||||
|
impl_head_ext!(
|
||||||
|
$snake,
|
||||||
|
$camel,
|
||||||
|
$macro_name,
|
||||||
|
$mgr_module,
|
||||||
|
$mgr_name,
|
||||||
|
$mgr_id_name,
|
||||||
|
$head_module,
|
||||||
|
$head_name,
|
||||||
|
$head_id_name,
|
||||||
|
$version,
|
||||||
|
$dollar(filter = $filter,)?
|
||||||
|
$dollar(after_announce = $after_announce,)?
|
||||||
|
$dollar(after_transaction = $after_transaction,)?
|
||||||
|
);
|
||||||
|
|
||||||
|
macro_rules! head_common_req {
|
||||||
|
() => {
|
||||||
|
head_common_req_!($snake);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! mgr_common_req {
|
||||||
|
() => {
|
||||||
|
mgr_common_req_!($snake);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrorName = $error_name;
|
||||||
|
type MgrName = $mgr_name;
|
||||||
|
type HeadName = $head_name;
|
||||||
|
|
||||||
|
macro_rules! error {
|
||||||
|
($dollar2($tt:tt)*) => {
|
||||||
|
error_!($error_name, $dollar2($tt)*);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! mgr_common_req_ {
|
||||||
|
($snake:ident) => {
|
||||||
|
with_builtin_macros::with_eager_expansions! {
|
||||||
|
fn destroy(
|
||||||
|
&self,
|
||||||
|
_req: crate::wire::#{concat_idents!(jay_head_manager_ext_, $snake)}::Destroy,
|
||||||
|
_slf: &Rc<Self>,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
self.common.assert_stopped()?;
|
||||||
|
self.client.remove_obj(self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! head_common_req_ {
|
||||||
|
($snake:ident) => {
|
||||||
|
with_builtin_macros::with_eager_expansions! {
|
||||||
|
fn destroy(
|
||||||
|
&self,
|
||||||
|
_req: crate::wire::#{concat_idents!(jay_head_ext_, $snake)}::Destroy,
|
||||||
|
_slf: &Rc<Self>,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
self.common.assert_removed()?;
|
||||||
|
self.client.remove_obj(self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! declare_extensions {
|
||||||
|
($($snake:ident: $camel:ident,)*) => {
|
||||||
|
#[derive(linearize::Linearize)]
|
||||||
|
pub(super) enum HeadExtension {
|
||||||
|
$($camel,)*
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn send_available_extensions(mgr: &JayHeadManagerV1) {
|
||||||
|
use linearize::Linearize;
|
||||||
|
with_builtin_macros::with_eager_expansions! {
|
||||||
|
$(
|
||||||
|
type $camel = super::jay_head_ext::#{concat_idents!(jay_head_ext_, $snake)}::#{concat_idents!(JayHeadManagerExt, $camel)};
|
||||||
|
mgr.send_extension(
|
||||||
|
HeadExtension::$camel.linearize() as _,
|
||||||
|
$camel::NAME,
|
||||||
|
$camel::VERSION,
|
||||||
|
);
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn announce_head(
|
||||||
|
session: &Rc<JayHeadManagerSessionV1>,
|
||||||
|
head: &Rc<JayHeadV1>,
|
||||||
|
connector: &ConnectorData,
|
||||||
|
) -> Result<Rc<Head>, ClientError> {
|
||||||
|
session.send_head_start(head, connector.head_managers.name);
|
||||||
|
let head = super::Head {
|
||||||
|
session: session.clone(),
|
||||||
|
common: head.common.clone(),
|
||||||
|
head: head.clone(),
|
||||||
|
ext: HeadExts {
|
||||||
|
$(
|
||||||
|
$snake: match session.ext.$snake.get() {
|
||||||
|
Some(f) => f.announce(connector, &head.common)?,
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
)*
|
||||||
|
},
|
||||||
|
};
|
||||||
|
session.send_head_complete();
|
||||||
|
let shared = &*connector.head_managers.state.borrow();
|
||||||
|
$(
|
||||||
|
if let Some(ext) = &head.ext.$snake {
|
||||||
|
ext.after_announce_wrapper(shared);
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
Ok(Rc::new(head))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn bind_extension(session: &JayHeadManagerSessionV1, ext: HeadExtension, name: u32, version: u32, id: ObjectId) -> Result<(), JayHeadManagerSessionV1Error> {
|
||||||
|
match ext {
|
||||||
|
$(
|
||||||
|
HeadExtension::$camel => {
|
||||||
|
if session.ext.$snake.is_some() {
|
||||||
|
return Err(JayHeadManagerSessionV1Error::AlreadyBound(name));
|
||||||
|
}
|
||||||
|
let version = Version(version);
|
||||||
|
with_builtin_macros::with_eager_expansions! {
|
||||||
|
type T = super::jay_head_ext::#{concat_idents!(jay_head_ext_, $snake)}::#{concat_idents!(JayHeadManagerExt, $camel)};
|
||||||
|
if version > T::VERSION {
|
||||||
|
return Err(JayHeadManagerSessionV1Error::UnsupportedVersion(name, version));
|
||||||
|
}
|
||||||
|
let obj = Rc::new(T {
|
||||||
|
id: id.into(),
|
||||||
|
client: session.client.clone(),
|
||||||
|
tracker: Default::default(),
|
||||||
|
version,
|
||||||
|
common: session.common.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
track!(session.client, obj);
|
||||||
|
session.client.add_client_obj(&obj)?;
|
||||||
|
session.ext.$snake.set(Some(obj));
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
with_builtin_macros::with_eager_expansions! {
|
||||||
|
#[derive(Default)]
|
||||||
|
pub(super) struct MgrExts {
|
||||||
|
$(
|
||||||
|
pub(super) $snake: CloneCell<Option<Rc<super::jay_head_ext::#{concat_idents!(jay_head_ext_, $snake)}::#{concat_idents!(JayHeadManagerExt, $camel)}>>>,
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct HeadExts {
|
||||||
|
$(
|
||||||
|
pub(super) $snake: Option<Rc<super::jay_head_ext::#{concat_idents!(jay_head_ext_, $snake)}::#{concat_idents!(JayHeadExt, $camel)}>>,
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadExts {
|
||||||
|
pub(super) fn after_transaction(&self, shared: &HeadState, tran: &HeadState) {
|
||||||
|
$(
|
||||||
|
if let Some(ext) = &self.$snake {
|
||||||
|
ext.after_transaction_wrapper(shared, tran);
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
with_builtin_macros::with_eager_expansions! {
|
||||||
|
$(
|
||||||
|
declare_extension_type_macro!(
|
||||||
|
($),
|
||||||
|
$snake,
|
||||||
|
$camel,
|
||||||
|
#{concat_idents!(impl_, $snake)},
|
||||||
|
#{concat_idents!(impl_, $snake, _int)},
|
||||||
|
#{concat_idents!(jay_head_manager_ext_, $snake)},
|
||||||
|
#{concat_idents!(JayHeadManagerExt, $camel)},
|
||||||
|
#{concat_idents!(JayHeadManagerExt, $camel, Id)},
|
||||||
|
#{concat_idents!(JayHeadManagerExt, $camel, RequestHandler)},
|
||||||
|
#{concat_idents!(jay_head_ext_, $snake)},
|
||||||
|
#{concat_idents!(JayHeadExt, $camel)},
|
||||||
|
#{concat_idents!(JayHeadExt, $camel, Id)},
|
||||||
|
#{concat_idents!(JayHeadExt, $camel, RequestHandler)},
|
||||||
|
#{concat_idents!(JayHeadExt, $camel, Error)},
|
||||||
|
);
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_extensions! {
|
||||||
|
core_info_v1: CoreInfoV1,
|
||||||
|
compositor_space_info_v1: CompositorSpaceInfoV1,
|
||||||
|
compositor_space_positioner_v1: CompositorSpacePositionerV1,
|
||||||
|
compositor_space_transformer_v1: CompositorSpaceTransformerV1,
|
||||||
|
compositor_space_scaler_v1: CompositorSpaceScalerV1,
|
||||||
|
compositor_space_enabler_v1: CompositorSpaceEnablerV1,
|
||||||
|
connector_info_v1: ConnectorInfoV1,
|
||||||
|
mode_info_v1: ModeInfoV1,
|
||||||
|
mode_setter_v1: ModeSetterV1,
|
||||||
|
physical_display_info_v1: PhysicalDisplayInfoV1,
|
||||||
|
non_desktop_info_v1: NonDesktopInfoV1,
|
||||||
|
vrr_state_v1: VrrStateV1,
|
||||||
|
tearing_state_v1: TearingStateV1,
|
||||||
|
format_info_v1: FormatInfoV1,
|
||||||
|
drm_color_space_info_v1: DrmColorSpaceInfoV1,
|
||||||
|
non_desktop_override_v1: NonDesktopOverrideV1,
|
||||||
|
jay_vrr_mode_info_v1: JayVrrModeInfoV1,
|
||||||
|
jay_tearing_mode_info_v1: JayTearingModeInfoV1,
|
||||||
|
jay_vrr_mode_setter_v1: JayVrrModeSetterV1,
|
||||||
|
jay_tearing_mode_setter_v1: JayTearingModeSetterV1,
|
||||||
|
format_setter_v1: FormatSetterV1,
|
||||||
|
drm_color_space_setter_v1: DrmColorSpaceSetterV1,
|
||||||
|
brightness_info_v1: BrightnessInfoV1,
|
||||||
|
brightness_setter_v1: BrightnessSetterV1,
|
||||||
|
}
|
||||||
77
src/ifs/head_management/jay_head_error_v1.rs
Normal file
77
src/ifs/head_management/jay_head_error_v1.rs
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
client::{Client, ClientError},
|
||||||
|
ifs::head_management::HeadTransactionError,
|
||||||
|
leaks::Tracker,
|
||||||
|
object::{Object, Version},
|
||||||
|
utils::errorfmt::ErrorFmt,
|
||||||
|
wire::{JayHeadErrorV1Id, jay_head_error_v1::*},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct JayHeadErrorV1 {
|
||||||
|
pub(super) id: JayHeadErrorV1Id,
|
||||||
|
pub(super) client: Rc<Client>,
|
||||||
|
pub(super) tracker: Tracker<Self>,
|
||||||
|
pub(super) version: Version,
|
||||||
|
pub(super) error: Rc<HeadTransactionError>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadErrorV1 {
|
||||||
|
pub fn send(&self) {
|
||||||
|
let msg = ErrorFmt(&*self.error).to_string();
|
||||||
|
self.send_message(&msg);
|
||||||
|
match &*self.error {
|
||||||
|
HeadTransactionError::HeadRemoved(_) | HeadTransactionError::MonitorChanged(_) => {
|
||||||
|
self.send_out_of_date();
|
||||||
|
}
|
||||||
|
HeadTransactionError::AlreadyFailed => {
|
||||||
|
self.send_already_failed();
|
||||||
|
}
|
||||||
|
HeadTransactionError::Backend(_) => {}
|
||||||
|
}
|
||||||
|
self.client.event(Done { self_id: self.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_message(&self, message: &str) {
|
||||||
|
self.client.event(Message {
|
||||||
|
self_id: self.id,
|
||||||
|
msg: message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_out_of_date(&self) {
|
||||||
|
self.client.event(OutOfDate { self_id: self.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_already_failed(&self) {
|
||||||
|
self.client.event(AlreadyFailed { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadErrorV1RequestHandler for JayHeadErrorV1 {
|
||||||
|
type Error = JayHeadErrorV1Error;
|
||||||
|
|
||||||
|
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.client.remove_obj(self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_base! {
|
||||||
|
self = JayHeadErrorV1;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for JayHeadErrorV1 {}
|
||||||
|
|
||||||
|
dedicated_add_obj!(JayHeadErrorV1, JayHeadErrorV1Id, jay_head_errors);
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum JayHeadErrorV1Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientError(Box<ClientError>),
|
||||||
|
}
|
||||||
|
efrom!(JayHeadErrorV1Error, ClientError);
|
||||||
24
src/ifs/head_management/jay_head_ext.rs
Normal file
24
src/ifs/head_management/jay_head_ext.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
pub(super) mod jay_head_ext_brightness_info_v1;
|
||||||
|
pub(super) mod jay_head_ext_brightness_setter_v1;
|
||||||
|
pub(super) mod jay_head_ext_compositor_space_enabler_v1;
|
||||||
|
pub(super) mod jay_head_ext_compositor_space_info_v1;
|
||||||
|
pub(super) mod jay_head_ext_compositor_space_positioner_v1;
|
||||||
|
pub(super) mod jay_head_ext_compositor_space_scaler_v1;
|
||||||
|
pub(super) mod jay_head_ext_compositor_space_transformer_v1;
|
||||||
|
pub(super) mod jay_head_ext_connector_info_v1;
|
||||||
|
pub(super) mod jay_head_ext_core_info_v1;
|
||||||
|
pub(super) mod jay_head_ext_drm_color_space_info_v1;
|
||||||
|
pub(super) mod jay_head_ext_drm_color_space_setter_v1;
|
||||||
|
pub(super) mod jay_head_ext_format_info_v1;
|
||||||
|
pub(super) mod jay_head_ext_format_setter_v1;
|
||||||
|
pub(super) mod jay_head_ext_jay_tearing_mode_info_v1;
|
||||||
|
pub(super) mod jay_head_ext_jay_tearing_mode_setter_v1;
|
||||||
|
pub(super) mod jay_head_ext_jay_vrr_mode_info_v1;
|
||||||
|
pub(super) mod jay_head_ext_jay_vrr_mode_setter_v1;
|
||||||
|
pub(super) mod jay_head_ext_mode_info_v1;
|
||||||
|
pub(super) mod jay_head_ext_mode_setter_v1;
|
||||||
|
pub(super) mod jay_head_ext_non_desktop_info_v1;
|
||||||
|
pub(super) mod jay_head_ext_non_desktop_override_v1;
|
||||||
|
pub(super) mod jay_head_ext_physical_display_info_v1;
|
||||||
|
pub(super) mod jay_head_ext_tearing_state_v1;
|
||||||
|
pub(super) mod jay_head_ext_vrr_state_v1;
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
backend::BackendTransferFunction,
|
||||||
|
cmm::cmm_luminance::Luminance,
|
||||||
|
ifs::head_management::HeadState,
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_brightness_info_v1::{
|
||||||
|
Brightness, DefaultBrightness, ImpliedDefaultBrightness,
|
||||||
|
JayHeadExtBrightnessInfoV1RequestHandler,
|
||||||
|
},
|
||||||
|
jay_head_manager_ext_brightness_info_v1::JayHeadManagerExtBrightnessInfoV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_brightness_info_v1! {
|
||||||
|
version = 1,
|
||||||
|
after_announce = after_announce,
|
||||||
|
after_transaction = after_transaction,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadName {
|
||||||
|
fn after_announce(&self, shared: &HeadState) {
|
||||||
|
self.send_implied_default_brightness(shared);
|
||||||
|
self.send_brightness(shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_transaction(&self, shared: &HeadState, tran: &HeadState) {
|
||||||
|
if shared.transfer_function != tran.transfer_function {
|
||||||
|
self.send_implied_default_brightness(shared);
|
||||||
|
}
|
||||||
|
if shared.brightness != tran.brightness {
|
||||||
|
self.send_brightness(shared);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_implied_default_brightness(&self, shared: &HeadState) {
|
||||||
|
let lux = match shared.transfer_function {
|
||||||
|
BackendTransferFunction::Default => shared
|
||||||
|
.monitor_info
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|m| m.luminance.as_ref())
|
||||||
|
.map(|l| l.max)
|
||||||
|
.unwrap_or(Luminance::SRGB.white.0),
|
||||||
|
BackendTransferFunction::Pq => Luminance::ST2084_PQ.white.0,
|
||||||
|
};
|
||||||
|
self.client.event(ImpliedDefaultBrightness {
|
||||||
|
self_id: self.id,
|
||||||
|
lux: (lux as f32).to_bits(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_brightness(&self, shared: &HeadState) {
|
||||||
|
match shared.brightness {
|
||||||
|
None => self.client.event(DefaultBrightness { self_id: self.id }),
|
||||||
|
Some(b) => self.client.event(Brightness {
|
||||||
|
self_id: self.id,
|
||||||
|
lux: (b as f32).to_bits(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtBrightnessInfoV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtBrightnessInfoV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
error!();
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::head_management::HeadOp,
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_brightness_setter_v1::{
|
||||||
|
JayHeadExtBrightnessSetterV1RequestHandler, SetBrightness, UnsetBrightness,
|
||||||
|
},
|
||||||
|
jay_head_manager_ext_brightness_setter_v1::JayHeadManagerExtBrightnessSetterV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_brightness_setter_v1! {
|
||||||
|
version = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtBrightnessSetterV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtBrightnessSetterV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
|
||||||
|
fn unset_brightness(&self, _req: UnsetBrightness, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.common.push_op(HeadOp::SetBrightness(None))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_brightness(&self, req: SetBrightness, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.common
|
||||||
|
.push_op(HeadOp::SetBrightness(Some(f32::from_bits(req.lux) as f64)))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error!();
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
backend::CONCAP_CONNECTOR,
|
||||||
|
ifs::head_management::{HeadCommon, HeadOp},
|
||||||
|
state::ConnectorData,
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_compositor_space_enabler_v1::{
|
||||||
|
Disable, Enable, JayHeadExtCompositorSpaceEnablerV1RequestHandler,
|
||||||
|
},
|
||||||
|
jay_head_manager_ext_compositor_space_enabler_v1::JayHeadManagerExtCompositorSpaceEnablerV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_compositor_space_enabler_v1! {
|
||||||
|
version = 1,
|
||||||
|
filter = filter,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MgrName {
|
||||||
|
fn filter(&self, connector: &ConnectorData, _common: &Rc<HeadCommon>) -> bool {
|
||||||
|
connector.connector.caps().contains(CONCAP_CONNECTOR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtCompositorSpaceEnablerV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtCompositorSpaceEnablerV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
|
||||||
|
fn enable(&self, _req: Enable, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.common.push_op(HeadOp::SetConnectorEnabled(true))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn disable(&self, _req: Disable, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.common.push_op(HeadOp::SetConnectorEnabled(false))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error!();
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::head_management::HeadState,
|
||||||
|
utils::transform_ext::TransformExt,
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_compositor_space_info_v1::{
|
||||||
|
Disabled, Enabled, Inside, JayHeadExtCompositorSpaceInfoV1RequestHandler, Outside,
|
||||||
|
Position, Scaling, Size, Transform,
|
||||||
|
},
|
||||||
|
jay_head_manager_ext_compositor_space_info_v1::JayHeadManagerExtCompositorSpaceInfoV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_compositor_space_info_v1! {
|
||||||
|
version = 1,
|
||||||
|
after_announce = after_announce,
|
||||||
|
after_transaction = after_transaction,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadName {
|
||||||
|
fn after_announce(&self, shared: &HeadState) {
|
||||||
|
self.send_enabled(shared);
|
||||||
|
self.send_inside_outside(shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_transaction(&self, shared: &HeadState, tran: &HeadState) {
|
||||||
|
if shared.connector_enabled != tran.connector_enabled {
|
||||||
|
self.send_enabled(shared);
|
||||||
|
}
|
||||||
|
if shared.in_compositor_space != tran.in_compositor_space {
|
||||||
|
self.send_inside_outside(shared);
|
||||||
|
} else if shared.in_compositor_space {
|
||||||
|
if shared.position != tran.position {
|
||||||
|
self.send_position(shared);
|
||||||
|
}
|
||||||
|
if shared.size != tran.size {
|
||||||
|
self.send_size(shared);
|
||||||
|
}
|
||||||
|
if shared.transform != tran.transform {
|
||||||
|
self.send_transform(shared);
|
||||||
|
}
|
||||||
|
if shared.scale != tran.scale {
|
||||||
|
self.send_scale(shared);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_inside_outside(&self, state: &HeadState) {
|
||||||
|
if state.in_compositor_space {
|
||||||
|
self.client.event(Inside { self_id: self.id });
|
||||||
|
self.send_position(state);
|
||||||
|
self.send_size(state);
|
||||||
|
self.send_transform(state);
|
||||||
|
self.send_scale(state);
|
||||||
|
} else {
|
||||||
|
self.client.event(Outside { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_enabled(&self, state: &HeadState) {
|
||||||
|
if state.connector_enabled {
|
||||||
|
self.client.event(Enabled { self_id: self.id });
|
||||||
|
} else {
|
||||||
|
self.client.event(Disabled { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_position(&self, state: &HeadState) {
|
||||||
|
self.client.event(Position {
|
||||||
|
self_id: self.id,
|
||||||
|
x: state.position.0,
|
||||||
|
y: state.position.1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_size(&self, state: &HeadState) {
|
||||||
|
self.client.event(Size {
|
||||||
|
self_id: self.id,
|
||||||
|
width: state.size.0,
|
||||||
|
height: state.size.1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_transform(&self, state: &HeadState) {
|
||||||
|
self.client.event(Transform {
|
||||||
|
self_id: self.id,
|
||||||
|
transform: state.transform.to_wl() as _,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_scale(&self, state: &HeadState) {
|
||||||
|
self.client.event(Scaling {
|
||||||
|
self_id: self.id,
|
||||||
|
scaling: state.scale.to_wl(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtCompositorSpaceInfoV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtCompositorSpaceInfoV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
error!();
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
compositor::MAX_EXTENTS,
|
||||||
|
ifs::head_management::{HeadOp, HeadState},
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_compositor_space_positioner_v1::{
|
||||||
|
JayHeadExtCompositorSpacePositionerV1RequestHandler, Range, SetPosition,
|
||||||
|
},
|
||||||
|
jay_head_manager_ext_compositor_space_positioner_v1::JayHeadManagerExtCompositorSpacePositionerV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_compositor_space_positioner_v1! {
|
||||||
|
version = 1,
|
||||||
|
after_announce = after_announce,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadName {
|
||||||
|
fn after_announce(&self, _shared: &HeadState) {
|
||||||
|
self.send_range();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_range(&self) {
|
||||||
|
self.client.event(Range {
|
||||||
|
self_id: self.id,
|
||||||
|
x_min: 0,
|
||||||
|
y_min: 0,
|
||||||
|
x_max: MAX_EXTENTS,
|
||||||
|
y_max: MAX_EXTENTS,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtCompositorSpacePositionerV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtCompositorSpacePositionerV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
|
||||||
|
fn set_position(&self, req: SetPosition, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.common.assert_in_transaction()?;
|
||||||
|
if req.x < 0 || req.x > MAX_EXTENTS || req.y < 0 || req.y > MAX_EXTENTS {
|
||||||
|
return Err(JayHeadExtCompositorSpacePositionerV1Error::PositionOutOfBounds);
|
||||||
|
}
|
||||||
|
self.common.push_op(HeadOp::SetPosition(req.x, req.y))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error! {
|
||||||
|
#[error("The position is out of bounds")]
|
||||||
|
PositionOutOfBounds,
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::head_management::{HeadOp, HeadState},
|
||||||
|
scale::Scale,
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_compositor_space_scaler_v1::{
|
||||||
|
JayHeadExtCompositorSpaceScalerV1RequestHandler, Range, SetScale,
|
||||||
|
},
|
||||||
|
jay_head_manager_ext_compositor_space_scaler_v1::JayHeadManagerExtCompositorSpaceScalerV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_compositor_space_scaler_v1! {
|
||||||
|
version = 1,
|
||||||
|
after_announce = after_announce,
|
||||||
|
}
|
||||||
|
|
||||||
|
const MIN_SCALE: Scale = Scale::from_wl(60);
|
||||||
|
const MAX_SCALE: Scale = Scale::from_int(16);
|
||||||
|
|
||||||
|
impl HeadName {
|
||||||
|
fn after_announce(&self, _shared: &HeadState) {
|
||||||
|
self.send_range(MIN_SCALE, MAX_SCALE);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_range(&self, min: Scale, max: Scale) {
|
||||||
|
self.client.event(Range {
|
||||||
|
self_id: self.id,
|
||||||
|
min: min.to_wl(),
|
||||||
|
max: max.to_wl(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtCompositorSpaceScalerV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtCompositorSpaceScalerV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
|
||||||
|
fn set_scale(&self, req: SetScale, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.common.assert_in_transaction()?;
|
||||||
|
let scale = Scale::from_wl(req.scale);
|
||||||
|
if scale < MIN_SCALE || scale > MAX_SCALE {
|
||||||
|
return Err(JayHeadExtCompositorSpaceScalerV1Error::ScaleOutOfBounds);
|
||||||
|
}
|
||||||
|
self.common.push_op(HeadOp::SetScale(scale))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error! {
|
||||||
|
#[error("The scale is out of bounds")]
|
||||||
|
ScaleOutOfBounds,
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::head_management::{HeadOp, HeadState},
|
||||||
|
utils::transform_ext::TransformExt,
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_compositor_space_transformer_v1::{
|
||||||
|
JayHeadExtCompositorSpaceTransformerV1RequestHandler, SetTransform,
|
||||||
|
SupportedTransform,
|
||||||
|
},
|
||||||
|
jay_head_manager_ext_compositor_space_transformer_v1::JayHeadManagerExtCompositorSpaceTransformerV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
jay_config::video::Transform,
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_compositor_space_transformer_v1! {
|
||||||
|
version = 1,
|
||||||
|
after_announce = after_announce,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadName {
|
||||||
|
fn after_announce(&self, _shared: &HeadState) {
|
||||||
|
self.send_supported_transform(Transform::None);
|
||||||
|
self.send_supported_transform(Transform::Rotate90);
|
||||||
|
self.send_supported_transform(Transform::Rotate180);
|
||||||
|
self.send_supported_transform(Transform::Rotate270);
|
||||||
|
self.send_supported_transform(Transform::Flip);
|
||||||
|
self.send_supported_transform(Transform::FlipRotate90);
|
||||||
|
self.send_supported_transform(Transform::FlipRotate180);
|
||||||
|
self.send_supported_transform(Transform::FlipRotate270);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_supported_transform(&self, transform: Transform) {
|
||||||
|
self.client.event(SupportedTransform {
|
||||||
|
self_id: self.id,
|
||||||
|
transform: transform.to_wl() as _,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtCompositorSpaceTransformerV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtCompositorSpaceTransformerV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
|
||||||
|
fn set_transform(&self, req: SetTransform, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.common.assert_in_transaction()?;
|
||||||
|
let Some(transform) = Transform::from_wl(req.transform as _) else {
|
||||||
|
return Err(ErrorName::UnknownTransform(req.transform));
|
||||||
|
};
|
||||||
|
self.common.push_op(HeadOp::SetTransform(transform))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error! {
|
||||||
|
#[error("Unknown transform {0}")]
|
||||||
|
UnknownTransform(u32),
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
backend::CONCAP_CONNECTOR,
|
||||||
|
ifs::head_management::{HeadCommon, HeadState},
|
||||||
|
state::ConnectorData,
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_connector_info_v1::{
|
||||||
|
Active, Connected, Disconnected, Inactive, JayHeadExtConnectorInfoV1RequestHandler,
|
||||||
|
},
|
||||||
|
jay_head_manager_ext_connector_info_v1::JayHeadManagerExtConnectorInfoV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_connector_info_v1! {
|
||||||
|
version = 1,
|
||||||
|
filter = filter,
|
||||||
|
after_announce = after_announce,
|
||||||
|
after_transaction = after_transaction,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MgrName {
|
||||||
|
fn filter(&self, connector: &ConnectorData, _common: &Rc<HeadCommon>) -> bool {
|
||||||
|
connector.connector.caps().contains(CONCAP_CONNECTOR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadName {
|
||||||
|
fn after_announce(&self, shared: &HeadState) {
|
||||||
|
self.send_connected(shared);
|
||||||
|
self.send_active(shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_transaction(&self, shared: &HeadState, tran: &HeadState) {
|
||||||
|
if shared.connected != tran.connected {
|
||||||
|
self.send_connected(shared);
|
||||||
|
}
|
||||||
|
if shared.active != tran.active {
|
||||||
|
self.send_active(shared);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_connected(&self, state: &HeadState) {
|
||||||
|
if state.connected {
|
||||||
|
self.client.event(Connected { self_id: self.id });
|
||||||
|
} else {
|
||||||
|
self.client.event(Disconnected { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_active(&self, state: &HeadState) {
|
||||||
|
if state.active {
|
||||||
|
self.client.event(Active { self_id: self.id });
|
||||||
|
} else {
|
||||||
|
self.client.event(Inactive { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtConnectorInfoV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtConnectorInfoV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
error!();
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::head_management::HeadState,
|
||||||
|
wire::{jay_head_ext_core_info_v1::*, jay_head_manager_ext_core_info_v1::*},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_core_info_v1! {
|
||||||
|
version = 1,
|
||||||
|
after_announce = after_announce,
|
||||||
|
after_transaction = after_transaction,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadName {
|
||||||
|
fn after_announce(&self, shared: &HeadState) {
|
||||||
|
self.send_name(shared);
|
||||||
|
self.send_wl_output(shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_transaction(&self, shared: &HeadState, tran: &HeadState) {
|
||||||
|
if shared.wl_output != tran.wl_output {
|
||||||
|
self.send_wl_output(shared);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_name(&self, state: &HeadState) {
|
||||||
|
self.client.event(Name {
|
||||||
|
self_id: self.id,
|
||||||
|
name: Some(&**state.name),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_wl_output(&self, state: &HeadState) {
|
||||||
|
match state.wl_output {
|
||||||
|
None => {
|
||||||
|
self.client.event(NoWlOutput { self_id: self.id });
|
||||||
|
}
|
||||||
|
Some(name) => {
|
||||||
|
self.client.event(WlOutput {
|
||||||
|
self_id: self.id,
|
||||||
|
global_name: name.raw(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtCoreInfoV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtCoreInfoV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
error!();
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
backend::CONCAP_CONNECTOR,
|
||||||
|
ifs::head_management::{HeadCommon, HeadState},
|
||||||
|
state::ConnectorData,
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_drm_color_space_info_v1::{
|
||||||
|
Colorimetry, HdmiEotf, JayHeadExtDrmColorSpaceInfoV1RequestHandler,
|
||||||
|
},
|
||||||
|
jay_head_manager_ext_drm_color_space_info_v1::JayHeadManagerExtDrmColorSpaceInfoV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_drm_color_space_info_v1! {
|
||||||
|
version = 1,
|
||||||
|
filter = filter,
|
||||||
|
after_announce = after_announce,
|
||||||
|
after_transaction = after_transaction,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MgrName {
|
||||||
|
fn filter(&self, connector: &ConnectorData, _common: &Rc<HeadCommon>) -> bool {
|
||||||
|
connector.connector.caps().contains(CONCAP_CONNECTOR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadName {
|
||||||
|
fn after_announce(&self, shared: &HeadState) {
|
||||||
|
self.send_state(shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_transaction(&self, shared: &HeadState, tran: &HeadState) {
|
||||||
|
if (shared.color_space, shared.transfer_function)
|
||||||
|
!= (tran.color_space, tran.transfer_function)
|
||||||
|
{
|
||||||
|
self.send_state(shared);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_state(&self, state: &HeadState) {
|
||||||
|
self.client.event(HdmiEotf {
|
||||||
|
self_id: self.id,
|
||||||
|
eotf: state.transfer_function.to_drm() as u32,
|
||||||
|
});
|
||||||
|
self.client.event(Colorimetry {
|
||||||
|
self_id: self.id,
|
||||||
|
colorimetry: state.color_space.to_drm() as u32,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtDrmColorSpaceInfoV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtDrmColorSpaceInfoV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
error!();
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
backend::{BackendColorSpace, BackendTransferFunction},
|
||||||
|
ifs::head_management::{HeadOp, HeadState},
|
||||||
|
video::drm::{
|
||||||
|
DRM_MODE_COLORIMETRY_BT2020_RGB, DRM_MODE_COLORIMETRY_DEFAULT, HDMI_EOTF_SMPTE_ST2084,
|
||||||
|
HDMI_EOTF_TRADITIONAL_GAMMA_SDR,
|
||||||
|
},
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_drm_color_space_setter_v1::{
|
||||||
|
JayHeadExtDrmColorSpaceSetterV1RequestHandler, Reset, SetColorimetry, SetHdmiEotf,
|
||||||
|
SupportedColorimetry, SupportedHdmiEotf,
|
||||||
|
},
|
||||||
|
jay_head_manager_ext_drm_color_space_setter_v1::JayHeadManagerExtDrmColorSpaceSetterV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
isnt::std_1::primitive::IsntSlice2Ext,
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_drm_color_space_setter_v1! {
|
||||||
|
version = 1,
|
||||||
|
after_announce = after_announce,
|
||||||
|
after_transaction = after_transaction,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadName {
|
||||||
|
fn after_announce(&self, shared: &HeadState) {
|
||||||
|
self.send_supported(shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_transaction(&self, shared: &HeadState, tran: &HeadState) {
|
||||||
|
if shared.monitor_info != tran.monitor_info {
|
||||||
|
self.send_supported(shared);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_supported(&self, state: &HeadState) {
|
||||||
|
self.client.event(Reset { self_id: self.id });
|
||||||
|
let Some(mi) = &state.monitor_info else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
self.send_supported_eotf(HDMI_EOTF_TRADITIONAL_GAMMA_SDR);
|
||||||
|
for tf in &mi.transfer_functions {
|
||||||
|
self.send_supported_eotf(tf.to_drm());
|
||||||
|
}
|
||||||
|
self.send_supported_colorimetry(DRM_MODE_COLORIMETRY_DEFAULT);
|
||||||
|
for cs in &mi.color_spaces {
|
||||||
|
self.send_supported_colorimetry(cs.to_drm());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_supported_eotf(&self, eotf: u8) {
|
||||||
|
self.client.event(SupportedHdmiEotf {
|
||||||
|
self_id: self.id,
|
||||||
|
eotf: eotf as u32,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_supported_colorimetry(&self, colorimetry: u64) {
|
||||||
|
self.client.event(SupportedColorimetry {
|
||||||
|
self_id: self.id,
|
||||||
|
colorimetry: colorimetry as u32,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtDrmColorSpaceSetterV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtDrmColorSpaceSetterV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
|
||||||
|
fn set_hdmi_eotf(&self, req: SetHdmiEotf, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
const DEFAULT: u32 = HDMI_EOTF_TRADITIONAL_GAMMA_SDR as u32;
|
||||||
|
const PQ: u32 = HDMI_EOTF_SMPTE_ST2084 as u32;
|
||||||
|
let eotf = match req.eotf {
|
||||||
|
DEFAULT => BackendTransferFunction::Default,
|
||||||
|
PQ => BackendTransferFunction::Pq,
|
||||||
|
_ => return Err(ErrorName::UnknownEotf(req.eotf)),
|
||||||
|
};
|
||||||
|
if eotf != BackendTransferFunction::Default {
|
||||||
|
let state = &*self.common.transaction_state.borrow();
|
||||||
|
let Some(mi) = &state.monitor_info else {
|
||||||
|
return Err(ErrorName::UnsupportedEotf(req.eotf));
|
||||||
|
};
|
||||||
|
if mi.transfer_functions.not_contains(&eotf) {
|
||||||
|
return Err(ErrorName::UnsupportedEotf(req.eotf));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.common.push_op(HeadOp::SetTransferFunction(eotf))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_colorimetry(&self, req: SetColorimetry, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let cs = match req.colorimetry as u64 {
|
||||||
|
DRM_MODE_COLORIMETRY_DEFAULT => BackendColorSpace::Default,
|
||||||
|
DRM_MODE_COLORIMETRY_BT2020_RGB => BackendColorSpace::Bt2020,
|
||||||
|
_ => return Err(ErrorName::UnknownColorimetry(req.colorimetry)),
|
||||||
|
};
|
||||||
|
if cs != BackendColorSpace::Default {
|
||||||
|
let state = &*self.common.transaction_state.borrow();
|
||||||
|
let Some(mi) = &state.monitor_info else {
|
||||||
|
return Err(ErrorName::UnsupportedColorimetry(req.colorimetry));
|
||||||
|
};
|
||||||
|
if mi.color_spaces.not_contains(&cs) {
|
||||||
|
return Err(ErrorName::UnsupportedColorimetry(req.colorimetry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.common.push_op(HeadOp::SetColorSpace(cs))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error! {
|
||||||
|
#[error("Unknown EOTF {0}")]
|
||||||
|
UnknownEotf(u32),
|
||||||
|
#[error("Unknown colorimetry {0}")]
|
||||||
|
UnknownColorimetry(u32),
|
||||||
|
#[error("Unsupported EOTF {0}")]
|
||||||
|
UnsupportedEotf(u32),
|
||||||
|
#[error("Unsupported colorimetry {0}")]
|
||||||
|
UnsupportedColorimetry(u32),
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::head_management::HeadState,
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_format_info_v1::{Format, JayHeadExtFormatInfoV1RequestHandler},
|
||||||
|
jay_head_manager_ext_format_info_v1::JayHeadManagerExtFormatInfoV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_format_info_v1! {
|
||||||
|
version = 1,
|
||||||
|
after_announce = after_announce,
|
||||||
|
after_transaction = after_transaction,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadName {
|
||||||
|
fn after_announce(&self, shared: &HeadState) {
|
||||||
|
self.send_format(shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_transaction(&self, shared: &HeadState, tran: &HeadState) {
|
||||||
|
if shared.format != tran.format {
|
||||||
|
self.send_format(shared);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_format(&self, state: &HeadState) {
|
||||||
|
self.client.event(Format {
|
||||||
|
self_id: self.id,
|
||||||
|
format: state.format.drm,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtFormatInfoV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtFormatInfoV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
error!();
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
format::formats,
|
||||||
|
ifs::head_management::{HeadOp, HeadState},
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_format_setter_v1::{
|
||||||
|
JayHeadExtFormatSetterV1RequestHandler, Reset, SetFormat, SupportedFormat,
|
||||||
|
},
|
||||||
|
jay_head_manager_ext_format_setter_v1::JayHeadManagerExtFormatSetterV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
isnt::std_1::primitive::IsntSlice2Ext,
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_format_setter_v1! {
|
||||||
|
version = 1,
|
||||||
|
after_announce = after_announce,
|
||||||
|
after_transaction = after_transaction,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadName {
|
||||||
|
fn after_announce(&self, shared: &HeadState) {
|
||||||
|
self.send_supported_formats(shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_transaction(&self, shared: &HeadState, tran: &HeadState) {
|
||||||
|
if shared.supported_formats != tran.supported_formats {
|
||||||
|
self.send_supported_formats(shared);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_supported_formats(&self, state: &HeadState) {
|
||||||
|
self.client.event(Reset { self_id: self.id });
|
||||||
|
for format in &*state.supported_formats {
|
||||||
|
self.client.event(SupportedFormat {
|
||||||
|
self_id: self.id,
|
||||||
|
format: format.drm,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtFormatSetterV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtFormatSetterV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
|
||||||
|
fn set_format(&self, req: SetFormat, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let Some(format) = formats().get(&req.format) else {
|
||||||
|
return Err(ErrorName::UnknownFormat(req.format));
|
||||||
|
};
|
||||||
|
if self
|
||||||
|
.common
|
||||||
|
.transaction_state
|
||||||
|
.borrow()
|
||||||
|
.supported_formats
|
||||||
|
.not_contains(format)
|
||||||
|
{
|
||||||
|
return Err(ErrorName::UnsupportedFormat(req.format));
|
||||||
|
}
|
||||||
|
self.common.push_op(HeadOp::SetFormat(format))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error! {
|
||||||
|
#[error("Unknown format {0}")]
|
||||||
|
UnknownFormat(u32),
|
||||||
|
#[error("Unsupported format {0}")]
|
||||||
|
UnsupportedFormat(u32),
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::head_management::HeadState,
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_jay_tearing_mode_info_v1::{
|
||||||
|
JayHeadExtJayTearingModeInfoV1RequestHandler, Mode,
|
||||||
|
},
|
||||||
|
jay_head_manager_ext_jay_tearing_mode_info_v1::JayHeadManagerExtJayTearingModeInfoV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_jay_tearing_mode_info_v1! {
|
||||||
|
version = 1,
|
||||||
|
after_announce = after_announce,
|
||||||
|
after_transaction = after_transaction,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadName {
|
||||||
|
fn after_announce(&self, shared: &HeadState) {
|
||||||
|
self.send_mode(shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_transaction(&self, shared: &HeadState, tran: &HeadState) {
|
||||||
|
if shared.tearing_mode != tran.tearing_mode {
|
||||||
|
self.send_mode(shared);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_mode(&self, state: &HeadState) {
|
||||||
|
self.client.event(Mode {
|
||||||
|
self_id: self.id,
|
||||||
|
mode: state.tearing_mode.0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtJayTearingModeInfoV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtJayTearingModeInfoV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
error!();
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::head_management::{HeadOp, HeadState},
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_jay_tearing_mode_setter_v1::{
|
||||||
|
JayHeadExtJayTearingModeSetterV1RequestHandler, SetMode, SupportedMode,
|
||||||
|
},
|
||||||
|
jay_head_manager_ext_jay_tearing_mode_setter_v1::JayHeadManagerExtJayTearingModeSetterV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
jay_config::video::TearingMode,
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_jay_tearing_mode_setter_v1! {
|
||||||
|
version = 1,
|
||||||
|
after_announce = after_announce,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadName {
|
||||||
|
fn after_announce(&self, _shared: &HeadState) {
|
||||||
|
self.send_supported_mode(TearingMode::NEVER);
|
||||||
|
self.send_supported_mode(TearingMode::ALWAYS);
|
||||||
|
self.send_supported_mode(TearingMode::VARIANT_1);
|
||||||
|
self.send_supported_mode(TearingMode::VARIANT_2);
|
||||||
|
self.send_supported_mode(TearingMode::VARIANT_3);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_supported_mode(&self, mode: TearingMode) {
|
||||||
|
self.client.event(SupportedMode {
|
||||||
|
self_id: self.id,
|
||||||
|
mode: mode.0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtJayTearingModeSetterV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtJayTearingModeSetterV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
|
||||||
|
fn set_mode(&self, req: SetMode, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
if req.mode > TearingMode::VARIANT_3.0 {
|
||||||
|
return Err(ErrorName::UnknownMode(req.mode));
|
||||||
|
}
|
||||||
|
self.common
|
||||||
|
.push_op(HeadOp::SetTearingMode(TearingMode(req.mode)))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error! {
|
||||||
|
#[error("Unknown tearing mode {0}")]
|
||||||
|
UnknownMode(u32),
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::head_management::HeadState,
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_jay_vrr_mode_info_v1::{JayHeadExtJayVrrModeInfoV1RequestHandler, Mode},
|
||||||
|
jay_head_manager_ext_jay_vrr_mode_info_v1::JayHeadManagerExtJayVrrModeInfoV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_jay_vrr_mode_info_v1! {
|
||||||
|
version = 1,
|
||||||
|
after_announce = after_announce,
|
||||||
|
after_transaction = after_transaction,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadName {
|
||||||
|
fn after_announce(&self, shared: &HeadState) {
|
||||||
|
self.send_mode(shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_transaction(&self, shared: &HeadState, tran: &HeadState) {
|
||||||
|
if shared.vrr_mode != tran.vrr_mode {
|
||||||
|
self.send_mode(shared);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_mode(&self, state: &HeadState) {
|
||||||
|
self.client.event(Mode {
|
||||||
|
self_id: self.id,
|
||||||
|
mode: state.vrr_mode.0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtJayVrrModeInfoV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtJayVrrModeInfoV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
error!();
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::head_management::{HeadOp, HeadState},
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_jay_vrr_mode_setter_v1::{
|
||||||
|
JayHeadExtJayVrrModeSetterV1RequestHandler, SetMode, SupportedMode,
|
||||||
|
},
|
||||||
|
jay_head_manager_ext_jay_vrr_mode_setter_v1::JayHeadManagerExtJayVrrModeSetterV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
jay_config::video::VrrMode,
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_jay_vrr_mode_setter_v1! {
|
||||||
|
version = 1,
|
||||||
|
after_announce = after_announce,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadName {
|
||||||
|
fn after_announce(&self, _shared: &HeadState) {
|
||||||
|
self.send_supported_mode(VrrMode::NEVER);
|
||||||
|
self.send_supported_mode(VrrMode::ALWAYS);
|
||||||
|
self.send_supported_mode(VrrMode::VARIANT_1);
|
||||||
|
self.send_supported_mode(VrrMode::VARIANT_2);
|
||||||
|
self.send_supported_mode(VrrMode::VARIANT_3);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_supported_mode(&self, mode: VrrMode) {
|
||||||
|
self.client.event(SupportedMode {
|
||||||
|
self_id: self.id,
|
||||||
|
mode: mode.0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtJayVrrModeSetterV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtJayVrrModeSetterV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
|
||||||
|
fn set_mode(&self, req: SetMode, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
if req.mode > VrrMode::VARIANT_3.0 {
|
||||||
|
return Err(ErrorName::UnknownMode(req.mode));
|
||||||
|
}
|
||||||
|
self.common.push_op(HeadOp::SetVrrMode(VrrMode(req.mode)))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error! {
|
||||||
|
#[error("Unknown VRR mode {0}")]
|
||||||
|
UnknownMode(u32),
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::head_management::HeadState,
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_mode_info_v1::{JayHeadExtModeInfoV1RequestHandler, Mode},
|
||||||
|
jay_head_manager_ext_mode_info_v1::JayHeadManagerExtModeInfoV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_mode_info_v1! {
|
||||||
|
version = 1,
|
||||||
|
after_announce = after_announce,
|
||||||
|
after_transaction = after_transaction,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadName {
|
||||||
|
fn after_announce(&self, shared: &HeadState) {
|
||||||
|
self.send_mode(shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_transaction(&self, shared: &HeadState, tran: &HeadState) {
|
||||||
|
if shared.mode != tran.mode {
|
||||||
|
self.send_mode(shared);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_mode(&self, state: &HeadState) {
|
||||||
|
self.client.event(Mode {
|
||||||
|
self_id: self.id,
|
||||||
|
width: state.mode.width,
|
||||||
|
height: state.mode.height,
|
||||||
|
refresh_mhz: state.mode.refresh_rate_millihz,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtModeInfoV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtModeInfoV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
error!();
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
backend::CONCAP_MODE_SETTING,
|
||||||
|
ifs::head_management::{HeadCommon, HeadOp, HeadState},
|
||||||
|
state::ConnectorData,
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_mode_setter_v1::{
|
||||||
|
JayHeadExtModeSetterV1RequestHandler, Mode, Reset, SetMode,
|
||||||
|
},
|
||||||
|
jay_head_manager_ext_mode_setter_v1::JayHeadManagerExtModeSetterV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_mode_setter_v1! {
|
||||||
|
version = 1,
|
||||||
|
filter = filter,
|
||||||
|
after_announce = after_announce,
|
||||||
|
after_transaction = after_transaction,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MgrName {
|
||||||
|
fn filter(&self, connector: &ConnectorData, _common: &Rc<HeadCommon>) -> bool {
|
||||||
|
connector.connector.caps().contains(CONCAP_MODE_SETTING)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadName {
|
||||||
|
fn after_announce(&self, shared: &HeadState) {
|
||||||
|
self.send_modes(shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_transaction(&self, shared: &HeadState, tran: &HeadState) {
|
||||||
|
match (&shared.monitor_info, &tran.monitor_info) {
|
||||||
|
(Some(s), Some(t)) if s != t => {}
|
||||||
|
_ => return,
|
||||||
|
}
|
||||||
|
self.send_modes(shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_modes(&self, state: &HeadState) {
|
||||||
|
self.client.event(Reset { self_id: self.id });
|
||||||
|
if let Some(mi) = &state.monitor_info {
|
||||||
|
for mode in &mi.modes {
|
||||||
|
self.client.event(Mode {
|
||||||
|
self_id: self.id,
|
||||||
|
width: mode.width,
|
||||||
|
height: mode.height,
|
||||||
|
refresh_mhz: mode.refresh_rate_millihz,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtModeSetterV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtModeSetterV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
|
||||||
|
fn set_mode(&self, req: SetMode, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.common.assert_in_transaction()?;
|
||||||
|
let num_modes = self
|
||||||
|
.common
|
||||||
|
.snapshot_state
|
||||||
|
.borrow()
|
||||||
|
.monitor_info
|
||||||
|
.as_deref()
|
||||||
|
.map(|i| i.modes.len())
|
||||||
|
.unwrap_or(0);
|
||||||
|
let idx = req.idx as usize;
|
||||||
|
if idx >= num_modes {
|
||||||
|
return Err(JayHeadExtModeSetterV1Error::ModeOutOfBounds);
|
||||||
|
}
|
||||||
|
self.common.push_op(HeadOp::SetMode(idx))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error! {
|
||||||
|
#[error("The mode is out of bounds")]
|
||||||
|
ModeOutOfBounds,
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::head_management::HeadState,
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_non_desktop_info_v1::{
|
||||||
|
EffectiveDesktop, EffectiveNonDesktop, InherentDesktop, InherentNonDesktop,
|
||||||
|
JayHeadExtNonDesktopInfoV1RequestHandler, OverrideDesktop, OverrideNonDesktop,
|
||||||
|
Reset,
|
||||||
|
},
|
||||||
|
jay_head_manager_ext_non_desktop_info_v1::JayHeadManagerExtNonDesktopInfoV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_non_desktop_info_v1! {
|
||||||
|
version = 1,
|
||||||
|
after_announce = after_announce,
|
||||||
|
after_transaction = after_transaction,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadName {
|
||||||
|
fn after_announce(&self, shared: &HeadState) {
|
||||||
|
self.send_state(shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_transaction(&self, shared: &HeadState, tran: &HeadState) {
|
||||||
|
if shared.override_non_desktop == tran.override_non_desktop {
|
||||||
|
match (&shared.monitor_info, &tran.monitor_info) {
|
||||||
|
(Some(s), Some(t)) if s.non_desktop == t.non_desktop => return,
|
||||||
|
(None, None) => return,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.send_state(shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_state(&self, state: &HeadState) {
|
||||||
|
self.client.event(Reset { self_id: self.id });
|
||||||
|
let mut inherent_non_desktop = None;
|
||||||
|
if let Some(monitor_info) = &state.monitor_info {
|
||||||
|
inherent_non_desktop = Some(monitor_info.non_desktop);
|
||||||
|
if monitor_info.non_desktop {
|
||||||
|
self.client.event(InherentNonDesktop { self_id: self.id });
|
||||||
|
} else {
|
||||||
|
self.client.event(InherentDesktop { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(overrd) = state.override_non_desktop {
|
||||||
|
if overrd {
|
||||||
|
self.client.event(OverrideNonDesktop { self_id: self.id });
|
||||||
|
} else {
|
||||||
|
self.client.event(OverrideDesktop { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(nd) = state.override_non_desktop.or(inherent_non_desktop) {
|
||||||
|
if nd {
|
||||||
|
self.client.event(EffectiveNonDesktop { self_id: self.id });
|
||||||
|
} else {
|
||||||
|
self.client.event(EffectiveDesktop { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtNonDesktopInfoV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtNonDesktopInfoV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
error!();
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::head_management::HeadOp,
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_non_desktop_override_v1::{
|
||||||
|
DisableOverride, JayHeadExtNonDesktopOverrideV1RequestHandler, OverrideDesktop,
|
||||||
|
OverrideNonDesktop,
|
||||||
|
},
|
||||||
|
jay_head_manager_ext_non_desktop_override_v1::JayHeadManagerExtNonDesktopOverrideV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_non_desktop_override_v1! {
|
||||||
|
version = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtNonDesktopOverrideV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtNonDesktopOverrideV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
|
||||||
|
fn disable_override(&self, _req: DisableOverride, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.common.push_op(HeadOp::SetNonDesktopOverride(None))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn override_desktop(&self, _req: OverrideDesktop, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.common
|
||||||
|
.push_op(HeadOp::SetNonDesktopOverride(Some(false)))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn override_non_desktop(
|
||||||
|
&self,
|
||||||
|
_req: OverrideNonDesktop,
|
||||||
|
_slf: &Rc<Self>,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
self.common
|
||||||
|
.push_op(HeadOp::SetNonDesktopOverride(Some(true)))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error!();
|
||||||
|
|
@ -0,0 +1,125 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
backend::{self, CONCAP_PHYSICAL_DISPLAY},
|
||||||
|
ifs::head_management::{HeadCommon, HeadState},
|
||||||
|
state::ConnectorData,
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_physical_display_info_v1::{
|
||||||
|
JayHeadExtPhysicalDisplayInfoV1RequestHandler, Manufacturer, Mode, Model,
|
||||||
|
NonDesktop, PhysicalSize, Reset, SerialNumber, VrrCapable,
|
||||||
|
},
|
||||||
|
jay_head_manager_ext_physical_display_info_v1::JayHeadManagerExtPhysicalDisplayInfoV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_physical_display_info_v1! {
|
||||||
|
version = 1,
|
||||||
|
filter = filter,
|
||||||
|
after_announce = after_announce,
|
||||||
|
after_transaction = after_transaction,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MgrName {
|
||||||
|
fn filter(&self, connector: &ConnectorData, _common: &Rc<HeadCommon>) -> bool {
|
||||||
|
connector.connector.caps().contains(CONCAP_PHYSICAL_DISPLAY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadName {
|
||||||
|
fn after_announce(&self, shared: &HeadState) {
|
||||||
|
self.send_info(shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_transaction(&self, shared: &HeadState, tran: &HeadState) {
|
||||||
|
match (&shared.monitor_info, &tran.monitor_info) {
|
||||||
|
(Some(s), Some(t)) if s != t => {}
|
||||||
|
_ => return,
|
||||||
|
}
|
||||||
|
self.send_info(shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_info(&self, state: &HeadState) {
|
||||||
|
self.send_reset();
|
||||||
|
if let Some(mi) = &state.monitor_info {
|
||||||
|
for mode in &mi.modes {
|
||||||
|
self.send_mode(mode);
|
||||||
|
}
|
||||||
|
self.send_manufacturer(&mi.output_id.manufacturer);
|
||||||
|
self.send_model(&mi.output_id.model);
|
||||||
|
self.send_serial_number(&mi.output_id.serial_number);
|
||||||
|
self.send_physical_size(mi.width_mm, mi.height_mm);
|
||||||
|
if mi.non_desktop_effective {
|
||||||
|
self.send_non_desktop();
|
||||||
|
}
|
||||||
|
if mi.vrr_capable {
|
||||||
|
self.send_vrr_capable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_reset(&self) {
|
||||||
|
self.client.event(Reset { self_id: self.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_mode(&self, mode: &backend::Mode) {
|
||||||
|
self.client.event(Mode {
|
||||||
|
self_id: self.id,
|
||||||
|
width: mode.width,
|
||||||
|
height: mode.height,
|
||||||
|
refresh_mhz: mode.refresh_rate_millihz,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_physical_size(&self, width_mm: i32, height_mm: i32) {
|
||||||
|
self.client.event(PhysicalSize {
|
||||||
|
self_id: self.id,
|
||||||
|
width_mm,
|
||||||
|
height_mm,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_manufacturer(&self, manufacturer: &str) {
|
||||||
|
self.client.event(Manufacturer {
|
||||||
|
self_id: self.id,
|
||||||
|
manufacturer,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_model(&self, model: &str) {
|
||||||
|
self.client.event(Model {
|
||||||
|
self_id: self.id,
|
||||||
|
model,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_serial_number(&self, serial_number: &str) {
|
||||||
|
self.client.event(SerialNumber {
|
||||||
|
self_id: self.id,
|
||||||
|
serial_number,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_non_desktop(&self) {
|
||||||
|
self.client.event(NonDesktop { self_id: self.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_vrr_capable(&self) {
|
||||||
|
self.client.event(VrrCapable { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtPhysicalDisplayInfoV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtPhysicalDisplayInfoV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
error!();
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::head_management::HeadState,
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_tearing_state_v1::{
|
||||||
|
Active, Disabled, Enabled, Inactive, JayHeadExtTearingStateV1RequestHandler,
|
||||||
|
},
|
||||||
|
jay_head_manager_ext_tearing_state_v1::JayHeadManagerExtTearingStateV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_tearing_state_v1! {
|
||||||
|
version = 1,
|
||||||
|
after_announce = after_announce,
|
||||||
|
after_transaction = after_transaction,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadName {
|
||||||
|
fn after_announce(&self, shared: &HeadState) {
|
||||||
|
self.send_enabled(shared);
|
||||||
|
self.send_active(shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_transaction(&self, shared: &HeadState, tran: &HeadState) {
|
||||||
|
if shared.tearing_enabled != tran.tearing_enabled {
|
||||||
|
self.send_enabled(shared);
|
||||||
|
}
|
||||||
|
if shared.tearing_active != tran.tearing_active {
|
||||||
|
self.send_active(shared);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_enabled(&self, state: &HeadState) {
|
||||||
|
if state.tearing_enabled {
|
||||||
|
self.client.event(Enabled { self_id: self.id });
|
||||||
|
} else {
|
||||||
|
self.client.event(Disabled { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_active(&self, state: &HeadState) {
|
||||||
|
if state.tearing_active {
|
||||||
|
self.client.event(Active { self_id: self.id });
|
||||||
|
} else {
|
||||||
|
self.client.event(Inactive { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtTearingStateV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtTearingStateV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
error!();
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::head_management::HeadState,
|
||||||
|
wire::{
|
||||||
|
jay_head_ext_vrr_state_v1::{
|
||||||
|
Capable, Enabled, JayHeadExtVrrStateV1RequestHandler, Reset,
|
||||||
|
},
|
||||||
|
jay_head_manager_ext_vrr_state_v1::JayHeadManagerExtVrrStateV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_vrr_state_v1! {
|
||||||
|
version = 1,
|
||||||
|
after_announce = after_announce,
|
||||||
|
after_transaction = after_transaction,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeadName {
|
||||||
|
fn after_announce(&self, shared: &HeadState) {
|
||||||
|
self.send_state(shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_transaction(&self, shared: &HeadState, tran: &HeadState) {
|
||||||
|
let shared_capable = shared.monitor_info.as_ref().map(|m| m.vrr_capable);
|
||||||
|
let tran_capable = tran.monitor_info.as_ref().map(|m| m.vrr_capable);
|
||||||
|
if (shared.vrr, shared_capable) != (tran.vrr, tran_capable) {
|
||||||
|
self.send_state(shared);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn send_state(&self, state: &HeadState) {
|
||||||
|
self.client.event(Reset { self_id: self.id });
|
||||||
|
if let Some(mi) = &state.monitor_info
|
||||||
|
&& mi.vrr_capable
|
||||||
|
{
|
||||||
|
self.client.event(Capable { self_id: self.id });
|
||||||
|
}
|
||||||
|
if state.vrr {
|
||||||
|
self.client.event(Enabled { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerExtVrrStateV1RequestHandler for MgrName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
mgr_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadExtVrrStateV1RequestHandler for HeadName {
|
||||||
|
type Error = ErrorName;
|
||||||
|
|
||||||
|
head_common_req!();
|
||||||
|
}
|
||||||
|
|
||||||
|
error!();
|
||||||
634
src/ifs/head_management/jay_head_manager_session_v1.rs
Normal file
634
src/ifs/head_management/jay_head_manager_session_v1.rs
Normal file
|
|
@ -0,0 +1,634 @@
|
||||||
|
use {
|
||||||
|
super::HeadMgrCommon,
|
||||||
|
crate::{
|
||||||
|
backend::transaction::{ConnectorTransaction, PreparedConnectorTransaction},
|
||||||
|
client::{Client, ClientError},
|
||||||
|
ifs::{
|
||||||
|
head_management::{
|
||||||
|
Head, HeadCommon, HeadCommonError, HeadMgrState, HeadName, HeadOp,
|
||||||
|
HeadTransactionError,
|
||||||
|
head_management_macros::{HeadExtension, MgrExts, announce_head, bind_extension},
|
||||||
|
jay_head_manager_v1::JayHeadManagerV1,
|
||||||
|
jay_head_transaction_result_v1::JayHeadTransactionResultV1,
|
||||||
|
jay_head_v1::JayHeadV1,
|
||||||
|
},
|
||||||
|
wl_output::PersistentOutputState,
|
||||||
|
},
|
||||||
|
leaks::Tracker,
|
||||||
|
object::{Object, Version},
|
||||||
|
state::{ConnectorData, State},
|
||||||
|
tree::{TearingMode, VrrMode},
|
||||||
|
utils::{copyhashmap::CopyHashMap, numcell::NumCell},
|
||||||
|
wire::{
|
||||||
|
JayHeadManagerSessionV1Id, JayHeadTransactionResultV1Id,
|
||||||
|
jay_head_manager_session_v1::{
|
||||||
|
ApplyChanges, BeginTransaction, BindExtension, CommitTransaction, Destroy,
|
||||||
|
HeadComplete, HeadStart, JayHeadManagerSessionV1RequestHandler,
|
||||||
|
RollbackTransaction, Start, Stop, Stopped, TestTransaction, TransactionEnded,
|
||||||
|
TransactionStarted,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
linearize::LinearizeExt,
|
||||||
|
std::{cell::Cell, mem, ops::Deref, rc::Rc},
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct HeadManagerEvent {
|
||||||
|
mgr: Rc<JayHeadManagerSessionV1>,
|
||||||
|
ty: HeadManagerEventType,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) enum HeadManagerEventType {
|
||||||
|
Done,
|
||||||
|
TransactionStarted,
|
||||||
|
TransactionEnded,
|
||||||
|
TransactionResult(Rc<JayHeadTransactionResultV1>),
|
||||||
|
Stopped,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn handle_jay_head_manager_done(state: Rc<State>) {
|
||||||
|
loop {
|
||||||
|
let ev = state.head_managers_async.pop().await;
|
||||||
|
let session = ev.mgr;
|
||||||
|
if session.mgr.destroyed.get() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if session.mgr.done_scheduled.take() {
|
||||||
|
session.mgr.send_done();
|
||||||
|
}
|
||||||
|
if session.common.state.get() == HeadMgrState::Stopped {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
match ev.ty {
|
||||||
|
HeadManagerEventType::Done => {}
|
||||||
|
HeadManagerEventType::TransactionStarted => {
|
||||||
|
session.send_transaction_started();
|
||||||
|
}
|
||||||
|
HeadManagerEventType::TransactionEnded => {
|
||||||
|
session.send_transaction_ended();
|
||||||
|
}
|
||||||
|
HeadManagerEventType::Stopped => {
|
||||||
|
session.common.state.set(HeadMgrState::Stopped);
|
||||||
|
session.send_stopped();
|
||||||
|
}
|
||||||
|
HeadManagerEventType::TransactionResult(res) => {
|
||||||
|
if !res.destroyed.get() {
|
||||||
|
res.send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct JayHeadManagerSessionV1 {
|
||||||
|
pub(super) id: JayHeadManagerSessionV1Id,
|
||||||
|
pub(super) mgr: Rc<JayHeadManagerV1>,
|
||||||
|
pub(super) client: Rc<Client>,
|
||||||
|
pub(super) tracker: Tracker<Self>,
|
||||||
|
pub(super) version: Version,
|
||||||
|
pub(super) common: Rc<HeadMgrCommon>,
|
||||||
|
pub(super) serial: NumCell<u64>,
|
||||||
|
pub(super) heads: CopyHashMap<HeadName, Rc<Head>>,
|
||||||
|
pub(super) ext: MgrExts,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerSessionV1 {
|
||||||
|
pub fn announce(self: &Rc<Self>, connector: &ConnectorData) {
|
||||||
|
if self.common.in_transaction.get() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if let Err(e) = self.try_announce(connector) {
|
||||||
|
self.client.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_announce(self: &Rc<Self>, connector: &ConnectorData) -> Result<(), ClientError> {
|
||||||
|
let shared = connector.head_managers.state.clone();
|
||||||
|
let common = Rc::new(HeadCommon {
|
||||||
|
mgr: self.common.clone(),
|
||||||
|
name: connector.head_managers.name,
|
||||||
|
id: connector.id,
|
||||||
|
removed: Cell::new(false),
|
||||||
|
shared: shared.clone(),
|
||||||
|
snapshot_state: shared.deref().clone(),
|
||||||
|
transaction_state: shared.deref().clone(),
|
||||||
|
pending: Default::default(),
|
||||||
|
});
|
||||||
|
let obj = Rc::new(JayHeadV1 {
|
||||||
|
id: self.client.new_id()?,
|
||||||
|
client: self.client.clone(),
|
||||||
|
tracker: Default::default(),
|
||||||
|
version: self.version,
|
||||||
|
common: common.clone(),
|
||||||
|
});
|
||||||
|
track!(self.client, obj);
|
||||||
|
self.client.add_server_obj(&obj);
|
||||||
|
let head = announce_head(self, &obj, connector)?;
|
||||||
|
connector
|
||||||
|
.head_managers
|
||||||
|
.managers
|
||||||
|
.set((self.client.id, self.id), head.clone());
|
||||||
|
self.heads.set(common.name, head);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schedule_event(self: &Rc<Self>, ty: HeadManagerEventType) {
|
||||||
|
self.client
|
||||||
|
.state
|
||||||
|
.head_managers_async
|
||||||
|
.push(HeadManagerEvent {
|
||||||
|
mgr: self.clone(),
|
||||||
|
ty,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn schedule_done(self: &Rc<Self>) {
|
||||||
|
if !self.mgr.done_scheduled.replace(true) {
|
||||||
|
self.serial.fetch_add(1);
|
||||||
|
self.schedule_event(HeadManagerEventType::Done);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schedule_transaction_started(self: &Rc<Self>) {
|
||||||
|
self.mgr.done_scheduled.set(true);
|
||||||
|
self.schedule_event(HeadManagerEventType::TransactionStarted);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schedule_transaction_ended(self: &Rc<Self>) {
|
||||||
|
self.mgr.done_scheduled.set(true);
|
||||||
|
self.schedule_event(HeadManagerEventType::TransactionEnded);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schedule_stopped(self: &Rc<Self>) {
|
||||||
|
self.mgr.done_scheduled.set(true);
|
||||||
|
self.schedule_event(HeadManagerEventType::Stopped);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_transaction_started(&self) {
|
||||||
|
self.client.event(TransactionStarted { self_id: self.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_transaction_ended(&self) {
|
||||||
|
self.client.event(TransactionEnded { self_id: self.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_stopped(&self) {
|
||||||
|
self.client.event(Stopped { self_id: self.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn send_head_start(&self, head: &JayHeadV1, name: HeadName) {
|
||||||
|
self.client.event(HeadStart {
|
||||||
|
self_id: self.id,
|
||||||
|
head: head.id,
|
||||||
|
name: name.0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn send_head_complete(&self) {
|
||||||
|
self.client.event(HeadComplete { self_id: self.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn detach(&self, send_removed: bool) {
|
||||||
|
let id = (self.client.id, self.id);
|
||||||
|
for data in self.client.state.connectors.lock().values() {
|
||||||
|
if let Some(head) = data.head_managers.managers.remove(&id) {
|
||||||
|
if send_removed {
|
||||||
|
head.head.send_removed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.client.state.head_managers.remove(&id);
|
||||||
|
self.heads.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schedule_transaction_result(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
id: JayHeadTransactionResultV1Id,
|
||||||
|
error: Option<HeadTransactionError>,
|
||||||
|
) -> Result<(), JayHeadManagerSessionV1Error> {
|
||||||
|
if error.is_some() {
|
||||||
|
self.common.transaction_failed.set(true);
|
||||||
|
}
|
||||||
|
self.mgr.done_scheduled.set(true);
|
||||||
|
let res = Rc::new(JayHeadTransactionResultV1 {
|
||||||
|
id,
|
||||||
|
client: self.client.clone(),
|
||||||
|
tracker: Default::default(),
|
||||||
|
version: self.version,
|
||||||
|
error: error.map(Rc::new),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
});
|
||||||
|
track!(self.client, res);
|
||||||
|
self.client.add_client_obj(&res)?;
|
||||||
|
self.schedule_event(HeadManagerEventType::TransactionResult(res));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_transaction_ended(self: &Rc<Self>) {
|
||||||
|
let mut to_remove = vec![];
|
||||||
|
for head in self.heads.lock().values() {
|
||||||
|
if self.client.state.connectors.not_contains(&head.common.id) {
|
||||||
|
head.head.send_removed();
|
||||||
|
to_remove.push(head.common.name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let _ = head.common.pending.take();
|
||||||
|
let tran = &*head.common.transaction_state.borrow();
|
||||||
|
let shared = &*head.common.shared.borrow();
|
||||||
|
head.ext.after_transaction(shared, tran);
|
||||||
|
}
|
||||||
|
for name in to_remove {
|
||||||
|
self.heads.remove(&name);
|
||||||
|
}
|
||||||
|
for connector in self.client.state.connectors.lock().values() {
|
||||||
|
if !self.heads.contains(&connector.head_managers.name) {
|
||||||
|
self.announce(connector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.schedule_transaction_ended();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepare_transaction(&self) -> Result<PreparedConnectorTransaction, HeadTransactionError> {
|
||||||
|
let mut tran = ConnectorTransaction::new(&self.client.state);
|
||||||
|
for head in self.heads.lock().values() {
|
||||||
|
let current = &*head.common.shared.borrow();
|
||||||
|
let snapshot = &*head.common.snapshot_state.borrow();
|
||||||
|
let desired = &*head.common.transaction_state.borrow();
|
||||||
|
if desired == current || desired == snapshot {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let Some(connector) = self.client.state.connectors.get(&head.common.id) else {
|
||||||
|
return Err(HeadTransactionError::HeadRemoved(head.common.id));
|
||||||
|
};
|
||||||
|
let old = connector.state.get();
|
||||||
|
let mut new = old;
|
||||||
|
new.enabled = desired.connector_enabled;
|
||||||
|
new.mode = desired.mode;
|
||||||
|
new.non_desktop_override = desired.override_non_desktop;
|
||||||
|
new.format = desired.format;
|
||||||
|
new.color_space = desired.color_space;
|
||||||
|
new.transfer_function = desired.transfer_function;
|
||||||
|
if old == new {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if current.monitor_info != desired.monitor_info {
|
||||||
|
return Err(HeadTransactionError::MonitorChanged(head.common.id));
|
||||||
|
}
|
||||||
|
tran.add(&connector.connector, new)?;
|
||||||
|
}
|
||||||
|
Ok(tran.prepare()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn commit_transaction(&self) -> Result<(), HeadTransactionError> {
|
||||||
|
self.prepare_transaction()?.apply()?.commit();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerSessionV1RequestHandler for JayHeadManagerSessionV1 {
|
||||||
|
type Error = JayHeadManagerSessionV1Error;
|
||||||
|
|
||||||
|
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.common.assert_stopped()?;
|
||||||
|
self.mgr.sessions.fetch_sub(1);
|
||||||
|
self.client.remove_obj(self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bind_extension(&self, req: BindExtension<'_>, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
if self.common.state.get() != HeadMgrState::Init {
|
||||||
|
return Err(JayHeadManagerSessionV1Error::AlreadyStarted);
|
||||||
|
}
|
||||||
|
let Some(ext) = HeadExtension::from_linear(req.name as usize) else {
|
||||||
|
return Err(JayHeadManagerSessionV1Error::UnknownExtension(req.name));
|
||||||
|
};
|
||||||
|
bind_extension(self, ext, req.name, req.version, req.id)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stop(&self, _req: Stop, slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
if self.common.in_transaction.get() {
|
||||||
|
return Err(JayHeadManagerSessionV1Error::InTransaction);
|
||||||
|
}
|
||||||
|
match self.common.state.get() {
|
||||||
|
HeadMgrState::Init | HeadMgrState::Started => {}
|
||||||
|
HeadMgrState::StopScheduled | HeadMgrState::Stopped => return Ok(()),
|
||||||
|
}
|
||||||
|
self.common.state.set(HeadMgrState::StopScheduled);
|
||||||
|
self.detach(true);
|
||||||
|
self.serial.fetch_add(1);
|
||||||
|
slf.schedule_stopped();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start(&self, _req: Start, slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
if self.common.state.get() != HeadMgrState::Init {
|
||||||
|
return Err(JayHeadManagerSessionV1Error::AlreadyStarted);
|
||||||
|
}
|
||||||
|
self.common.state.set(HeadMgrState::Started);
|
||||||
|
self.client
|
||||||
|
.state
|
||||||
|
.head_managers
|
||||||
|
.set((self.client.id, self.id), slf.clone());
|
||||||
|
for connector in self.client.state.connectors.lock().values() {
|
||||||
|
slf.announce(connector);
|
||||||
|
}
|
||||||
|
slf.schedule_done();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn begin_transaction(&self, _req: BeginTransaction, slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
if self.common.in_transaction.replace(true) {
|
||||||
|
return Err(JayHeadManagerSessionV1Error::AlreadyInTransaction);
|
||||||
|
}
|
||||||
|
for head in self.heads.lock().values() {
|
||||||
|
let snapshot = head.common.shared.borrow().clone();
|
||||||
|
*head.common.transaction_state.borrow_mut() = snapshot.clone();
|
||||||
|
*head.common.snapshot_state.borrow_mut() = snapshot;
|
||||||
|
head.common.pending.borrow_mut().clear();
|
||||||
|
}
|
||||||
|
self.common.transaction_failed.set(false);
|
||||||
|
slf.schedule_transaction_started();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rollback_transaction(
|
||||||
|
&self,
|
||||||
|
_req: RollbackTransaction,
|
||||||
|
slf: &Rc<Self>,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
if !self.common.in_transaction.replace(false) {
|
||||||
|
return Err(JayHeadManagerSessionV1Error::NotInTransaction);
|
||||||
|
}
|
||||||
|
slf.after_transaction_ended();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_changes(&self, req: ApplyChanges, slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
if !self.common.in_transaction.get() {
|
||||||
|
return Err(JayHeadManagerSessionV1Error::NotInTransaction);
|
||||||
|
}
|
||||||
|
macro_rules! schedule_result {
|
||||||
|
($res:expr) => {
|
||||||
|
slf.schedule_transaction_result(req.result, Some($res))?;
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if self.common.transaction_failed.get() {
|
||||||
|
schedule_result!(HeadTransactionError::AlreadyFailed);
|
||||||
|
}
|
||||||
|
bitflags! {
|
||||||
|
ToSend: u32;
|
||||||
|
CORE_INFO = 1 << 0,
|
||||||
|
COMPOSITOR_SPACE_INFO_FULL = 1 << 1,
|
||||||
|
COMPOSITOR_SPACE_INFO_POS = 1 << 2,
|
||||||
|
COMPOSITOR_SPACE_INFO_SIZE = 1 << 3,
|
||||||
|
COMPOSITOR_SPACE_INFO_TRANSFORM = 1 << 4,
|
||||||
|
COMPOSITOR_SPACE_INFO_SCALE = 1 << 5,
|
||||||
|
MODE_INFO = 1 << 6,
|
||||||
|
NON_DESKTOP_INFO = 1 << 7,
|
||||||
|
VRR_MODE_INFO = 1 << 8,
|
||||||
|
TEARING_MODE_INFO = 1 << 9,
|
||||||
|
FORMAT_INFO = 1 << 10,
|
||||||
|
DRM_COLOR_SPACE_INFO = 1 << 11,
|
||||||
|
BRIGHTNESS_INFO = 1 << 12,
|
||||||
|
COMPOSITOR_SPACE_INFO_ENABLED = 1 << 13,
|
||||||
|
}
|
||||||
|
for head in self.heads.lock().values() {
|
||||||
|
let pending = mem::take(&mut *head.common.pending.borrow_mut());
|
||||||
|
let snapshot = &*head.common.snapshot_state.borrow();
|
||||||
|
let state = &mut *head.common.transaction_state.borrow_mut();
|
||||||
|
let mut to_send = ToSend::default();
|
||||||
|
for op in pending {
|
||||||
|
match op {
|
||||||
|
HeadOp::SetPosition(x, y) => {
|
||||||
|
state.position = (x, y);
|
||||||
|
to_send |= COMPOSITOR_SPACE_INFO_POS;
|
||||||
|
}
|
||||||
|
HeadOp::SetConnectorEnabled(enabled) => {
|
||||||
|
state.connector_enabled = enabled;
|
||||||
|
state.update_in_compositor_space(snapshot.wl_output);
|
||||||
|
to_send |= COMPOSITOR_SPACE_INFO_FULL;
|
||||||
|
to_send |= COMPOSITOR_SPACE_INFO_ENABLED;
|
||||||
|
to_send |= CORE_INFO;
|
||||||
|
}
|
||||||
|
HeadOp::SetTransform(t) => {
|
||||||
|
state.transform = t;
|
||||||
|
state.update_size();
|
||||||
|
to_send |= COMPOSITOR_SPACE_INFO_TRANSFORM;
|
||||||
|
to_send |= COMPOSITOR_SPACE_INFO_SIZE;
|
||||||
|
}
|
||||||
|
HeadOp::SetScale(s) => {
|
||||||
|
state.scale = s;
|
||||||
|
state.update_size();
|
||||||
|
to_send |= COMPOSITOR_SPACE_INFO_SCALE;
|
||||||
|
to_send |= COMPOSITOR_SPACE_INFO_SIZE;
|
||||||
|
}
|
||||||
|
HeadOp::SetMode(i) => {
|
||||||
|
state.mode = snapshot.monitor_info.as_deref().unwrap().modes[i];
|
||||||
|
state.update_size();
|
||||||
|
to_send |= MODE_INFO;
|
||||||
|
to_send |= COMPOSITOR_SPACE_INFO_SIZE;
|
||||||
|
}
|
||||||
|
HeadOp::SetNonDesktopOverride(m) => {
|
||||||
|
state.override_non_desktop = m;
|
||||||
|
state.update_in_compositor_space(snapshot.wl_output);
|
||||||
|
to_send |= COMPOSITOR_SPACE_INFO_FULL;
|
||||||
|
to_send |= CORE_INFO;
|
||||||
|
to_send |= NON_DESKTOP_INFO;
|
||||||
|
}
|
||||||
|
HeadOp::SetVrrMode(m) => {
|
||||||
|
state.vrr_mode = m;
|
||||||
|
to_send |= VRR_MODE_INFO;
|
||||||
|
}
|
||||||
|
HeadOp::SetTearingMode(m) => {
|
||||||
|
state.tearing_mode = m;
|
||||||
|
to_send |= TEARING_MODE_INFO;
|
||||||
|
}
|
||||||
|
HeadOp::SetFormat(f) => {
|
||||||
|
state.format = f;
|
||||||
|
to_send |= FORMAT_INFO;
|
||||||
|
}
|
||||||
|
HeadOp::SetTransferFunction(e) => {
|
||||||
|
state.transfer_function = e;
|
||||||
|
to_send |= DRM_COLOR_SPACE_INFO;
|
||||||
|
to_send |= BRIGHTNESS_INFO;
|
||||||
|
}
|
||||||
|
HeadOp::SetColorSpace(c) => {
|
||||||
|
state.color_space = c;
|
||||||
|
to_send |= DRM_COLOR_SPACE_INFO;
|
||||||
|
}
|
||||||
|
HeadOp::SetBrightness(b) => {
|
||||||
|
state.brightness = b;
|
||||||
|
to_send |= BRIGHTNESS_INFO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if to_send.contains(CORE_INFO)
|
||||||
|
&& let Some(i) = &head.ext.core_info_v1
|
||||||
|
{
|
||||||
|
i.send_wl_output(state);
|
||||||
|
}
|
||||||
|
if let Some(i) = &head.ext.compositor_space_info_v1 {
|
||||||
|
if to_send.contains(COMPOSITOR_SPACE_INFO_ENABLED) {
|
||||||
|
i.send_enabled(state);
|
||||||
|
}
|
||||||
|
if to_send.contains(COMPOSITOR_SPACE_INFO_FULL) {
|
||||||
|
i.send_inside_outside(state);
|
||||||
|
} else {
|
||||||
|
if to_send.contains(COMPOSITOR_SPACE_INFO_POS) {
|
||||||
|
i.send_position(state);
|
||||||
|
}
|
||||||
|
if to_send.contains(COMPOSITOR_SPACE_INFO_SIZE) {
|
||||||
|
i.send_size(state);
|
||||||
|
}
|
||||||
|
if to_send.contains(COMPOSITOR_SPACE_INFO_TRANSFORM) {
|
||||||
|
i.send_transform(state);
|
||||||
|
}
|
||||||
|
if to_send.contains(COMPOSITOR_SPACE_INFO_SCALE) {
|
||||||
|
i.send_scale(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if to_send.contains(MODE_INFO)
|
||||||
|
&& let Some(i) = &head.ext.mode_info_v1
|
||||||
|
{
|
||||||
|
i.send_mode(state);
|
||||||
|
}
|
||||||
|
if to_send.contains(NON_DESKTOP_INFO)
|
||||||
|
&& let Some(i) = &head.ext.non_desktop_info_v1
|
||||||
|
{
|
||||||
|
i.send_state(state);
|
||||||
|
}
|
||||||
|
if to_send.contains(VRR_MODE_INFO)
|
||||||
|
&& let Some(i) = &head.ext.jay_vrr_mode_info_v1
|
||||||
|
{
|
||||||
|
i.send_mode(state);
|
||||||
|
}
|
||||||
|
if to_send.contains(TEARING_MODE_INFO)
|
||||||
|
&& let Some(i) = &head.ext.jay_tearing_mode_info_v1
|
||||||
|
{
|
||||||
|
i.send_mode(state);
|
||||||
|
}
|
||||||
|
if to_send.contains(FORMAT_INFO)
|
||||||
|
&& let Some(i) = &head.ext.format_info_v1
|
||||||
|
{
|
||||||
|
i.send_format(state);
|
||||||
|
}
|
||||||
|
if to_send.contains(DRM_COLOR_SPACE_INFO)
|
||||||
|
&& let Some(i) = &head.ext.drm_color_space_info_v1
|
||||||
|
{
|
||||||
|
i.send_state(state);
|
||||||
|
}
|
||||||
|
if to_send.contains(BRIGHTNESS_INFO)
|
||||||
|
&& let Some(i) = &head.ext.brightness_info_v1
|
||||||
|
{
|
||||||
|
i.send_brightness(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slf.schedule_transaction_result(req.result, None)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_transaction(&self, req: TestTransaction, slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
if !self.common.in_transaction.get() {
|
||||||
|
return Err(JayHeadManagerSessionV1Error::NotInTransaction);
|
||||||
|
}
|
||||||
|
let res = self.prepare_transaction().err();
|
||||||
|
slf.schedule_transaction_result(req.result, res)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn commit_transaction(
|
||||||
|
&self,
|
||||||
|
req: CommitTransaction,
|
||||||
|
slf: &Rc<Self>,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
if !self.common.in_transaction.replace(false) {
|
||||||
|
return Err(JayHeadManagerSessionV1Error::NotInTransaction);
|
||||||
|
}
|
||||||
|
slf.after_transaction_ended();
|
||||||
|
if let Err(e) = self.commit_transaction() {
|
||||||
|
slf.schedule_transaction_result(req.result, Some(e))?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
for head in self.heads.lock().values() {
|
||||||
|
let desired = &*head.common.transaction_state.borrow();
|
||||||
|
if let Some(output) = self.client.state.outputs.get(&head.common.id)
|
||||||
|
&& let Some(node) = &output.node
|
||||||
|
{
|
||||||
|
node.set_position(desired.position.0, desired.position.1);
|
||||||
|
node.set_preferred_scale(desired.scale);
|
||||||
|
node.update_transform(desired.transform);
|
||||||
|
node.set_vrr_mode(VrrMode::from_config(desired.vrr_mode).unwrap());
|
||||||
|
node.set_tearing_mode(TearingMode::from_config(desired.tearing_mode).unwrap());
|
||||||
|
node.set_brightness(desired.brightness);
|
||||||
|
} else if let Some(mi) = &desired.monitor_info {
|
||||||
|
let pos = &self.client.state.persistent_output_states;
|
||||||
|
let pos = match pos.get(&mi.output_id) {
|
||||||
|
Some(ps) => ps,
|
||||||
|
_ => {
|
||||||
|
let ps = Rc::new(PersistentOutputState {
|
||||||
|
transform: Default::default(),
|
||||||
|
scale: Default::default(),
|
||||||
|
pos: Default::default(),
|
||||||
|
vrr_mode: Cell::new(&VrrMode::Never),
|
||||||
|
vrr_cursor_hz: Default::default(),
|
||||||
|
tearing_mode: Cell::new(&TearingMode::Never),
|
||||||
|
brightness: Default::default(),
|
||||||
|
});
|
||||||
|
pos.set(mi.output_id.clone(), ps.clone());
|
||||||
|
ps
|
||||||
|
}
|
||||||
|
};
|
||||||
|
pos.pos.set(desired.position);
|
||||||
|
pos.scale.set(desired.scale);
|
||||||
|
pos.transform.set(desired.transform);
|
||||||
|
pos.vrr_mode
|
||||||
|
.set(VrrMode::from_config(desired.vrr_mode).unwrap());
|
||||||
|
pos.tearing_mode
|
||||||
|
.set(TearingMode::from_config(desired.tearing_mode).unwrap());
|
||||||
|
pos.brightness.set(desired.brightness);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slf.schedule_transaction_result(req.result, None)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_base! {
|
||||||
|
self = JayHeadManagerSessionV1;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for JayHeadManagerSessionV1 {
|
||||||
|
fn break_loops(&self) {
|
||||||
|
self.detach(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simple_add_obj!(JayHeadManagerSessionV1);
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum JayHeadManagerSessionV1Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientError(Box<ClientError>),
|
||||||
|
#[error(transparent)]
|
||||||
|
Common(#[from] HeadCommonError),
|
||||||
|
#[error("Manager was already started")]
|
||||||
|
AlreadyStarted,
|
||||||
|
#[error("There is no extension with name {}", .0)]
|
||||||
|
UnknownExtension(u32),
|
||||||
|
#[error("The extension with name {} is already bound", .0)]
|
||||||
|
AlreadyBound(u32),
|
||||||
|
#[error("The extension with name {} does not support version {}", .0, .1 .0)]
|
||||||
|
UnsupportedVersion(u32, Version),
|
||||||
|
#[error("There already is an active transaction")]
|
||||||
|
AlreadyInTransaction,
|
||||||
|
#[error("There is no active transaction")]
|
||||||
|
NotInTransaction,
|
||||||
|
#[error("There is an active transaction")]
|
||||||
|
InTransaction,
|
||||||
|
}
|
||||||
|
efrom!(JayHeadManagerSessionV1Error, ClientError);
|
||||||
158
src/ifs/head_management/jay_head_manager_v1.rs
Normal file
158
src/ifs/head_management/jay_head_manager_v1.rs
Normal file
|
|
@ -0,0 +1,158 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
client::{CAP_HEAD_MANAGER, Client, ClientCaps, ClientError},
|
||||||
|
globals::{Global, GlobalName},
|
||||||
|
ifs::head_management::{
|
||||||
|
HeadMgrCommon, head_management_macros::send_available_extensions,
|
||||||
|
jay_head_manager_session_v1::JayHeadManagerSessionV1,
|
||||||
|
},
|
||||||
|
leaks::Tracker,
|
||||||
|
object::{Object, Version},
|
||||||
|
utils::numcell::NumCell,
|
||||||
|
wire::{
|
||||||
|
JayHeadManagerV1Id,
|
||||||
|
jay_head_manager_v1::{
|
||||||
|
CreateSession, Destroy, Done, Extension, ExtensionsDone,
|
||||||
|
JayHeadManagerV1RequestHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct JayHeadManagerV1Global {
|
||||||
|
pub name: GlobalName,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerV1Global {
|
||||||
|
pub fn new(name: GlobalName) -> Self {
|
||||||
|
Self { name }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bind_(
|
||||||
|
self: Rc<Self>,
|
||||||
|
id: JayHeadManagerV1Id,
|
||||||
|
client: &Rc<Client>,
|
||||||
|
version: Version,
|
||||||
|
) -> Result<(), JayHeadManagerV1Error> {
|
||||||
|
let mgr = Rc::new(JayHeadManagerV1 {
|
||||||
|
id,
|
||||||
|
client: client.clone(),
|
||||||
|
tracker: Default::default(),
|
||||||
|
version,
|
||||||
|
done_scheduled: Cell::new(false),
|
||||||
|
sessions: Default::default(),
|
||||||
|
destroyed: Default::default(),
|
||||||
|
});
|
||||||
|
track!(client, mgr);
|
||||||
|
client.add_client_obj(&mgr)?;
|
||||||
|
send_available_extensions(&mgr);
|
||||||
|
mgr.send_extensions_done();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
global_base!(
|
||||||
|
JayHeadManagerV1Global,
|
||||||
|
JayHeadManagerV1,
|
||||||
|
JayHeadManagerV1Error
|
||||||
|
);
|
||||||
|
|
||||||
|
simple_add_global!(JayHeadManagerV1Global);
|
||||||
|
|
||||||
|
impl Global for JayHeadManagerV1Global {
|
||||||
|
fn singleton(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn version(&self) -> u32 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn required_caps(&self) -> ClientCaps {
|
||||||
|
CAP_HEAD_MANAGER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct JayHeadManagerV1 {
|
||||||
|
pub(super) id: JayHeadManagerV1Id,
|
||||||
|
pub(super) client: Rc<Client>,
|
||||||
|
pub(super) tracker: Tracker<Self>,
|
||||||
|
pub(super) version: Version,
|
||||||
|
pub(super) done_scheduled: Cell<bool>,
|
||||||
|
pub(super) sessions: NumCell<u32>,
|
||||||
|
pub(super) destroyed: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerV1 {
|
||||||
|
pub(super) fn send_extension(&self, name: u32, interface: &str, version: Version) {
|
||||||
|
self.client.event(Extension {
|
||||||
|
self_id: self.id,
|
||||||
|
name,
|
||||||
|
interface,
|
||||||
|
version: version.0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_extensions_done(&self) {
|
||||||
|
self.client.event(ExtensionsDone { self_id: self.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn send_done(&self) {
|
||||||
|
self.client.event(Done { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadManagerV1RequestHandler for JayHeadManagerV1 {
|
||||||
|
type Error = JayHeadManagerV1Error;
|
||||||
|
|
||||||
|
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
if self.sessions.get() > 0 {
|
||||||
|
return Err(JayHeadManagerV1Error::HasSessions);
|
||||||
|
}
|
||||||
|
self.destroyed.set(true);
|
||||||
|
self.client.remove_obj(self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_session(&self, req: CreateSession, slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let obj = Rc::new(JayHeadManagerSessionV1 {
|
||||||
|
id: req.session,
|
||||||
|
mgr: slf.clone(),
|
||||||
|
client: self.client.clone(),
|
||||||
|
tracker: Default::default(),
|
||||||
|
version: self.version,
|
||||||
|
common: Rc::new(HeadMgrCommon {
|
||||||
|
state: Default::default(),
|
||||||
|
in_transaction: Cell::new(false),
|
||||||
|
transaction_failed: Cell::new(false),
|
||||||
|
}),
|
||||||
|
serial: Default::default(),
|
||||||
|
heads: Default::default(),
|
||||||
|
ext: Default::default(),
|
||||||
|
});
|
||||||
|
track!(self.client, obj);
|
||||||
|
self.client.add_client_obj(&obj)?;
|
||||||
|
self.sessions.fetch_add(1);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_base! {
|
||||||
|
self = JayHeadManagerV1;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for JayHeadManagerV1 {}
|
||||||
|
|
||||||
|
simple_add_obj!(JayHeadManagerV1);
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum JayHeadManagerV1Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientError(Box<ClientError>),
|
||||||
|
#[error("Manager still has sessions")]
|
||||||
|
HasSessions,
|
||||||
|
}
|
||||||
|
efrom!(JayHeadManagerV1Error, ClientError);
|
||||||
82
src/ifs/head_management/jay_head_transaction_result_v1.rs
Normal file
82
src/ifs/head_management/jay_head_transaction_result_v1.rs
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
client::{Client, ClientError},
|
||||||
|
ifs::head_management::{HeadTransactionError, jay_head_error_v1::JayHeadErrorV1},
|
||||||
|
leaks::Tracker,
|
||||||
|
object::{Object, Version},
|
||||||
|
wire::{JayHeadTransactionResultV1Id, jay_head_transaction_result_v1::*},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(super) struct JayHeadTransactionResultV1 {
|
||||||
|
pub(super) id: JayHeadTransactionResultV1Id,
|
||||||
|
pub(super) client: Rc<Client>,
|
||||||
|
pub(super) tracker: Tracker<Self>,
|
||||||
|
pub(super) version: Version,
|
||||||
|
pub(super) error: Option<Rc<HeadTransactionError>>,
|
||||||
|
pub(super) destroyed: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadTransactionResultV1 {
|
||||||
|
pub(super) fn send(&self) {
|
||||||
|
match self.error {
|
||||||
|
None => self.send_success(),
|
||||||
|
_ => self.send_failed(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_success(&self) {
|
||||||
|
self.client.event(Success { self_id: self.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_failed(&self) {
|
||||||
|
self.client.event(Failed { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadTransactionResultV1RequestHandler for JayHeadTransactionResultV1 {
|
||||||
|
type Error = JayHeadTransactionResultV1Error;
|
||||||
|
|
||||||
|
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.client.remove_obj(self)?;
|
||||||
|
self.destroyed.set(true);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_error(&self, req: GetError, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let Some(err) = &self.error else {
|
||||||
|
return Err(JayHeadTransactionResultV1Error::NoError);
|
||||||
|
};
|
||||||
|
let err = Rc::new(JayHeadErrorV1 {
|
||||||
|
id: req.error,
|
||||||
|
client: self.client.clone(),
|
||||||
|
tracker: Default::default(),
|
||||||
|
version: self.version,
|
||||||
|
error: err.clone(),
|
||||||
|
});
|
||||||
|
track!(self.client, err);
|
||||||
|
self.client.add_client_obj(&err)?;
|
||||||
|
err.send();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_base! {
|
||||||
|
self = JayHeadTransactionResultV1;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for JayHeadTransactionResultV1 {}
|
||||||
|
|
||||||
|
simple_add_obj!(JayHeadTransactionResultV1);
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum JayHeadTransactionResultV1Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientError(Box<ClientError>),
|
||||||
|
#[error("The transaction result was success")]
|
||||||
|
NoError,
|
||||||
|
}
|
||||||
|
efrom!(JayHeadTransactionResultV1Error, ClientError);
|
||||||
55
src/ifs/head_management/jay_head_v1.rs
Normal file
55
src/ifs/head_management/jay_head_v1.rs
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
use {
|
||||||
|
super::HeadCommon,
|
||||||
|
crate::{
|
||||||
|
client::{Client, ClientError},
|
||||||
|
ifs::head_management::HeadCommonError,
|
||||||
|
leaks::Tracker,
|
||||||
|
object::{Object, Version},
|
||||||
|
wire::{JayHeadV1Id, jay_head_v1::*},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(super) struct JayHeadV1 {
|
||||||
|
pub(super) id: JayHeadV1Id,
|
||||||
|
pub(super) client: Rc<Client>,
|
||||||
|
pub(super) tracker: Tracker<Self>,
|
||||||
|
pub(super) version: Version,
|
||||||
|
pub(super) common: Rc<HeadCommon>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadV1 {
|
||||||
|
pub(super) fn send_removed(&self) {
|
||||||
|
self.common.removed.set(true);
|
||||||
|
self.client.event(Removed { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayHeadV1RequestHandler for JayHeadV1 {
|
||||||
|
type Error = JayHeadV1Error;
|
||||||
|
|
||||||
|
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.common.assert_removed()?;
|
||||||
|
self.client.remove_obj(self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_base! {
|
||||||
|
self = JayHeadV1;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for JayHeadV1 {}
|
||||||
|
|
||||||
|
simple_add_obj!(JayHeadV1);
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum JayHeadV1Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientError(Box<ClientError>),
|
||||||
|
#[error(transparent)]
|
||||||
|
Common(#[from] HeadCommonError),
|
||||||
|
}
|
||||||
|
efrom!(JayHeadV1Error, ClientError);
|
||||||
|
|
@ -419,8 +419,7 @@ impl JayRandrRequestHandler for JayRandr {
|
||||||
let Some(c) = self.get_output_node(req.output) else {
|
let Some(c) = self.get_output_node(req.output) else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
c.global.persistent.vrr_mode.set(mode);
|
c.set_vrr_mode(mode);
|
||||||
c.update_presentation_type();
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -447,8 +446,7 @@ impl JayRandrRequestHandler for JayRandr {
|
||||||
let Some(c) = self.get_output_node(req.output) else {
|
let Some(c) = self.get_output_node(req.output) else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
c.global.persistent.tearing_mode.set(mode);
|
c.set_tearing_mode(mode);
|
||||||
c.update_presentation_type();
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ impl WpDrmLeaseDeviceV1Global {
|
||||||
}
|
}
|
||||||
for c in dev.connectors.lock().keys() {
|
for c in dev.connectors.lock().keys() {
|
||||||
if let Some(o) = client.state.outputs.get(c)
|
if let Some(o) = client.state.outputs.get(c)
|
||||||
&& o.monitor_info.non_desktop
|
&& o.monitor_info.non_desktop_effective
|
||||||
{
|
{
|
||||||
obj.create_connector(&o);
|
obj.create_connector(&o);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,7 @@ impl TestBackend {
|
||||||
width_mm: 80,
|
width_mm: 80,
|
||||||
height_mm: 60,
|
height_mm: 60,
|
||||||
non_desktop: false,
|
non_desktop: false,
|
||||||
|
non_desktop_effective: false,
|
||||||
vrr_capable: false,
|
vrr_capable: false,
|
||||||
transfer_functions: vec![],
|
transfer_functions: vec![],
|
||||||
color_spaces: vec![],
|
color_spaces: vec![],
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
width_mm: 0,
|
width_mm: 0,
|
||||||
height_mm: 0,
|
height_mm: 0,
|
||||||
non_desktop: false,
|
non_desktop: false,
|
||||||
|
non_desktop_effective: false,
|
||||||
vrr_capable: false,
|
vrr_capable: false,
|
||||||
transfer_functions: vec![],
|
transfer_functions: vec![],
|
||||||
color_spaces: vec![],
|
color_spaces: vec![],
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ impl Default for Scale {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scale {
|
impl Scale {
|
||||||
pub fn from_int(f: u32) -> Self {
|
pub const fn from_int(f: u32) -> Self {
|
||||||
Self(f.saturating_mul(BASE))
|
Self(f.saturating_mul(BASE))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31,7 +31,7 @@ impl Scale {
|
||||||
self.0.saturating_add(BASE - 1) / BASE
|
self.0.saturating_add(BASE - 1) / BASE
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_wl(wl: u32) -> Self {
|
pub const fn from_wl(wl: u32) -> Self {
|
||||||
Self(wl)
|
Self(wl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
59
src/state.rs
59
src/state.rs
|
|
@ -40,6 +40,10 @@ use {
|
||||||
ext_foreign_toplevel_list_v1::ExtForeignToplevelListV1,
|
ext_foreign_toplevel_list_v1::ExtForeignToplevelListV1,
|
||||||
ext_idle_notification_v1::ExtIdleNotificationV1,
|
ext_idle_notification_v1::ExtIdleNotificationV1,
|
||||||
ext_session_lock_v1::ExtSessionLockV1,
|
ext_session_lock_v1::ExtSessionLockV1,
|
||||||
|
head_management::{
|
||||||
|
HeadManagers, HeadNames,
|
||||||
|
jay_head_manager_session_v1::{HeadManagerEvent, JayHeadManagerSessionV1},
|
||||||
|
},
|
||||||
ipc::{
|
ipc::{
|
||||||
DataOfferIds, DataSourceIds, data_control::DataControlDeviceIds,
|
DataOfferIds, DataSourceIds, data_control::DataControlDeviceIds,
|
||||||
x_data_device::XIpcDeviceIds,
|
x_data_device::XIpcDeviceIds,
|
||||||
|
|
@ -107,8 +111,9 @@ use {
|
||||||
},
|
},
|
||||||
wheel::Wheel,
|
wheel::Wheel,
|
||||||
wire::{
|
wire::{
|
||||||
ExtForeignToplevelListV1Id, ExtIdleNotificationV1Id, JayRenderCtxId, JaySeatEventsId,
|
ExtForeignToplevelListV1Id, ExtIdleNotificationV1Id, JayHeadManagerSessionV1Id,
|
||||||
JayWorkspaceWatcherId, ZwlrForeignToplevelManagerV1Id, ZwpLinuxDmabufFeedbackV1Id,
|
JayRenderCtxId, JaySeatEventsId, JayWorkspaceWatcherId, ZwlrForeignToplevelManagerV1Id,
|
||||||
|
ZwpLinuxDmabufFeedbackV1Id,
|
||||||
},
|
},
|
||||||
xwayland::{self, XWaylandEvent},
|
xwayland::{self, XWaylandEvent},
|
||||||
},
|
},
|
||||||
|
|
@ -257,6 +262,10 @@ pub struct State {
|
||||||
pub node_at_tree: RefCell<Vec<FoundNode>>,
|
pub node_at_tree: RefCell<Vec<FoundNode>>,
|
||||||
pub position_hint_requests: AsyncQueue<PositionHintRequest>,
|
pub position_hint_requests: AsyncQueue<PositionHintRequest>,
|
||||||
pub backend_connector_state_serials: BackendConnectorStateSerials,
|
pub backend_connector_state_serials: BackendConnectorStateSerials,
|
||||||
|
pub head_names: HeadNames,
|
||||||
|
pub head_managers:
|
||||||
|
CopyHashMap<(ClientId, JayHeadManagerSessionV1Id), Rc<JayHeadManagerSessionV1>>,
|
||||||
|
pub head_managers_async: AsyncQueue<HeadManagerEvent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl Drop for State {
|
// impl Drop for State {
|
||||||
|
|
@ -368,10 +377,11 @@ pub struct DeviceHandlerData {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ConnectorData {
|
pub struct ConnectorData {
|
||||||
|
pub id: ConnectorId,
|
||||||
pub connector: Rc<dyn Connector>,
|
pub connector: Rc<dyn Connector>,
|
||||||
pub handler: Cell<Option<SpawnedFuture<()>>>,
|
pub handler: Cell<Option<SpawnedFuture<()>>>,
|
||||||
pub connected: Cell<bool>,
|
pub connected: Cell<bool>,
|
||||||
pub name: String,
|
pub name: Rc<String>,
|
||||||
pub drm_dev: Option<Rc<DrmDevData>>,
|
pub drm_dev: Option<Rc<DrmDevData>>,
|
||||||
pub async_event: Rc<AsyncEvent>,
|
pub async_event: Rc<AsyncEvent>,
|
||||||
pub damaged: Cell<bool>,
|
pub damaged: Cell<bool>,
|
||||||
|
|
@ -379,11 +389,12 @@ pub struct ConnectorData {
|
||||||
pub needs_vblank_emulation: Cell<bool>,
|
pub needs_vblank_emulation: Cell<bool>,
|
||||||
pub damage_intersect: Cell<Rect>,
|
pub damage_intersect: Cell<Rect>,
|
||||||
pub state: Cell<BackendConnectorState>,
|
pub state: Cell<BackendConnectorState>,
|
||||||
|
pub head_managers: HeadManagers,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OutputData {
|
pub struct OutputData {
|
||||||
pub connector: Rc<ConnectorData>,
|
pub connector: Rc<ConnectorData>,
|
||||||
pub monitor_info: MonitorInfo,
|
pub monitor_info: Rc<MonitorInfo>,
|
||||||
pub node: Option<Rc<OutputNode>>,
|
pub node: Option<Rc<OutputNode>>,
|
||||||
pub lease_connectors: Rc<Bindings<WpDrmLeaseConnectorV1>>,
|
pub lease_connectors: Rc<Bindings<WpDrmLeaseConnectorV1>>,
|
||||||
}
|
}
|
||||||
|
|
@ -422,14 +433,44 @@ impl ConnectorData {
|
||||||
let mut tran = self.connector.create_transaction()?;
|
let mut tran = self.connector.create_transaction()?;
|
||||||
tran.add(&self.connector, s)?;
|
tran.add(&self.connector, s)?;
|
||||||
tran.prepare()?.apply()?.commit();
|
tran.prepare()?.apply()?.commit();
|
||||||
|
self.set_state(state, s);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_state(&self, state: &State, s: BackendConnectorState) {
|
||||||
|
let old = self.state.get();
|
||||||
|
if old.serial >= s.serial {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.state.set(s);
|
||||||
|
if old.enabled != s.enabled {
|
||||||
|
self.head_managers.handle_enabled_change(s.enabled);
|
||||||
|
}
|
||||||
|
if old.active != s.active {
|
||||||
|
self.head_managers.handle_active_change(s.active);
|
||||||
|
}
|
||||||
|
if old.non_desktop_override != s.non_desktop_override {
|
||||||
|
self.head_managers
|
||||||
|
.handle_non_desktop_override_changed(s.non_desktop_override);
|
||||||
|
}
|
||||||
|
if old.vrr != s.vrr {
|
||||||
|
self.head_managers.handle_vrr_change(s.vrr);
|
||||||
|
}
|
||||||
|
if old.tearing != s.tearing {
|
||||||
|
self.head_managers.handle_tearing_enabled_change(s.tearing);
|
||||||
|
}
|
||||||
|
if old.format != s.format {
|
||||||
|
self.head_managers.handle_format_change(s.format);
|
||||||
|
}
|
||||||
|
if (old.color_space, old.transfer_function) != (s.color_space, s.transfer_function) {
|
||||||
|
self.head_managers
|
||||||
|
.handle_colors_change(s.color_space, s.transfer_function);
|
||||||
|
}
|
||||||
if let Some(output) = state.outputs.get(&self.connector.id())
|
if let Some(output) = state.outputs.get(&self.connector.id())
|
||||||
&& let Some(node) = &output.node
|
&& let Some(node) = &output.node
|
||||||
{
|
{
|
||||||
node.update_state(s);
|
node.update_state(old, s);
|
||||||
} else {
|
|
||||||
self.state.set(s);
|
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1010,6 +1051,8 @@ impl State {
|
||||||
self.tl_matcher_manager.clear();
|
self.tl_matcher_manager.clear();
|
||||||
self.node_at_tree.borrow_mut().clear();
|
self.node_at_tree.borrow_mut().clear();
|
||||||
self.position_hint_requests.clear();
|
self.position_hint_requests.clear();
|
||||||
|
self.head_managers.clear();
|
||||||
|
self.head_managers_async.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_toplevel_id(&self, id: ToplevelIdentifier) {
|
pub fn remove_toplevel_id(&self, id: ToplevelIdentifier) {
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,18 @@ use {
|
||||||
format::XRGB8888,
|
format::XRGB8888,
|
||||||
globals::GlobalName,
|
globals::GlobalName,
|
||||||
ifs::{
|
ifs::{
|
||||||
|
head_management::{HeadManagers, HeadState},
|
||||||
jay_tray_v1::JayTrayV1Global,
|
jay_tray_v1::JayTrayV1Global,
|
||||||
wl_output::{PersistentOutputState, WlOutputGlobal},
|
wl_output::{PersistentOutputState, WlOutputGlobal},
|
||||||
},
|
},
|
||||||
output_schedule::OutputSchedule,
|
output_schedule::OutputSchedule,
|
||||||
state::{ConnectorData, OutputData, State},
|
state::{ConnectorData, OutputData, State},
|
||||||
tree::{OutputNode, WsMoveConfig, move_ws_to_output},
|
tree::{OutputNode, WsMoveConfig, move_ws_to_output},
|
||||||
utils::{asyncevent::AsyncEvent, clonecell::CloneCell, hash_map_ext::HashMapExt},
|
utils::{
|
||||||
|
asyncevent::AsyncEvent, clonecell::CloneCell, hash_map_ext::HashMapExt, rc_eq::RcEq,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
jay_config::video::Transform,
|
||||||
std::{cell::Cell, collections::VecDeque, rc::Rc},
|
std::{cell::Cell, collections::VecDeque, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -39,11 +43,39 @@ pub fn handle(state: &Rc<State>, connector: &Rc<dyn Connector>) {
|
||||||
transfer_function: Default::default(),
|
transfer_function: Default::default(),
|
||||||
};
|
};
|
||||||
let id = connector.id();
|
let id = connector.id();
|
||||||
|
let name = Rc::new(connector.kernel_id().to_string());
|
||||||
|
let head_state = HeadState {
|
||||||
|
name: RcEq(name.clone()),
|
||||||
|
position: (0, 0),
|
||||||
|
size: (0, 0),
|
||||||
|
active: backend_state.active,
|
||||||
|
connected: false,
|
||||||
|
transform: Transform::None,
|
||||||
|
scale: Default::default(),
|
||||||
|
wl_output: None,
|
||||||
|
connector_enabled: backend_state.enabled,
|
||||||
|
in_compositor_space: false,
|
||||||
|
mode: Default::default(),
|
||||||
|
monitor_info: None,
|
||||||
|
inherent_non_desktop: false,
|
||||||
|
override_non_desktop: backend_state.non_desktop_override,
|
||||||
|
vrr: backend_state.vrr,
|
||||||
|
vrr_mode: Default::default(),
|
||||||
|
tearing_enabled: backend_state.tearing,
|
||||||
|
tearing_active: false,
|
||||||
|
tearing_mode: Default::default(),
|
||||||
|
format: backend_state.format,
|
||||||
|
color_space: backend_state.color_space,
|
||||||
|
transfer_function: backend_state.transfer_function,
|
||||||
|
supported_formats: Default::default(),
|
||||||
|
brightness: None,
|
||||||
|
};
|
||||||
let data = Rc::new(ConnectorData {
|
let data = Rc::new(ConnectorData {
|
||||||
|
id,
|
||||||
connector: connector.clone(),
|
connector: connector.clone(),
|
||||||
handler: Default::default(),
|
handler: Default::default(),
|
||||||
connected: Cell::new(false),
|
connected: Cell::new(false),
|
||||||
name: connector.kernel_id().to_string(),
|
name,
|
||||||
drm_dev: drm_dev.clone(),
|
drm_dev: drm_dev.clone(),
|
||||||
async_event: Rc::new(AsyncEvent::default()),
|
async_event: Rc::new(AsyncEvent::default()),
|
||||||
damaged: Cell::new(false),
|
damaged: Cell::new(false),
|
||||||
|
|
@ -51,6 +83,7 @@ pub fn handle(state: &Rc<State>, connector: &Rc<dyn Connector>) {
|
||||||
needs_vblank_emulation: Cell::new(false),
|
needs_vblank_emulation: Cell::new(false),
|
||||||
damage_intersect: Default::default(),
|
damage_intersect: Default::default(),
|
||||||
state: Cell::new(backend_state),
|
state: Cell::new(backend_state),
|
||||||
|
head_managers: HeadManagers::new(state.head_names.next(), head_state),
|
||||||
});
|
});
|
||||||
if let Some(dev) = drm_dev {
|
if let Some(dev) = drm_dev {
|
||||||
dev.connectors.set(id, data.clone());
|
dev.connectors.set(id, data.clone());
|
||||||
|
|
@ -62,6 +95,9 @@ pub fn handle(state: &Rc<State>, connector: &Rc<dyn Connector>) {
|
||||||
};
|
};
|
||||||
let future = state.eng.spawn("connector handler", oh.handle());
|
let future = state.eng.spawn("connector handler", oh.handle());
|
||||||
data.handler.set(Some(future));
|
data.handler.set(Some(future));
|
||||||
|
for mgr in state.head_managers.lock().values() {
|
||||||
|
mgr.announce(&data);
|
||||||
|
}
|
||||||
if state.connectors.set(id, data).is_some() {
|
if state.connectors.set(id, data).is_some() {
|
||||||
panic!("Connector id has been reused");
|
panic!("Connector id has been reused");
|
||||||
}
|
}
|
||||||
|
|
@ -100,22 +136,21 @@ impl ConnectorHandler {
|
||||||
}
|
}
|
||||||
self.data.handler.set(None);
|
self.data.handler.set(None);
|
||||||
self.state.connectors.remove(&self.id);
|
self.state.connectors.remove(&self.id);
|
||||||
|
self.data.head_managers.handle_removed();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_connected(&self, info: MonitorInfo) {
|
async fn handle_connected(&self, info: MonitorInfo) {
|
||||||
log::info!("Connector {} connected", self.data.connector.kernel_id());
|
log::info!("Connector {} connected", self.data.connector.kernel_id());
|
||||||
self.data.connected.set(true);
|
self.data.connected.set(true);
|
||||||
let old_state = self.data.state.get();
|
self.data.set_state(&self.state, info.state);
|
||||||
if old_state.serial < info.state.serial {
|
|
||||||
self.data.state.set(info.state);
|
|
||||||
}
|
|
||||||
let name = self.state.globals.name();
|
let name = self.state.globals.name();
|
||||||
if info.non_desktop {
|
if info.non_desktop_effective {
|
||||||
self.handle_non_desktop_connected(info).await;
|
self.handle_non_desktop_connected(info).await;
|
||||||
} else {
|
} else {
|
||||||
self.handle_desktop_connected(info, name).await;
|
self.handle_desktop_connected(info, name).await;
|
||||||
}
|
}
|
||||||
self.data.connected.set(false);
|
self.data.connected.set(false);
|
||||||
|
self.data.head_managers.handle_output_disconnected();
|
||||||
log::info!("Connector {} disconnected", self.data.connector.kernel_id());
|
log::info!("Connector {} disconnected", self.data.connector.kernel_id());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,6 +249,7 @@ impl ConnectorHandler {
|
||||||
tray_items: Default::default(),
|
tray_items: Default::default(),
|
||||||
ext_workspace_groups: Default::default(),
|
ext_workspace_groups: Default::default(),
|
||||||
pinned: Default::default(),
|
pinned: Default::default(),
|
||||||
|
tearing: Default::default(),
|
||||||
});
|
});
|
||||||
on.update_visible();
|
on.update_visible();
|
||||||
on.update_rects();
|
on.update_rects();
|
||||||
|
|
@ -221,11 +257,11 @@ impl ConnectorHandler {
|
||||||
.add_output_scale(on.global.persistent.scale.get());
|
.add_output_scale(on.global.persistent.scale.get());
|
||||||
let output_data = Rc::new(OutputData {
|
let output_data = Rc::new(OutputData {
|
||||||
connector: self.data.clone(),
|
connector: self.data.clone(),
|
||||||
monitor_info: info,
|
monitor_info: Rc::new(info),
|
||||||
node: Some(on.clone()),
|
node: Some(on.clone()),
|
||||||
lease_connectors: Default::default(),
|
lease_connectors: Default::default(),
|
||||||
});
|
});
|
||||||
self.state.outputs.set(self.id, output_data);
|
self.state.outputs.set(self.id, output_data.clone());
|
||||||
on.schedule_update_render_data();
|
on.schedule_update_render_data();
|
||||||
self.state.root.outputs.set(self.id, on.clone());
|
self.state.root.outputs.set(self.id, on.clone());
|
||||||
self.state.output_extents_changed();
|
self.state.output_extents_changed();
|
||||||
|
|
@ -277,6 +313,9 @@ impl ConnectorHandler {
|
||||||
self.state.tree_changed();
|
self.state.tree_changed();
|
||||||
on.update_presentation_type();
|
on.update_presentation_type();
|
||||||
self.state.workspace_managers.announce_output(&on);
|
self.state.workspace_managers.announce_output(&on);
|
||||||
|
self.data
|
||||||
|
.head_managers
|
||||||
|
.handle_output_connected(&output_data);
|
||||||
'outer: loop {
|
'outer: loop {
|
||||||
while let Some(event) = self.data.connector.event() {
|
while let Some(event) = self.data.connector.event() {
|
||||||
match event {
|
match event {
|
||||||
|
|
@ -287,10 +326,11 @@ impl ConnectorHandler {
|
||||||
self.state.refresh_hardware_cursors();
|
self.state.refresh_hardware_cursors();
|
||||||
}
|
}
|
||||||
ConnectorEvent::FormatsChanged(formats) => {
|
ConnectorEvent::FormatsChanged(formats) => {
|
||||||
|
self.data.head_managers.handle_formats_change(&formats);
|
||||||
on.global.formats.set(formats);
|
on.global.formats.set(formats);
|
||||||
}
|
}
|
||||||
ConnectorEvent::State(state) => {
|
ConnectorEvent::State(state) => {
|
||||||
on.update_state(state);
|
self.data.set_state(&self.state, state);
|
||||||
}
|
}
|
||||||
ev => unreachable!("received unexpected event {:?}", ev),
|
ev => unreachable!("received unexpected event {:?}", ev),
|
||||||
}
|
}
|
||||||
|
|
@ -365,7 +405,7 @@ impl ConnectorHandler {
|
||||||
async fn handle_non_desktop_connected(&self, monitor_info: MonitorInfo) {
|
async fn handle_non_desktop_connected(&self, monitor_info: MonitorInfo) {
|
||||||
let output_data = Rc::new(OutputData {
|
let output_data = Rc::new(OutputData {
|
||||||
connector: self.data.clone(),
|
connector: self.data.clone(),
|
||||||
monitor_info,
|
monitor_info: Rc::new(monitor_info),
|
||||||
node: None,
|
node: None,
|
||||||
lease_connectors: Default::default(),
|
lease_connectors: Default::default(),
|
||||||
});
|
});
|
||||||
|
|
@ -390,6 +430,9 @@ impl ConnectorHandler {
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
self.data
|
||||||
|
.head_managers
|
||||||
|
.handle_output_connected(&output_data);
|
||||||
'outer: loop {
|
'outer: loop {
|
||||||
while let Some(event) = self.data.connector.event() {
|
while let Some(event) = self.data.connector.event() {
|
||||||
match event {
|
match event {
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ impl Idle {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_set_idle(&self, idle: bool) -> Result<(), BackendConnectorTransactionError> {
|
fn try_set_idle(&self, idle: bool) -> Result<(), BackendConnectorTransactionError> {
|
||||||
let mut tran = ConnectorTransaction::default();
|
let mut tran = ConnectorTransaction::new(&self.state);
|
||||||
for connector in self.state.connectors.lock().values() {
|
for connector in self.state.connectors.lock().values() {
|
||||||
let mut state = connector.state.get();
|
let mut state = connector.state.get();
|
||||||
state.active = !idle;
|
state.active = !idle;
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ use {
|
||||||
ext_workspace_manager_v1::WorkspaceManagerId,
|
ext_workspace_manager_v1::WorkspaceManagerId,
|
||||||
},
|
},
|
||||||
wp_content_type_v1::ContentType,
|
wp_content_type_v1::ContentType,
|
||||||
|
wp_presentation_feedback::KIND_VSYNC,
|
||||||
zwlr_layer_shell_v1::{BACKGROUND, BOTTOM, OVERLAY, TOP},
|
zwlr_layer_shell_v1::{BACKGROUND, BOTTOM, OVERLAY, TOP},
|
||||||
zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1,
|
zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1,
|
||||||
},
|
},
|
||||||
|
|
@ -47,10 +48,10 @@ use {
|
||||||
WorkspaceNodeId, walker::NodeVisitor,
|
WorkspaceNodeId, walker::NodeVisitor,
|
||||||
},
|
},
|
||||||
utils::{
|
utils::{
|
||||||
asyncevent::AsyncEvent, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
asyncevent::AsyncEvent, bitflags::BitflagsExt, clonecell::CloneCell,
|
||||||
errorfmt::ErrorFmt, event_listener::EventSource, hash_map_ext::HashMapExt,
|
copyhashmap::CopyHashMap, errorfmt::ErrorFmt, event_listener::EventSource,
|
||||||
linkedlist::LinkedList, on_drop_event::OnDropEvent, scroller::Scroller,
|
hash_map_ext::HashMapExt, linkedlist::LinkedList, on_drop_event::OnDropEvent,
|
||||||
transform_ext::TransformExt,
|
scroller::Scroller, transform_ext::TransformExt,
|
||||||
},
|
},
|
||||||
wire::{
|
wire::{
|
||||||
ExtImageCopyCaptureSessionV1Id, JayOutputId, JayScreencastId, ZwlrScreencopyFrameV1Id,
|
ExtImageCopyCaptureSessionV1Id, JayOutputId, JayScreencastId, ZwlrScreencopyFrameV1Id,
|
||||||
|
|
@ -107,6 +108,7 @@ pub struct OutputNode {
|
||||||
pub tray_items: LinkedList<Rc<dyn DynTrayItem>>,
|
pub tray_items: LinkedList<Rc<dyn DynTrayItem>>,
|
||||||
pub ext_workspace_groups: CopyHashMap<WorkspaceManagerId, Rc<ExtWorkspaceGroupHandleV1>>,
|
pub ext_workspace_groups: CopyHashMap<WorkspaceManagerId, Rc<ExtWorkspaceGroupHandleV1>>,
|
||||||
pub pinned: LinkedList<Rc<dyn PinnedNode>>,
|
pub pinned: LinkedList<Rc<dyn PinnedNode>>,
|
||||||
|
pub tearing: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
|
|
@ -218,6 +220,13 @@ impl OutputNode {
|
||||||
if locked && let Some(lock) = self.state.lock.lock.get() {
|
if locked && let Some(lock) = self.state.lock.lock.get() {
|
||||||
lock.check_locked()
|
lock.check_locked()
|
||||||
}
|
}
|
||||||
|
let tearing = flags.not_contains(KIND_VSYNC);
|
||||||
|
if self.tearing.replace(tearing) != tearing {
|
||||||
|
self.global
|
||||||
|
.connector
|
||||||
|
.head_managers
|
||||||
|
.handle_tearing_active_change(tearing);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_exclusive_zones(self: &Rc<Self>) {
|
pub fn update_exclusive_zones(self: &Rc<Self>) {
|
||||||
|
|
@ -470,6 +479,10 @@ impl OutputNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.schedule_update_render_data();
|
self.schedule_update_render_data();
|
||||||
|
self.global
|
||||||
|
.connector
|
||||||
|
.head_managers
|
||||||
|
.handle_scale_change(scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn schedule_update_render_data(self: &Rc<Self>) {
|
pub fn schedule_update_render_data(self: &Rc<Self>) {
|
||||||
|
|
@ -800,18 +813,30 @@ impl OutputNode {
|
||||||
if transform != old_transform {
|
if transform != old_transform {
|
||||||
self.state.refresh_hardware_cursors();
|
self.state.refresh_hardware_cursors();
|
||||||
self.node_visit_children(&mut SurfaceSendPreferredTransformVisitor);
|
self.node_visit_children(&mut SurfaceSendPreferredTransformVisitor);
|
||||||
|
self.global
|
||||||
|
.connector
|
||||||
|
.head_managers
|
||||||
|
.handle_transform_change(transform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_extents(&self) -> Rect {
|
fn calculate_extents(&self) -> Rect {
|
||||||
let mode = self.global.mode.get();
|
Self::calculate_extents_(
|
||||||
let (width, height) = calculate_logical_size(
|
self.global.mode.get(),
|
||||||
(mode.width, mode.height),
|
|
||||||
self.global.persistent.transform.get(),
|
self.global.persistent.transform.get(),
|
||||||
self.global.persistent.scale.get(),
|
self.global.persistent.scale.get(),
|
||||||
);
|
self.global.pos.get().position(),
|
||||||
let pos = self.global.pos.get();
|
)
|
||||||
pos.with_size(width, height).unwrap()
|
}
|
||||||
|
|
||||||
|
pub fn calculate_extents_(
|
||||||
|
mode: Mode,
|
||||||
|
transform: Transform,
|
||||||
|
scale: Scale,
|
||||||
|
pos: (i32, i32),
|
||||||
|
) -> Rect {
|
||||||
|
let (width, height) = calculate_logical_size((mode.width, mode.height), transform, scale);
|
||||||
|
Rect::new_sized(pos.0, pos.1, width, height).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_extents_(self: &Rc<Self>, rect: &Rect) {
|
fn change_extents_(self: &Rc<Self>, rect: &Rect) {
|
||||||
|
|
@ -847,14 +872,13 @@ impl OutputNode {
|
||||||
seat.cursor_group().output_pos_changed(self)
|
seat.cursor_group().output_pos_changed(self)
|
||||||
}
|
}
|
||||||
self.state.tree_changed();
|
self.state.tree_changed();
|
||||||
|
self.global
|
||||||
|
.connector
|
||||||
|
.head_managers
|
||||||
|
.handle_position_size_change(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_state(self: &Rc<Self>, state: BackendConnectorState) {
|
pub fn update_state(self: &Rc<Self>, old: BackendConnectorState, state: BackendConnectorState) {
|
||||||
let old = self.global.connector.state.get();
|
|
||||||
if old.serial >= state.serial {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.global.connector.state.set(state);
|
|
||||||
self.update_btf_and_bcs(state.transfer_function, state.color_space);
|
self.update_btf_and_bcs(state.transfer_function, state.color_space);
|
||||||
if old.vrr != state.vrr {
|
if old.vrr != state.vrr {
|
||||||
self.schedule.set_vrr_enabled(state.vrr);
|
self.schedule.set_vrr_enabled(state.vrr);
|
||||||
|
|
@ -889,8 +913,14 @@ impl OutputNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_brightness(&self, brightness: Option<f64>) {
|
pub fn set_brightness(&self, brightness: Option<f64>) {
|
||||||
self.global.persistent.brightness.set(brightness);
|
let old = self.global.persistent.brightness.replace(brightness);
|
||||||
self.update_color_description();
|
if old != brightness {
|
||||||
|
self.update_color_description();
|
||||||
|
self.global
|
||||||
|
.connector
|
||||||
|
.head_managers
|
||||||
|
.handle_brightness_change(brightness);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_stacked_at(
|
fn find_stacked_at(
|
||||||
|
|
@ -1300,6 +1330,28 @@ impl OutputNode {
|
||||||
}
|
}
|
||||||
self.state.tree_changed();
|
self.state.tree_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_vrr_mode(&self, mode: &'static VrrMode) {
|
||||||
|
let old = self.global.persistent.vrr_mode.replace(mode);
|
||||||
|
if old != mode {
|
||||||
|
self.update_presentation_type();
|
||||||
|
self.global
|
||||||
|
.connector
|
||||||
|
.head_managers
|
||||||
|
.handle_vrr_mode_change(mode.to_config());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_tearing_mode(&self, mode: &'static TearingMode) {
|
||||||
|
let old = self.global.persistent.tearing_mode.replace(mode);
|
||||||
|
if old != mode {
|
||||||
|
self.update_presentation_type();
|
||||||
|
self.global
|
||||||
|
.connector
|
||||||
|
.head_managers
|
||||||
|
.handle_tearing_mode_change(mode.to_config());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OutputTitle {
|
pub struct OutputTitle {
|
||||||
|
|
@ -1750,13 +1802,13 @@ impl TearingMode {
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_config(&self) -> ConfigVrrMode {
|
pub fn to_config(&self) -> ConfigTearingMode {
|
||||||
match self {
|
match self {
|
||||||
Self::NEVER => ConfigVrrMode::NEVER,
|
Self::NEVER => ConfigTearingMode::NEVER,
|
||||||
Self::ALWAYS => ConfigVrrMode::ALWAYS,
|
Self::ALWAYS => ConfigTearingMode::ALWAYS,
|
||||||
Self::VARIANT_1 => ConfigVrrMode::VARIANT_1,
|
Self::VARIANT_1 => ConfigTearingMode::VARIANT_1,
|
||||||
Self::VARIANT_2 => ConfigVrrMode::VARIANT_2,
|
Self::VARIANT_2 => ConfigTearingMode::VARIANT_2,
|
||||||
Self::VARIANT_3 => ConfigVrrMode::VARIANT_3,
|
Self::VARIANT_3 => ConfigTearingMode::VARIANT_3,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,14 @@ impl<K: Eq + Hash, V> CopyHashMap<K, V> {
|
||||||
unsafe { self.map.get().deref().contains_key(k) }
|
unsafe { self.map.get().deref().contains_key(k) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn not_contains<Q>(&self, k: &Q) -> bool
|
||||||
|
where
|
||||||
|
Q: Hash + Eq + ?Sized,
|
||||||
|
K: Borrow<Q>,
|
||||||
|
{
|
||||||
|
!self.contains(k)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn lock(&self) -> Locked<'_, K, V> {
|
pub fn lock(&self) -> Locked<'_, K, V> {
|
||||||
Locked {
|
Locked {
|
||||||
source: self,
|
source: self,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,30 @@
|
||||||
use std::rc::Rc;
|
use std::{ops::Deref, rc::Rc};
|
||||||
|
|
||||||
pub fn rc_eq<T: ?Sized>(a: &Rc<T>, b: &Rc<T>) -> bool {
|
pub fn rc_eq<T: ?Sized>(a: &Rc<T>, b: &Rc<T>) -> bool {
|
||||||
Rc::as_ptr(a) as *const u8 == Rc::as_ptr(b) as *const u8
|
Rc::as_ptr(a) as *const u8 == Rc::as_ptr(b) as *const u8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct RcEq<T>(pub Rc<T>);
|
||||||
|
|
||||||
|
impl<T> Clone for RcEq<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self(self.0.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PartialEq for RcEq<T> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
rc_eq(&self.0, &other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Eq for RcEq<T> {}
|
||||||
|
|
||||||
|
impl<T> Deref for RcEq<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
23
wire/jay_head_error_v1.txt
Normal file
23
wire/jay_head_error_v1.txt
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event message {
|
||||||
|
msg: str,
|
||||||
|
}
|
||||||
|
|
||||||
|
event already_failed {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event out_of_date {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event extension {
|
||||||
|
name: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
event done {
|
||||||
|
|
||||||
|
}
|
||||||
15
wire/jay_head_ext_brightness_info_v1.txt
Normal file
15
wire/jay_head_ext_brightness_info_v1.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event implied_default_brightness {
|
||||||
|
lux: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
event default_brightness {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event brightness {
|
||||||
|
lux: u32,
|
||||||
|
}
|
||||||
11
wire/jay_head_ext_brightness_setter_v1.txt
Normal file
11
wire/jay_head_ext_brightness_setter_v1.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
request unset_brightness {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
request set_brightness {
|
||||||
|
lux: u32,
|
||||||
|
}
|
||||||
11
wire/jay_head_ext_compositor_space_enabler_v1.txt
Normal file
11
wire/jay_head_ext_compositor_space_enabler_v1.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
request enable {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
request disable {
|
||||||
|
|
||||||
|
}
|
||||||
37
wire/jay_head_ext_compositor_space_info_v1.txt
Normal file
37
wire/jay_head_ext_compositor_space_info_v1.txt
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event enabled {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event disabled {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event inside {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event outside {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event position {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
event size {
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
event transform {
|
||||||
|
transform: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
event scaling {
|
||||||
|
scaling: u32,
|
||||||
|
}
|
||||||
15
wire/jay_head_ext_compositor_space_positioner_v1.txt
Normal file
15
wire/jay_head_ext_compositor_space_positioner_v1.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
request set_position {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
event range {
|
||||||
|
x_min: i32,
|
||||||
|
y_min: i32,
|
||||||
|
x_max: i32,
|
||||||
|
y_max: i32,
|
||||||
|
}
|
||||||
12
wire/jay_head_ext_compositor_space_scaler_v1.txt
Normal file
12
wire/jay_head_ext_compositor_space_scaler_v1.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
request set_scale {
|
||||||
|
scale: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
event range {
|
||||||
|
min: u32,
|
||||||
|
max: u32,
|
||||||
|
}
|
||||||
15
wire/jay_head_ext_compositor_space_transformer_v1.txt
Normal file
15
wire/jay_head_ext_compositor_space_transformer_v1.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
request set_transform {
|
||||||
|
transform: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
event reset_supported_transforms {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event supported_transform {
|
||||||
|
transform: u32,
|
||||||
|
}
|
||||||
19
wire/jay_head_ext_connector_info_v1.txt
Normal file
19
wire/jay_head_ext_connector_info_v1.txt
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event connected {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event disconnected {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event active {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event inactive {
|
||||||
|
|
||||||
|
}
|
||||||
15
wire/jay_head_ext_core_info_v1.txt
Normal file
15
wire/jay_head_ext_core_info_v1.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event wl_output {
|
||||||
|
global_name: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
event no_wl_output {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event name {
|
||||||
|
name: optstr,
|
||||||
|
}
|
||||||
11
wire/jay_head_ext_drm_color_space_info_v1.txt
Normal file
11
wire/jay_head_ext_drm_color_space_info_v1.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event hdmi_eotf {
|
||||||
|
eotf: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
event colorimetry {
|
||||||
|
colorimetry: u32,
|
||||||
|
}
|
||||||
23
wire/jay_head_ext_drm_color_space_setter_v1.txt
Normal file
23
wire/jay_head_ext_drm_color_space_setter_v1.txt
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event reset {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event supported_hdmi_eotf {
|
||||||
|
eotf: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
event supported_colorimetry {
|
||||||
|
colorimetry: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
request set_hdmi_eotf {
|
||||||
|
eotf: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
request set_colorimetry {
|
||||||
|
colorimetry: u32,
|
||||||
|
}
|
||||||
7
wire/jay_head_ext_format_info_v1.txt
Normal file
7
wire/jay_head_ext_format_info_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event format {
|
||||||
|
format: u32,
|
||||||
|
}
|
||||||
15
wire/jay_head_ext_format_setter_v1.txt
Normal file
15
wire/jay_head_ext_format_setter_v1.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event reset {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event supported_format {
|
||||||
|
format: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
request set_format {
|
||||||
|
format: u32,
|
||||||
|
}
|
||||||
7
wire/jay_head_ext_jay_tearing_mode_info_v1.txt
Normal file
7
wire/jay_head_ext_jay_tearing_mode_info_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event mode {
|
||||||
|
mode: u32,
|
||||||
|
}
|
||||||
15
wire/jay_head_ext_jay_tearing_mode_setter_v1.txt
Normal file
15
wire/jay_head_ext_jay_tearing_mode_setter_v1.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event reset {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event supported_mode {
|
||||||
|
mode: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
request set_mode {
|
||||||
|
mode: u32,
|
||||||
|
}
|
||||||
7
wire/jay_head_ext_jay_vrr_mode_info_v1.txt
Normal file
7
wire/jay_head_ext_jay_vrr_mode_info_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event mode {
|
||||||
|
mode: u32,
|
||||||
|
}
|
||||||
15
wire/jay_head_ext_jay_vrr_mode_setter_v1.txt
Normal file
15
wire/jay_head_ext_jay_vrr_mode_setter_v1.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event reset {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event supported_mode {
|
||||||
|
mode: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
request set_mode {
|
||||||
|
mode: u32,
|
||||||
|
}
|
||||||
9
wire/jay_head_ext_mode_info_v1.txt
Normal file
9
wire/jay_head_ext_mode_info_v1.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event mode {
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
refresh_mhz: u32,
|
||||||
|
}
|
||||||
17
wire/jay_head_ext_mode_setter_v1.txt
Normal file
17
wire/jay_head_ext_mode_setter_v1.txt
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
request set_mode {
|
||||||
|
idx: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
event reset {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event mode {
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
refresh_mhz: u32,
|
||||||
|
}
|
||||||
31
wire/jay_head_ext_non_desktop_info_v1.txt
Normal file
31
wire/jay_head_ext_non_desktop_info_v1.txt
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event reset {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event inherent_desktop {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event inherent_non_desktop {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event override_desktop {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event override_non_desktop {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event effective_desktop {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event effective_non_desktop {
|
||||||
|
|
||||||
|
}
|
||||||
15
wire/jay_head_ext_non_desktop_override_v1.txt
Normal file
15
wire/jay_head_ext_non_desktop_override_v1.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
request disable_override {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
request override_desktop {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
request override_non_desktop {
|
||||||
|
|
||||||
|
}
|
||||||
38
wire/jay_head_ext_physical_display_info_v1.txt
Normal file
38
wire/jay_head_ext_physical_display_info_v1.txt
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event reset {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event mode {
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
refresh_mhz: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
event physical_size {
|
||||||
|
width_mm: i32,
|
||||||
|
height_mm: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
event manufacturer {
|
||||||
|
manufacturer: str,
|
||||||
|
}
|
||||||
|
|
||||||
|
event model {
|
||||||
|
model: str,
|
||||||
|
}
|
||||||
|
|
||||||
|
event serial_number {
|
||||||
|
serial_number: str,
|
||||||
|
}
|
||||||
|
|
||||||
|
event non_desktop {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event vrr_capable {
|
||||||
|
|
||||||
|
}
|
||||||
19
wire/jay_head_ext_tearing_state_v1.txt
Normal file
19
wire/jay_head_ext_tearing_state_v1.txt
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event enabled {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event disabled {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event active {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event inactive {
|
||||||
|
|
||||||
|
}
|
||||||
15
wire/jay_head_ext_vrr_state_v1.txt
Normal file
15
wire/jay_head_ext_vrr_state_v1.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event reset {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event capable {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event enabled {
|
||||||
|
|
||||||
|
}
|
||||||
7
wire/jay_head_manager_ext_brightness_info_v1.txt
Normal file
7
wire/jay_head_manager_ext_brightness_info_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event head {
|
||||||
|
head: id(jay_head_ext_brightness_info_v1) (new),
|
||||||
|
}
|
||||||
7
wire/jay_head_manager_ext_brightness_setter_v1.txt
Normal file
7
wire/jay_head_manager_ext_brightness_setter_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event head {
|
||||||
|
head: id(jay_head_ext_brightness_setter_v1) (new),
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event head {
|
||||||
|
head: id(jay_head_ext_compositor_space_enabler_v1) (new),
|
||||||
|
}
|
||||||
7
wire/jay_head_manager_ext_compositor_space_info_v1.txt
Normal file
7
wire/jay_head_manager_ext_compositor_space_info_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event head {
|
||||||
|
head: id(jay_head_ext_compositor_space_info_v1) (new),
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event head {
|
||||||
|
head: id(jay_head_ext_compositor_space_positioner_v1) (new),
|
||||||
|
}
|
||||||
7
wire/jay_head_manager_ext_compositor_space_scaler_v1.txt
Normal file
7
wire/jay_head_manager_ext_compositor_space_scaler_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event head {
|
||||||
|
head: id(jay_head_ext_compositor_space_scaler_v1) (new),
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event head {
|
||||||
|
head: id(jay_head_ext_compositor_space_transformer_v1) (new),
|
||||||
|
}
|
||||||
7
wire/jay_head_manager_ext_connector_info_v1.txt
Normal file
7
wire/jay_head_manager_ext_connector_info_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event head {
|
||||||
|
head: id(jay_head_ext_connector_info_v1) (new),
|
||||||
|
}
|
||||||
7
wire/jay_head_manager_ext_core_info_v1.txt
Normal file
7
wire/jay_head_manager_ext_core_info_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event head {
|
||||||
|
head: id(jay_head_ext_core_info_v1) (new),
|
||||||
|
}
|
||||||
7
wire/jay_head_manager_ext_drm_color_space_info_v1.txt
Normal file
7
wire/jay_head_manager_ext_drm_color_space_info_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event head {
|
||||||
|
head: id(jay_head_ext_drm_color_space_info_v1) (new),
|
||||||
|
}
|
||||||
7
wire/jay_head_manager_ext_drm_color_space_setter_v1.txt
Normal file
7
wire/jay_head_manager_ext_drm_color_space_setter_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event head {
|
||||||
|
head: id(jay_head_ext_drm_color_space_setter_v1) (new),
|
||||||
|
}
|
||||||
7
wire/jay_head_manager_ext_format_info_v1.txt
Normal file
7
wire/jay_head_manager_ext_format_info_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event head {
|
||||||
|
head: id(jay_head_ext_format_info_v1) (new),
|
||||||
|
}
|
||||||
7
wire/jay_head_manager_ext_format_setter_v1.txt
Normal file
7
wire/jay_head_manager_ext_format_setter_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event head {
|
||||||
|
head: id(jay_head_ext_format_setter_v1) (new),
|
||||||
|
}
|
||||||
7
wire/jay_head_manager_ext_jay_tearing_mode_info_v1.txt
Normal file
7
wire/jay_head_manager_ext_jay_tearing_mode_info_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event head {
|
||||||
|
head: id(jay_head_ext_jay_tearing_mode_info_v1) (new),
|
||||||
|
}
|
||||||
7
wire/jay_head_manager_ext_jay_tearing_mode_setter_v1.txt
Normal file
7
wire/jay_head_manager_ext_jay_tearing_mode_setter_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event head {
|
||||||
|
head: id(jay_head_ext_jay_tearing_mode_setter_v1) (new),
|
||||||
|
}
|
||||||
7
wire/jay_head_manager_ext_jay_vrr_mode_info_v1.txt
Normal file
7
wire/jay_head_manager_ext_jay_vrr_mode_info_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event head {
|
||||||
|
head: id(jay_head_ext_jay_vrr_mode_info_v1) (new),
|
||||||
|
}
|
||||||
7
wire/jay_head_manager_ext_jay_vrr_mode_setter_v1.txt
Normal file
7
wire/jay_head_manager_ext_jay_vrr_mode_setter_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event head {
|
||||||
|
head: id(jay_head_ext_jay_vrr_mode_setter_v1) (new),
|
||||||
|
}
|
||||||
7
wire/jay_head_manager_ext_mode_info_v1.txt
Normal file
7
wire/jay_head_manager_ext_mode_info_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event head {
|
||||||
|
head: id(jay_head_ext_mode_info_v1) (new),
|
||||||
|
}
|
||||||
7
wire/jay_head_manager_ext_mode_setter_v1.txt
Normal file
7
wire/jay_head_manager_ext_mode_setter_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event head {
|
||||||
|
head: id(jay_head_ext_mode_setter_v1) (new),
|
||||||
|
}
|
||||||
7
wire/jay_head_manager_ext_non_desktop_info_v1.txt
Normal file
7
wire/jay_head_manager_ext_non_desktop_info_v1.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
request destroy (destructor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event head {
|
||||||
|
head: id(jay_head_ext_non_desktop_info_v1) (new),
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue