1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-24 13:52:55 +03:00

Implement wlr-output-management-unstable

This commit is contained in:
Timmy Xiao 2024-01-23 21:15:58 -08:00 committed by Wez Furlong
parent d6dae4fc90
commit ea149a9686
No known key found for this signature in database
GPG Key ID: 7A7F66A31EC9B387
4 changed files with 195 additions and 213 deletions

View File

@ -173,16 +173,14 @@ impl ConnectionOps for WaylandConnection {
}
fn screens(&self) -> anyhow::Result<crate::screen::Screens> {
// TODO: implement for the outputhandler
// if let Some(screens) = self
// .environment
// .with_inner(|env| env.output_handler.screens())
// {
// return Ok(screens);
// }
//
log::trace!("Getting screens for wayland connection");
if let Some(output_manager) = &self.wayland_state.borrow().output_manager {
if let Some(screens) = output_manager.screens() {
return Ok(screens);
}
}
let mut by_name = HashMap::new();
let mut virtual_rect: ScreenRect = euclid::rect(0, 0, 0, 0);
let config = config::configuration();

View File

@ -2,11 +2,11 @@
pub mod connection;
pub mod inputhandler;
// pub mod output;
pub mod output;
pub mod window;
pub use self::window::*;
pub use connection::*;
// pub use output::*;
pub use output::*;
mod copy_and_paste;
mod drag_and_drop;
// mod frame;
@ -15,17 +15,3 @@ mod keyboard;
mod pointer;
mod seat;
mod state;
/// Returns the id of a wayland proxy object, suitable for using
/// a key into hash maps
pub fn todo() {}
// pub fn wl_id<I, T>(obj: T) -> u32
// where
// I: wayland_client::Interface,
// T: AsRef<wayland_client::Proxy<I>>,
// I: AsRef<wayland_client::Proxy<I>>,
// I: From<wayland_client::Proxy<I>>,
// {
// let proxy: &wayland_client::Proxy<I> = obj.as_ref();
// proxy.id()
// }

View File

@ -1,27 +1,23 @@
//! Dealing with Wayland outputs
use crate::os::wayland::wl_id;
use crate::screen::{ScreenInfo, Screens};
use crate::ScreenRect;
use smithay_client_toolkit::environment::GlobalHandler;
use smithay_client_toolkit::globals::GlobalData;
use smithay_client_toolkit::reexports::protocols_wlr::output_management::v1::client::zwlr_output_head_v1::{ZwlrOutputHeadV1, self, Event as ZwlrOutputHeadEvent};
use smithay_client_toolkit::reexports::protocols_wlr::output_management::v1::client::zwlr_output_manager_v1::{ZwlrOutputManagerV1, self, Event as ZwlrOutputEvent};
use smithay_client_toolkit::reexports::protocols_wlr::output_management::v1::client::zwlr_output_mode_v1::{ZwlrOutputModeV1, Event as ZwlrOutputModeEvent};
use wayland_client::{Dispatch, event_created_child, Proxy};
use wayland_client::globals::{GlobalList, BindError};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::sync::Mutex;
use wayland_client::backend::ObjectId;
use wayland_client::protocol::wl_output::Transform;
use wayland_client::protocol::wl_registry::WlRegistry;
use wayland_client::{Attached, DispatchData, Main};
use wayland_protocols::wlr::unstable::output_management::v1::client::zwlr_output_head_v1::{
Event as ZwlrOutputHeadEvent, ZwlrOutputHeadV1,
};
use wayland_protocols::wlr::unstable::output_management::v1::client::zwlr_output_manager_v1::{
Event as ZwlrOutputEvent, ZwlrOutputManagerV1,
};
use wayland_protocols::wlr::unstable::output_management::v1::client::zwlr_output_mode_v1::{
Event as ZwlrOutputModeEvent, ZwlrOutputModeV1,
};
use super::state::WaylandState;
#[derive(Debug, Default, Clone)]
pub struct ModeInfo {
pub id: u32,
pub id: Option<ObjectId>,
pub width: i32,
pub height: i32,
pub refresh: i32,
@ -30,15 +26,15 @@ pub struct ModeInfo {
#[derive(Debug, Default, Clone)]
pub struct HeadInfo {
pub id: u32,
pub id: Option<ObjectId>,
pub name: String,
pub description: String,
pub physical_width: i32,
pub physical_height: i32,
/// List of ids that correspond to ModeInfo's
pub mode_ids: Vec<u32>,
pub mode_ids: Vec<ObjectId>,
pub enabled: bool,
pub current_mode_id: Option<u32>,
pub current_mode_id: Option<ObjectId>,
pub x: i32,
pub y: i32,
pub transform: Option<Transform>,
@ -50,155 +46,27 @@ pub struct HeadInfo {
#[derive(Default, Debug)]
struct Inner {
zwlr_heads: HashMap<u32, Attached<ZwlrOutputHeadV1>>,
zwlr_modes: HashMap<u32, Attached<ZwlrOutputModeV1>>,
zwlr_mode_info: HashMap<u32, ModeInfo>,
zwlr_head_info: HashMap<u32, HeadInfo>,
zwlr_heads: HashMap<ObjectId, ZwlrOutputHeadV1>,
zwlr_modes: HashMap<ObjectId, ZwlrOutputModeV1>,
zwlr_mode_info: HashMap<ObjectId, ModeInfo>,
zwlr_head_info: HashMap<ObjectId, HeadInfo>,
}
impl Inner {
fn handle_zwlr_mode_event(
&mut self,
mode: Main<ZwlrOutputModeV1>,
event: ZwlrOutputModeEvent,
_ddata: DispatchData,
_inner: &Arc<Mutex<Self>>,
) {
log::debug!("handle_zwlr_mode_event {event:?}");
let id = wl_id(mode.detach());
let info = self.zwlr_mode_info.entry(id).or_insert_with(|| ModeInfo {
id,
..ModeInfo::default()
});
match event {
ZwlrOutputModeEvent::Size { width, height } => {
info.width = width;
info.height = height;
}
ZwlrOutputModeEvent::Refresh { refresh } => {
info.refresh = refresh;
}
ZwlrOutputModeEvent::Preferred => {
info.preferred = true;
}
ZwlrOutputModeEvent::Finished => {
self.zwlr_mode_info.remove(&id);
self.zwlr_modes.remove(&id);
}
_ => {}
}
}
fn handle_zwlr_head_event(
&mut self,
head: Main<ZwlrOutputHeadV1>,
event: ZwlrOutputHeadEvent,
_ddata: DispatchData,
inner: &Arc<Mutex<Self>>,
) {
log::debug!("handle_zwlr_head_event {event:?}");
let id = wl_id(head.detach());
let info = self.zwlr_head_info.entry(id).or_insert_with(|| HeadInfo {
id,
..HeadInfo::default()
});
match event {
ZwlrOutputHeadEvent::Name { name } => {
info.name = name;
}
ZwlrOutputHeadEvent::Description { description } => {
info.description = description;
}
ZwlrOutputHeadEvent::PhysicalSize { width, height } => {
info.physical_width = width;
info.physical_height = height;
}
ZwlrOutputHeadEvent::Mode { mode } => {
let inner = Arc::clone(inner);
mode.quick_assign(move |mode, event, ddata| {
inner
.lock()
.unwrap()
.handle_zwlr_mode_event(mode, event, ddata, &inner);
});
let mode_id = wl_id(mode.detach());
info.mode_ids.push(mode_id);
self.zwlr_modes.insert(mode_id, mode.into());
}
ZwlrOutputHeadEvent::Enabled { enabled } => {
info.enabled = enabled != 0;
}
ZwlrOutputHeadEvent::CurrentMode { mode } => {
let mode_id = wl_id(mode);
info.current_mode_id.replace(mode_id);
}
ZwlrOutputHeadEvent::Position { x, y } => {
info.x = x;
info.y = y;
}
ZwlrOutputHeadEvent::Transform { transform } => {
info.transform.replace(transform);
}
ZwlrOutputHeadEvent::Scale { scale } => {
info.scale = scale;
}
ZwlrOutputHeadEvent::Make { make } => {
info.make = make;
}
ZwlrOutputHeadEvent::Model { model } => {
info.model = model;
}
ZwlrOutputHeadEvent::SerialNumber { serial_number } => {
info.serial_number = serial_number;
}
ZwlrOutputHeadEvent::Finished => {
log::debug!("remove head with id {id}");
self.zwlr_heads.remove(&id);
self.zwlr_head_info.remove(&id);
}
_ => {}
}
}
fn handle_zwlr_output_event(
&mut self,
_output: Main<ZwlrOutputManagerV1>,
event: ZwlrOutputEvent,
_ddata: DispatchData,
inner: &Arc<Mutex<Self>>,
) {
log::debug!("handle_zwlr_output_event {event:?}");
match event {
ZwlrOutputEvent::Head { head } => {
let inner = Arc::clone(inner);
head.quick_assign(move |output, event, ddata| {
inner
.lock()
.unwrap()
.handle_zwlr_head_event(output, event, ddata, &inner);
});
self.zwlr_heads.insert(wl_id(head.detach()), head.into());
}
ZwlrOutputEvent::Done { serial: _ } => {}
ZwlrOutputEvent::Finished => {}
_ => {}
}
}
pub struct OutputManagerState {
_zwlr: ZwlrOutputManagerV1,
inner: Mutex<Inner>,
}
pub struct OutputHandler {
zwlr: Option<Attached<ZwlrOutputManagerV1>>,
inner: Arc<Mutex<Inner>>,
}
impl OutputHandler {
pub fn new() -> Self {
Self {
zwlr: None,
inner: Arc::new(Mutex::new(Inner::default())),
}
impl OutputManagerState {
pub(super) fn bind(
globals: &GlobalList,
queue_handle: &wayland_client::QueueHandle<WaylandState>,
) -> Result<Self, BindError> {
let _zwlr = globals.bind(queue_handle, 1..=1, GlobalData)?;
Ok(Self {
_zwlr,
inner: Mutex::new(Inner::default()),
})
}
pub fn screens(&self) -> Option<Screens> {
@ -212,7 +80,7 @@ impl OutputHandler {
for head in inner.zwlr_head_info.values() {
let name = head.name.clone();
let (width, height) = match head.current_mode_id {
let (width, height) = match head.current_mode_id.clone() {
Some(mode_id) => match inner.zwlr_mode_info.get(&mode_id) {
Some(mode) => (mode.width, mode.height),
None => continue,
@ -275,32 +143,149 @@ impl OutputHandler {
}
}
impl GlobalHandler<ZwlrOutputManagerV1> for OutputHandler {
fn created(
&mut self,
registry: Attached<WlRegistry>,
id: u32,
version: u32,
_ddata: DispatchData,
#[derive(Default)]
pub(super) struct OutputManagerData {}
impl Dispatch<ZwlrOutputManagerV1, GlobalData, WaylandState> for OutputManagerState {
fn event(
state: &mut WaylandState,
_proxy: &ZwlrOutputManagerV1,
event: <ZwlrOutputManagerV1 as wayland_client::Proxy>::Event,
_data: &GlobalData,
_conn: &wayland_client::Connection,
_qhandle: &wayland_client::QueueHandle<WaylandState>,
) {
if !config::configuration().enable_zwlr_output_manager {
return;
log::debug!("handle_zwlr_output_event {event:?}");
let mut inner = state.output_manager.unwrap().inner.lock().unwrap();
match event {
ZwlrOutputEvent::Head { head } => {
inner.zwlr_heads.insert(head.id(), head);
}
_ => {}
}
log::debug!("created ZwlrOutputManagerV1 {id} {version}");
let zwlr = registry.bind::<ZwlrOutputManagerV1>(2, id);
let inner = Arc::clone(&self.inner);
zwlr.quick_assign(move |output, event, ddata| {
inner
.lock()
.unwrap()
.handle_zwlr_output_event(output, event, ddata, &inner);
});
self.zwlr.replace(zwlr.into());
}
fn get(&self) -> std::option::Option<Attached<ZwlrOutputManagerV1>> {
self.zwlr.clone()
event_created_child!(WaylandState, ZwlrOutputManagerV1, [
zwlr_output_manager_v1::EVT_HEAD_OPCODE => (ZwlrOutputHeadV1, OutputManagerData::default())
]);
}
impl Dispatch<ZwlrOutputHeadV1, OutputManagerData, WaylandState> for OutputManagerState {
fn event(
state: &mut WaylandState,
head: &ZwlrOutputHeadV1,
event: <ZwlrOutputHeadV1 as wayland_client::Proxy>::Event,
_data: &OutputManagerData,
_conn: &wayland_client::Connection,
_qhandle: &wayland_client::QueueHandle<WaylandState>,
) {
log::debug!("handle_zwlr_head_event {event:?}");
let mut inner = state.output_manager.unwrap().inner.lock().unwrap();
let id = head.id();
let info = inner
.zwlr_head_info
.entry(id.clone())
.or_insert_with(|| HeadInfo {
id: Some(id.clone()),
..HeadInfo::default()
});
match event {
ZwlrOutputHeadEvent::Name { name } => {
info.name = name;
}
ZwlrOutputHeadEvent::Description { description } => {
info.description = description;
}
ZwlrOutputHeadEvent::PhysicalSize { width, height } => {
info.physical_width = width;
info.physical_height = height;
}
ZwlrOutputHeadEvent::Mode { mode } => {
let mode_id = mode.id();
info.mode_ids.push(mode_id.clone().into());
inner.zwlr_modes.insert(mode_id, mode.into());
}
ZwlrOutputHeadEvent::Enabled { enabled } => {
info.enabled = enabled != 0;
}
ZwlrOutputHeadEvent::CurrentMode { mode } => {
let mode_id = mode.id();
info.current_mode_id.replace(mode_id);
}
ZwlrOutputHeadEvent::Position { x, y } => {
info.x = x;
info.y = y;
}
ZwlrOutputHeadEvent::Transform { transform } => {
info.transform = transform.into_result().ok();
}
ZwlrOutputHeadEvent::Scale { scale } => {
info.scale = scale;
}
ZwlrOutputHeadEvent::Make { make } => {
info.make = make;
}
ZwlrOutputHeadEvent::Model { model } => {
info.model = model;
}
ZwlrOutputHeadEvent::SerialNumber { serial_number } => {
info.serial_number = serial_number;
}
ZwlrOutputHeadEvent::Finished => {
log::debug!("remove head with id {id}");
inner.zwlr_heads.remove(&id);
inner.zwlr_head_info.remove(&id);
}
_ => {}
}
}
event_created_child!(WaylandState, ZwlrOutputModeV1, [
zwlr_output_head_v1::EVT_CURRENT_MODE_OPCODE => (ZwlrOutputModeV1, OutputManagerData::default()),
zwlr_output_head_v1::EVT_MODE_OPCODE => (ZwlrOutputModeV1, OutputManagerData::default()),
]);
}
impl Dispatch<ZwlrOutputModeV1, OutputManagerData, WaylandState> for OutputManagerState {
fn event(
state: &mut WaylandState,
mode: &ZwlrOutputModeV1,
event: <ZwlrOutputModeV1 as wayland_client::Proxy>::Event,
_data: &OutputManagerData,
_conn: &wayland_client::Connection,
_qhandle: &wayland_client::QueueHandle<WaylandState>,
) {
log::debug!("handle_zwlr_mode_event {event:?}");
let mut inner = state.output_manager.unwrap().inner.lock().unwrap();
let id = mode.id();
let info = inner
.zwlr_mode_info
.entry(id.clone())
.or_insert_with(|| ModeInfo {
id: Some(id.clone()),
..ModeInfo::default()
});
match event {
ZwlrOutputModeEvent::Size { width, height } => {
info.width = width;
info.height = height;
}
ZwlrOutputModeEvent::Refresh { refresh } => {
info.refresh = refresh;
}
ZwlrOutputModeEvent::Preferred => {
info.preferred = true;
}
ZwlrOutputModeEvent::Finished => {
inner.zwlr_mode_info.remove(&id);
inner.zwlr_modes.remove(&id);
}
_ => {}
}
}
}

View File

@ -9,6 +9,9 @@ use smithay_client_toolkit::data_device_manager::data_source::CopyPasteSource;
use smithay_client_toolkit::data_device_manager::DataDeviceManagerState;
use smithay_client_toolkit::globals::GlobalData;
use smithay_client_toolkit::output::{OutputHandler, OutputState};
use smithay_client_toolkit::reexports::protocols_wlr::output_management::v1::client::zwlr_output_head_v1::ZwlrOutputHeadV1;
use smithay_client_toolkit::reexports::protocols_wlr::output_management::v1::client::zwlr_output_manager_v1::ZwlrOutputManagerV1;
use smithay_client_toolkit::reexports::protocols_wlr::output_management::v1::client::zwlr_output_mode_v1::ZwlrOutputModeV1;
use smithay_client_toolkit::registry::{ProvidesRegistryState, RegistryState};
use smithay_client_toolkit::seat::pointer::ThemedPointer;
use smithay_client_toolkit::seat::SeatState;
@ -34,7 +37,7 @@ use crate::x11::KeyboardWithFallback;
use super::inputhandler::{TextInputData, TextInputState};
use super::pointer::{PendingMouse, PointerUserData};
use super::{SurfaceUserData, WaylandWindowInner};
use super::{OutputManagerData, OutputManagerState, SurfaceUserData, WaylandWindowInner};
// We can't combine WaylandState and WaylandConnection together because
// the run_message_loop has &self(WaylandConnection) and needs to update WaylandState as mut
@ -43,6 +46,7 @@ pub(super) struct WaylandState {
pub(super) output: OutputState,
pub(super) compositor: CompositorState,
pub(super) text_input: TextInputState,
pub(super) output_manager: Option<OutputManagerState>,
pub(super) seat: SeatState,
pub(super) xdg: XdgShell,
pub(super) windows: RefCell<HashMap<usize, Rc<RefCell<WaylandWindowInner>>>>,
@ -74,6 +78,11 @@ impl WaylandState {
output: OutputState::new(globals, qh),
compositor: CompositorState::bind(globals, qh)?,
text_input: TextInputState::bind(globals, qh)?,
output_manager: if config::configuration().enable_zwlr_output_manager {
Some(OutputManagerState::bind(globals, qh)?)
} else {
None
},
windows: RefCell::new(HashMap::new()),
seat: SeatState::new(globals, qh),
xdg: XdgShell::bind(globals, qh)?,
@ -156,3 +165,7 @@ delegate_xdg_window!(WaylandState);
delegate_dispatch!(WaylandState: [ZwpTextInputManagerV3: GlobalData] => TextInputState);
delegate_dispatch!(WaylandState: [ZwpTextInputV3: TextInputData] => TextInputState);
delegate_dispatch!(WaylandState: [ZwlrOutputManagerV1: GlobalData] => OutputManagerState);
delegate_dispatch!(WaylandState: [ZwlrOutputHeadV1: OutputManagerData] => OutputManagerState);
delegate_dispatch!(WaylandState: [ZwlrOutputModeV1: OutputManagerData] => OutputManagerState);