1
0
Fork 0
forked from wry/wry

metal: send non-desktop outputs to the frontend

This commit is contained in:
Julian Orth 2024-04-25 16:31:29 +02:00
parent fa3d870935
commit 24d08918c4
11 changed files with 184 additions and 62 deletions

View file

@ -59,6 +59,7 @@ pub struct MonitorInfo {
pub initial_mode: Mode,
pub width_mm: i32,
pub height_mm: i32,
pub non_desktop: bool,
}
#[derive(Copy, Clone, Debug)]

View file

@ -409,9 +409,7 @@ impl MetalConnector {
fn connected(&self) -> bool {
let dd = self.display.borrow_mut();
self.enabled.get()
&& dd.connection == ConnectorStatus::Connected
&& self.primary_plane.is_some()
self.enabled.get() && dd.connection == ConnectorStatus::Connected
}
pub fn schedule_present(&self) {
@ -909,6 +907,9 @@ impl Connector for MetalConnector {
fn set_mode(&self, be_mode: Mode) {
let mut dd = self.display.borrow_mut();
if dd.non_desktop {
return;
}
let Some(mode) = dd.modes.iter().find(|m| m.to_backend() == be_mode) else {
log::warn!("Connector does not support mode {:?}", be_mode);
return;
@ -1561,6 +1562,7 @@ impl MetalBackend {
initial_mode: dd.mode.clone().unwrap().to_backend(),
width_mm: dd.mm_width as _,
height_mm: dd.mm_height as _,
non_desktop: dd.non_desktop,
}));
connector.connect_sent.set(true);
connector.send_hardware_cursor();
@ -2457,6 +2459,9 @@ impl MetalBackend {
if !connector.connect_sent.get() {
self.send_connected(connector, &dd);
}
if connector.primary_plane.is_none() {
return;
}
if log_mode {
log::info!(
"Initialized connector {}-{} with mode {:?}",

View file

@ -574,6 +574,7 @@ impl XBackend {
},
width_mm: output.width.get(),
height_mm: output.height.get(),
non_desktop: false,
}));
output.changed();
self.present(output).await;

View file

@ -217,6 +217,7 @@ struct Output {
pub height_mm: i32,
pub current_mode: Option<Mode>,
pub modes: Vec<Mode>,
pub non_desktop: bool,
}
#[derive(Copy, Clone, Debug)]
@ -479,12 +480,16 @@ impl Randr {
println!(" product: {}", o.product);
println!(" manufacturer: {}", o.manufacturer);
println!(" serial number: {}", o.serial_number);
println!(" position: {} x {}", o.x, o.y);
println!(" logical size: {} x {}", o.width, o.height);
println!(
" physical size: {}mm x {}mm",
o.width_mm, o.height_mm
);
if o.non_desktop {
println!(" non-desktop");
return;
}
println!(" position: {} x {}", o.x, o.y);
println!(" logical size: {} x {}", o.width, o.height);
if let Some(mode) = &o.current_mode {
print!(" mode: ");
self.print_mode(mode, false);
@ -570,6 +575,27 @@ impl Randr {
height_mm: msg.height_mm,
modes: Default::default(),
current_mode: None,
non_desktop: false,
});
});
jay_randr::NonDesktopOutput::handle(tc, randr, data.clone(), |data, msg| {
let mut data = data.borrow_mut();
let c = data.connectors.last_mut().unwrap();
c.output = Some(Output {
scale: 1.0,
width: 0,
height: 0,
x: 0,
y: 0,
transform: Transform::None,
manufacturer: msg.manufacturer.to_string(),
product: msg.product.to_string(),
serial_number: msg.serial_number.to_string(),
width_mm: msg.width_mm,
height_mm: msg.height_mm,
modes: Default::default(),
current_mode: None,
non_desktop: true,
});
});
jay_randr::Mode::handle(tc, randr, data.clone(), |data, msg| {

View file

@ -514,6 +514,14 @@ impl ConfigProxyHandler {
}
}
fn get_output_node(&self, connector: Connector) -> Result<Rc<OutputNode>, CphError> {
let data = self.get_output(connector)?;
match data.node.clone() {
Some(d) => Ok(d),
_ => Err(CphError::OutputIsNotDesktop(connector)),
}
}
fn get_drm_device(&self, dev: DrmDevice) -> Result<Rc<DrmDevData>, CphError> {
match self.state.drm_devs.get(&DrmDeviceId::from_raw(dev.0 as _)) {
Some(dev) => Ok(dev),
@ -783,7 +791,7 @@ impl ConfigProxyHandler {
workspace: WorkspaceSource,
connector: Connector,
) -> Result<(), CphError> {
let output = self.get_output(connector)?;
let output = self.get_output_node(connector)?;
let ws = match workspace {
WorkspaceSource::Explicit(ws) => {
let name = self.get_workspace(ws)?;
@ -797,10 +805,10 @@ impl ConfigProxyHandler {
_ => return Ok(()),
},
};
if ws.is_dummy || output.node.is_dummy {
if ws.is_dummy || output.is_dummy {
return Ok(());
}
if ws.output.get().id == output.node.id {
if ws.output.get().id == output.id {
return Ok(());
}
let link = match &*ws.output_link.borrow() {
@ -811,8 +819,8 @@ impl ConfigProxyHandler {
make_visible_if_empty: true,
source_is_destroyed: false,
};
move_ws_to_output(&link, &output.node, config);
ws.desired_output.set(output.node.global.output_id.clone());
move_ws_to_output(&link, &output, config);
ws.desired_output.set(output.global.output_id.clone());
self.state.tree_changed();
self.state.damage();
Ok(())
@ -856,8 +864,8 @@ impl ConfigProxyHandler {
}
fn handle_connector_mode(&self, connector: Connector) -> Result<(), CphError> {
let connector = self.get_output(connector)?;
let mode = connector.node.global.mode.get();
let connector = self.get_output_node(connector)?;
let mode = connector.global.mode.get();
self.respond(Response::ConnectorMode {
width: mode.width,
height: mode.height,
@ -881,10 +889,9 @@ impl ConfigProxyHandler {
}
fn handle_connector_modes(&self, connector: Connector) -> Result<(), CphError> {
let connector = self.get_output(connector)?;
let connector = self.get_output_node(connector)?;
self.respond(Response::ConnectorModes {
modes: connector
.node
.global
.modes
.iter()
@ -964,8 +971,8 @@ impl ConfigProxyHandler {
}
fn handle_connector_size(&self, connector: Connector) -> Result<(), CphError> {
let connector = self.get_output(connector)?;
let pos = connector.node.global.pos.get();
let connector = self.get_output_node(connector)?;
let pos = connector.global.pos.get();
self.respond(Response::ConnectorSize {
width: pos.width(),
height: pos.height(),
@ -974,9 +981,9 @@ impl ConfigProxyHandler {
}
fn handle_connector_get_scale(&self, connector: Connector) -> Result<(), CphError> {
let connector = self.get_output(connector)?;
let connector = self.get_output_node(connector)?;
self.respond(Response::ConnectorGetScale {
scale: connector.node.global.persistent.scale.get().to_f64(),
scale: connector.global.persistent.scale.get().to_f64(),
});
Ok(())
}
@ -989,8 +996,8 @@ impl ConfigProxyHandler {
return Err(CphError::ScaleTooLarge(scale));
}
let scale = Scale::from_f64(scale);
let connector = self.get_output(connector)?;
connector.node.set_preferred_scale(scale);
let connector = self.get_output_node(connector)?;
connector.set_preferred_scale(scale);
self.state.damage();
Ok(())
}
@ -1000,8 +1007,8 @@ impl ConfigProxyHandler {
connector: Connector,
transform: Transform,
) -> Result<(), CphError> {
let connector = self.get_output(connector)?;
connector.node.update_transform(transform);
let connector = self.get_output_node(connector)?;
connector.update_transform(transform);
self.state.damage();
Ok(())
}
@ -1012,15 +1019,15 @@ impl ConfigProxyHandler {
x: i32,
y: i32,
) -> Result<(), CphError> {
let connector = self.get_output(connector)?;
let connector = self.get_output_node(connector)?;
if x < 0 || y < 0 || x > MAX_EXTENTS || y > MAX_EXTENTS {
return Err(CphError::InvalidConnectorPosition(x, y));
}
let old_pos = connector.node.global.pos.get();
connector.node.set_position(x, y);
let old_pos = connector.global.pos.get();
connector.set_position(x, y);
let seats = self.state.globals.seats.lock();
for seat in seats.values() {
if seat.get_output().id == connector.node.id {
if seat.get_output().id == connector.id {
let seat_pos = seat.position();
seat.set_position(
seat_pos.0.round_down() + x - old_pos.x1(),
@ -1032,8 +1039,8 @@ impl ConfigProxyHandler {
}
fn handle_connector_get_position(&self, connector: Connector) -> Result<(), CphError> {
let connector = self.get_output(connector)?;
let (x, y) = connector.node.global.pos.get().position();
let connector = self.get_output_node(connector)?;
let (x, y) = connector.global.pos.get().position();
self.respond(Response::ConnectorGetPosition { x, y });
Ok(())
}
@ -1813,6 +1820,8 @@ enum CphError {
TimerDoesNotExist(JayTimer),
#[error("Connector {0:?} does not exist or is not connected")]
OutputDoesNotExist(Connector),
#[error("Output {0:?} is not a desktop output")]
OutputIsNotDesktop(Connector),
#[error("{0}x{1} is not a valid connector position")]
InvalidConnectorPosition(i32, i32),
#[error("Keymap {0:?} does not exist")]

View file

@ -7,6 +7,7 @@ use {
object::{Object, Version},
scale::Scale,
state::{ConnectorData, DrmDevData, OutputData},
tree::OutputNode,
utils::{gfx_api_ext::GfxApiExt, transform_ext::TransformExt},
wire::{jay_randr::*, JayRandrId},
},
@ -64,33 +65,47 @@ impl JayRandr {
enabled: data.connector.enabled() as _,
name: &data.name,
});
if let Some(output) = self.client.state.outputs.get(&data.connector.id()) {
let global = &output.node.global;
let pos = global.pos.get();
self.client.event(Output {
self_id: self.id,
scale: global.persistent.scale.get().to_wl(),
width: pos.width(),
height: pos.height(),
x: pos.x1(),
y: pos.y1(),
transform: global.persistent.transform.get().to_wl(),
manufacturer: &output.monitor_info.manufacturer,
product: &output.monitor_info.product,
serial_number: &output.monitor_info.serial_number,
width_mm: global.width_mm,
height_mm: global.height_mm,
});
let current_mode = global.mode.get();
for mode in &global.modes {
self.client.event(Mode {
let Some(output) = self.client.state.outputs.get(&data.connector.id()) else {
return;
};
let global = match output.node.as_ref().map(|n| &n.global) {
Some(g) => g,
_ => {
self.client.event(NonDesktopOutput {
self_id: self.id,
width: mode.width,
height: mode.height,
refresh_rate_millihz: mode.refresh_rate_millihz,
current: (mode == &current_mode) as _,
manufacturer: &output.monitor_info.manufacturer,
product: &output.monitor_info.product,
serial_number: &output.monitor_info.serial_number,
width_mm: output.monitor_info.width_mm,
height_mm: output.monitor_info.height_mm,
});
return;
}
};
let pos = global.pos.get();
self.client.event(Output {
self_id: self.id,
scale: global.persistent.scale.get().to_wl(),
width: pos.width(),
height: pos.height(),
x: pos.x1(),
y: pos.y1(),
transform: global.persistent.transform.get().to_wl(),
manufacturer: &output.monitor_info.manufacturer,
product: &output.monitor_info.product,
serial_number: &output.monitor_info.serial_number,
width_mm: global.width_mm,
height_mm: global.height_mm,
});
let current_mode = global.mode.get();
for mode in &global.modes {
self.client.event(Mode {
self_id: self.id,
width: mode.width,
height: mode.height,
refresh_rate_millihz: mode.refresh_rate_millihz,
current: (mode == &current_mode) as _,
});
}
}
@ -144,6 +159,18 @@ impl JayRandr {
}
None
}
fn get_output_node(&self, name: &str) -> Option<Rc<OutputNode>> {
let output = self.get_output(name)?;
match output.node.clone() {
Some(n) => return Some(n),
_ => self.send_error(&format!(
"Display connected to {} is not a desktop display",
output.connector.name
)),
}
None
}
}
impl JayRandrRequestHandler for JayRandr {
@ -203,22 +230,22 @@ impl JayRandrRequestHandler for JayRandr {
}
fn set_transform(&self, req: SetTransform, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let Some(c) = self.get_output(req.output) else {
let Some(c) = self.get_output_node(req.output) else {
return Ok(());
};
let Some(transform) = Transform::from_wl(req.transform) else {
self.send_error(&format!("Unknown transform {}", req.transform));
return Ok(());
};
c.node.update_transform(transform);
c.update_transform(transform);
Ok(())
}
fn set_scale(&self, req: SetScale, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let Some(c) = self.get_output(req.output) else {
let Some(c) = self.get_output_node(req.output) else {
return Ok(());
};
c.node.set_preferred_scale(Scale::from_wl(req.scale));
c.set_preferred_scale(Scale::from_wl(req.scale));
Ok(())
}
@ -235,7 +262,7 @@ impl JayRandrRequestHandler for JayRandr {
}
fn set_position(&self, req: SetPosition, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let Some(c) = self.get_output(req.output) else {
let Some(c) = self.get_output_node(req.output) else {
return Ok(());
};
if req.x < 0 || req.y < 0 {
@ -246,7 +273,7 @@ impl JayRandrRequestHandler for JayRandr {
self.send_error(&format!("x and y cannot be greater than {MAX_EXTENTS}"));
return Ok(());
}
c.node.set_position(req.x, req.y);
c.set_position(req.x, req.y);
Ok(())
}

View file

@ -106,6 +106,7 @@ impl TestBackend {
initial_mode: mode,
width_mm: 80,
height_mm: 60,
non_desktop: false,
};
Self {
state: state.clone(),

View file

@ -42,6 +42,7 @@ async fn test(run: Rc<TestRun>) -> TestResult {
},
width_mm: 0,
height_mm: 0,
non_desktop: false,
};
run.backend
.state

View file

@ -268,7 +268,7 @@ pub struct ConnectorData {
pub struct OutputData {
pub connector: Rc<ConnectorData>,
pub monitor_info: MonitorInfo,
pub node: Rc<OutputNode>,
pub node: Option<Rc<OutputNode>>,
}
pub struct DrmDevData {

View file

@ -1,6 +1,7 @@
use {
crate::{
backend::{Connector, ConnectorEvent, ConnectorId, MonitorInfo},
globals::GlobalName,
ifs::wl_output::{OutputId, PersistentOutputState, WlOutputGlobal},
state::{ConnectorData, OutputData, State},
tree::{move_ws_to_output, OutputNode, OutputRenderData, WsMoveConfig},
@ -70,6 +71,9 @@ impl ConnectorHandler {
}
self.data.async_event.triggered().await;
}
if let Some(dev) = &self.data.drm_dev {
dev.connectors.remove(&self.id);
}
if let Some(config) = self.state.config.get() {
config.del_connector(self.id);
}
@ -87,6 +91,21 @@ impl ConnectorHandler {
model: info.product.clone(),
serial_number: info.serial_number.clone(),
});
if info.non_desktop {
self.handle_non_desktop_connected(info).await;
} else {
self.handle_desktop_connected(info, name, output_id).await;
}
self.data.connected.set(false);
log::info!("Connector {} disconnected", self.data.connector.kernel_id());
}
async fn handle_desktop_connected(
&self,
info: MonitorInfo,
name: GlobalName,
output_id: Rc<OutputId>,
) {
let desired_state = match self.state.persistent_output_states.get(&output_id) {
Some(ds) => ds,
_ => {
@ -155,7 +174,7 @@ impl ConnectorHandler {
let output_data = Rc::new(OutputData {
connector: self.data.clone(),
monitor_info: info,
node: on.clone(),
node: Some(on.clone()),
});
self.state.outputs.set(self.id, output_data);
on.schedule_update_render_data();
@ -224,7 +243,6 @@ impl ConnectorHandler {
}
self.data.async_event.triggered().await;
}
log::info!("Connector {} disconnected", self.data.connector.kernel_id());
if let Some(config) = self.state.config.get() {
config.connector_disconnected(self.id);
}
@ -242,7 +260,6 @@ impl ConnectorHandler {
global.destroyed.set(true);
self.state.root.outputs.remove(&self.id);
self.state.root.update_extents();
self.data.connected.set(false);
self.state.outputs.remove(&self.id);
on.lock_surface.take();
{
@ -285,4 +302,30 @@ impl ConnectorHandler {
self.state.tree_changed();
self.state.damage();
}
async fn handle_non_desktop_connected(&self, monitor_info: MonitorInfo) {
let output_data = Rc::new(OutputData {
connector: self.data.clone(),
monitor_info,
node: None,
});
self.state.outputs.set(self.id, output_data);
if let Some(config) = self.state.config.get() {
config.connector_connected(self.id);
}
'outer: loop {
while let Some(event) = self.data.connector.event() {
match event {
ConnectorEvent::Disconnected => break 'outer,
ConnectorEvent::HardwareCursor(None) => {}
ev => unreachable!("received unexpected event {:?}", ev),
}
}
self.data.async_event.triggered().await;
}
self.state.outputs.remove(&self.id);
if let Some(config) = self.state.config.get() {
config.connector_disconnected(self.id);
}
}
}