mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-03-07 20:09:59 +03:00
committed by
Ferdinand Schober
parent
3e1c3e95b7
commit
21c24f7fa1
@@ -1,8 +1,9 @@
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures_core::Stream;
|
use futures_core::Stream;
|
||||||
use std::{
|
use std::{
|
||||||
collections::VecDeque,
|
collections::{HashSet, VecDeque},
|
||||||
env,
|
env,
|
||||||
|
fmt::{self, Display},
|
||||||
io::{self, ErrorKind},
|
io::{self, ErrorKind},
|
||||||
os::fd::{AsFd, RawFd},
|
os::fd::{AsFd, RawFd},
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
@@ -46,13 +47,15 @@ use wayland_protocols_wlr::layer_shell::v1::client::{
|
|||||||
use wayland_client::{
|
use wayland_client::{
|
||||||
backend::{ReadEventsGuard, WaylandError},
|
backend::{ReadEventsGuard, WaylandError},
|
||||||
delegate_noop,
|
delegate_noop,
|
||||||
globals::{registry_queue_init, GlobalListContents},
|
globals::{registry_queue_init, Global, GlobalList, GlobalListContents},
|
||||||
protocol::{
|
protocol::{
|
||||||
wl_buffer, wl_compositor,
|
wl_buffer, wl_compositor,
|
||||||
wl_keyboard::{self, WlKeyboard},
|
wl_keyboard::{self, WlKeyboard},
|
||||||
wl_output::{self, WlOutput},
|
wl_output::{self, WlOutput},
|
||||||
wl_pointer::{self, WlPointer},
|
wl_pointer::{self, WlPointer},
|
||||||
wl_region, wl_registry, wl_seat, wl_shm, wl_shm_pool,
|
wl_region,
|
||||||
|
wl_registry::{self, WlRegistry},
|
||||||
|
wl_seat, wl_shm, wl_shm_pool,
|
||||||
wl_surface::WlSurface,
|
wl_surface::WlSurface,
|
||||||
},
|
},
|
||||||
Connection, Dispatch, DispatchError, EventQueue, QueueHandle, WEnum,
|
Connection, Dispatch, DispatchError, EventQueue, QueueHandle, WEnum,
|
||||||
@@ -75,28 +78,42 @@ struct Globals {
|
|||||||
seat: wl_seat::WlSeat,
|
seat: wl_seat::WlSeat,
|
||||||
shm: wl_shm::WlShm,
|
shm: wl_shm::WlShm,
|
||||||
layer_shell: ZwlrLayerShellV1,
|
layer_shell: ZwlrLayerShellV1,
|
||||||
outputs: Vec<WlOutput>,
|
|
||||||
xdg_output_manager: ZxdgOutputManagerV1,
|
xdg_output_manager: ZxdgOutputManagerV1,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Clone, Debug)]
|
||||||
|
struct Output {
|
||||||
|
wl_output: WlOutput,
|
||||||
|
global: Global,
|
||||||
|
info: Option<OutputInfo>,
|
||||||
|
pending_info: OutputInfo,
|
||||||
|
has_xdg_info: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Output {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
if let Some(info) = &self.info {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{} {}x{} @pos {:?} ({})",
|
||||||
|
info.name, info.size.0, info.size.1, info.position, info.description
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
write!(f, "unknown output")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
struct OutputInfo {
|
struct OutputInfo {
|
||||||
|
description: String,
|
||||||
name: String,
|
name: String,
|
||||||
position: (i32, i32),
|
position: (i32, i32),
|
||||||
size: (i32, i32),
|
size: (i32, i32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OutputInfo {
|
|
||||||
fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
name: "".to_string(),
|
|
||||||
position: (0, 0),
|
|
||||||
size: (0, 0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
|
active_positions: HashSet<Position>,
|
||||||
pointer: Option<WlPointer>,
|
pointer: Option<WlPointer>,
|
||||||
keyboard: Option<WlKeyboard>,
|
keyboard: Option<WlKeyboard>,
|
||||||
pointer_lock: Option<ZwpLockedPointerV1>,
|
pointer_lock: Option<ZwpLockedPointerV1>,
|
||||||
@@ -104,12 +121,13 @@ struct State {
|
|||||||
shortcut_inhibitor: Option<ZwpKeyboardShortcutsInhibitorV1>,
|
shortcut_inhibitor: Option<ZwpKeyboardShortcutsInhibitorV1>,
|
||||||
active_windows: Vec<Arc<Window>>,
|
active_windows: Vec<Arc<Window>>,
|
||||||
focused: Option<Arc<Window>>,
|
focused: Option<Arc<Window>>,
|
||||||
g: Globals,
|
global_list: GlobalList,
|
||||||
|
globals: Globals,
|
||||||
wayland_fd: RawFd,
|
wayland_fd: RawFd,
|
||||||
read_guard: Option<ReadEventsGuard>,
|
read_guard: Option<ReadEventsGuard>,
|
||||||
qh: QueueHandle<Self>,
|
qh: QueueHandle<Self>,
|
||||||
pending_events: VecDeque<(Position, CaptureEvent)>,
|
pending_events: VecDeque<(Position, CaptureEvent)>,
|
||||||
output_info: Vec<(WlOutput, OutputInfo)>,
|
outputs: Vec<Output>,
|
||||||
scroll_discrete_pending: bool,
|
scroll_discrete_pending: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +160,7 @@ impl Window {
|
|||||||
size: (i32, i32),
|
size: (i32, i32),
|
||||||
) -> Window {
|
) -> Window {
|
||||||
log::debug!("creating window output: {output:?}, size: {size:?}");
|
log::debug!("creating window output: {output:?}, size: {size:?}");
|
||||||
let g = &state.g;
|
let g = &state.globals;
|
||||||
|
|
||||||
let (width, height) = match pos {
|
let (width, height) = match pos {
|
||||||
Position::Left | Position::Right => (1, size.1 as u32),
|
Position::Left | Position::Right => (1, size.1 as u32),
|
||||||
@@ -203,41 +221,36 @@ impl Drop for Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_edges(outputs: &[(WlOutput, OutputInfo)], pos: Position) -> Vec<(WlOutput, i32)> {
|
fn get_edges(outputs: &[Output], pos: Position) -> Vec<(Output, i32)> {
|
||||||
outputs
|
outputs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(o, i)| {
|
.filter_map(|output| {
|
||||||
(
|
output.info.as_ref().map(|info| {
|
||||||
o.clone(),
|
(
|
||||||
match pos {
|
output.clone(),
|
||||||
Position::Left => i.position.0,
|
match pos {
|
||||||
Position::Right => i.position.0 + i.size.0,
|
Position::Left => info.position.0,
|
||||||
Position::Top => i.position.1,
|
Position::Right => info.position.0 + info.size.0,
|
||||||
Position::Bottom => i.position.1 + i.size.1,
|
Position::Top => info.position.1,
|
||||||
},
|
Position::Bottom => info.position.1 + info.size.1,
|
||||||
)
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_output_configuration(state: &State, pos: Position) -> Vec<(WlOutput, OutputInfo)> {
|
fn get_output_configuration(state: &State, pos: Position) -> Vec<Output> {
|
||||||
// get all output edges corresponding to the position
|
// get all output edges corresponding to the position
|
||||||
let edges = get_edges(&state.output_info, pos);
|
let edges = get_edges(&state.outputs, pos);
|
||||||
log::debug!("edges: {edges:?}");
|
let opposite_edges = get_edges(&state.outputs, pos.opposite());
|
||||||
let opposite_edges = get_edges(&state.output_info, pos.opposite());
|
|
||||||
|
|
||||||
// remove those edges that are at the same position
|
// remove those edges that are at the same position
|
||||||
// as an opposite edge of a different output
|
// as an opposite edge of a different output
|
||||||
let outputs: Vec<WlOutput> = edges
|
edges
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, edge)| !opposite_edges.iter().map(|(_, e)| *e).any(|e| &e == edge))
|
.filter(|(_, edge)| !opposite_edges.iter().map(|(_, e)| *e).any(|e| &e == edge))
|
||||||
.map(|(o, _)| o.clone())
|
.map(|(o, _)| o.clone())
|
||||||
.collect();
|
|
||||||
state
|
|
||||||
.output_info
|
|
||||||
.iter()
|
|
||||||
.filter(|(o, _)| outputs.contains(o))
|
|
||||||
.map(|(o, i)| (o.clone(), i.clone()))
|
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,36 +272,36 @@ fn draw(f: &mut File, (width, height): (u32, u32)) {
|
|||||||
impl LayerShellInputCapture {
|
impl LayerShellInputCapture {
|
||||||
pub fn new() -> std::result::Result<Self, LayerShellCaptureCreationError> {
|
pub fn new() -> std::result::Result<Self, LayerShellCaptureCreationError> {
|
||||||
let conn = Connection::connect_to_env()?;
|
let conn = Connection::connect_to_env()?;
|
||||||
let (g, mut queue) = registry_queue_init::<State>(&conn)?;
|
let (global_list, mut queue) = registry_queue_init::<State>(&conn)?;
|
||||||
|
|
||||||
let qh = queue.handle();
|
let qh = queue.handle();
|
||||||
|
|
||||||
let compositor: wl_compositor::WlCompositor = g
|
let compositor: wl_compositor::WlCompositor = global_list
|
||||||
.bind(&qh, 4..=5, ())
|
.bind(&qh, 4..=5, ())
|
||||||
.map_err(|e| WaylandBindError::new(e, "wl_compositor 4..=5"))?;
|
.map_err(|e| WaylandBindError::new(e, "wl_compositor 4..=5"))?;
|
||||||
let xdg_output_manager: ZxdgOutputManagerV1 = g
|
let xdg_output_manager: ZxdgOutputManagerV1 = global_list
|
||||||
.bind(&qh, 1..=3, ())
|
.bind(&qh, 1..=3, ())
|
||||||
.map_err(|e| WaylandBindError::new(e, "xdg_output_manager 1..=3"))?;
|
.map_err(|e| WaylandBindError::new(e, "xdg_output_manager 1..=3"))?;
|
||||||
let shm: wl_shm::WlShm = g
|
let shm: wl_shm::WlShm = global_list
|
||||||
.bind(&qh, 1..=1, ())
|
.bind(&qh, 1..=1, ())
|
||||||
.map_err(|e| WaylandBindError::new(e, "wl_shm"))?;
|
.map_err(|e| WaylandBindError::new(e, "wl_shm"))?;
|
||||||
let layer_shell: ZwlrLayerShellV1 = g
|
let layer_shell: ZwlrLayerShellV1 = global_list
|
||||||
.bind(&qh, 3..=4, ())
|
.bind(&qh, 3..=4, ())
|
||||||
.map_err(|e| WaylandBindError::new(e, "wlr_layer_shell 3..=4"))?;
|
.map_err(|e| WaylandBindError::new(e, "wlr_layer_shell 3..=4"))?;
|
||||||
let seat: wl_seat::WlSeat = g
|
let seat: wl_seat::WlSeat = global_list
|
||||||
.bind(&qh, 7..=8, ())
|
.bind(&qh, 7..=8, ())
|
||||||
.map_err(|e| WaylandBindError::new(e, "wl_seat 7..=8"))?;
|
.map_err(|e| WaylandBindError::new(e, "wl_seat 7..=8"))?;
|
||||||
|
|
||||||
let pointer_constraints: ZwpPointerConstraintsV1 = g
|
let pointer_constraints: ZwpPointerConstraintsV1 = global_list
|
||||||
.bind(&qh, 1..=1, ())
|
.bind(&qh, 1..=1, ())
|
||||||
.map_err(|e| WaylandBindError::new(e, "zwp_pointer_constraints_v1"))?;
|
.map_err(|e| WaylandBindError::new(e, "zwp_pointer_constraints_v1"))?;
|
||||||
let relative_pointer_manager: ZwpRelativePointerManagerV1 = g
|
let relative_pointer_manager: ZwpRelativePointerManagerV1 = global_list
|
||||||
.bind(&qh, 1..=1, ())
|
.bind(&qh, 1..=1, ())
|
||||||
.map_err(|e| WaylandBindError::new(e, "zwp_relative_pointer_manager_v1"))?;
|
.map_err(|e| WaylandBindError::new(e, "zwp_relative_pointer_manager_v1"))?;
|
||||||
let shortcut_inhibit_manager: Result<
|
let shortcut_inhibit_manager: Result<
|
||||||
ZwpKeyboardShortcutsInhibitManagerV1,
|
ZwpKeyboardShortcutsInhibitManagerV1,
|
||||||
WaylandBindError,
|
WaylandBindError,
|
||||||
> = g
|
> = global_list
|
||||||
.bind(&qh, 1..=1, ())
|
.bind(&qh, 1..=1, ())
|
||||||
.map_err(|e| WaylandBindError::new(e, "zwp_keyboard_shortcuts_inhibit_manager_v1"));
|
.map_err(|e| WaylandBindError::new(e, "zwp_keyboard_shortcuts_inhibit_manager_v1"));
|
||||||
// layer-shell backend still works without this protocol so we make it an optional dependency
|
// layer-shell backend still works without this protocol so we make it an optional dependency
|
||||||
@@ -297,65 +310,41 @@ impl LayerShellInputCapture {
|
|||||||
to the client");
|
to the client");
|
||||||
}
|
}
|
||||||
let shortcut_inhibit_manager = shortcut_inhibit_manager.ok();
|
let shortcut_inhibit_manager = shortcut_inhibit_manager.ok();
|
||||||
let outputs = vec![];
|
|
||||||
|
|
||||||
let g = Globals {
|
|
||||||
compositor,
|
|
||||||
shm,
|
|
||||||
layer_shell,
|
|
||||||
seat,
|
|
||||||
pointer_constraints,
|
|
||||||
relative_pointer_manager,
|
|
||||||
shortcut_inhibit_manager,
|
|
||||||
outputs,
|
|
||||||
xdg_output_manager,
|
|
||||||
};
|
|
||||||
|
|
||||||
// flush outgoing events
|
|
||||||
queue.flush()?;
|
|
||||||
|
|
||||||
let wayland_fd = queue.as_fd().as_raw_fd();
|
|
||||||
|
|
||||||
let mut state = State {
|
let mut state = State {
|
||||||
|
active_positions: Default::default(),
|
||||||
pointer: None,
|
pointer: None,
|
||||||
keyboard: None,
|
keyboard: None,
|
||||||
g,
|
global_list,
|
||||||
|
globals: Globals {
|
||||||
|
compositor,
|
||||||
|
shm,
|
||||||
|
layer_shell,
|
||||||
|
seat,
|
||||||
|
pointer_constraints,
|
||||||
|
relative_pointer_manager,
|
||||||
|
shortcut_inhibit_manager,
|
||||||
|
xdg_output_manager,
|
||||||
|
},
|
||||||
pointer_lock: None,
|
pointer_lock: None,
|
||||||
rel_pointer: None,
|
rel_pointer: None,
|
||||||
shortcut_inhibitor: None,
|
shortcut_inhibitor: None,
|
||||||
active_windows: Vec::new(),
|
active_windows: Vec::new(),
|
||||||
focused: None,
|
focused: None,
|
||||||
qh,
|
qh,
|
||||||
wayland_fd,
|
wayland_fd: queue.as_fd().as_raw_fd(),
|
||||||
read_guard: None,
|
read_guard: None,
|
||||||
pending_events: VecDeque::new(),
|
pending_events: VecDeque::new(),
|
||||||
output_info: vec![],
|
outputs: vec![],
|
||||||
scroll_discrete_pending: false,
|
scroll_discrete_pending: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// dispatch registry to () again, in order to read all wl_outputs
|
for global in state.global_list.contents().clone_list() {
|
||||||
conn.display().get_registry(&state.qh, ());
|
state.register_global(global);
|
||||||
log::debug!("==============> requested registry");
|
|
||||||
|
|
||||||
// roundtrip to read wl_output globals
|
|
||||||
queue.roundtrip(&mut state)?;
|
|
||||||
log::debug!("==============> roundtrip 1 done");
|
|
||||||
|
|
||||||
// read outputs
|
|
||||||
for output in state.g.outputs.iter() {
|
|
||||||
state
|
|
||||||
.g
|
|
||||||
.xdg_output_manager
|
|
||||||
.get_xdg_output(output, &state.qh, output.clone());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// roundtrip to read xdg_output events
|
// flush outgoing events
|
||||||
queue.roundtrip(&mut state)?;
|
queue.flush()?;
|
||||||
|
|
||||||
log::debug!("==============> roundtrip 2 done");
|
|
||||||
for i in &state.output_info {
|
|
||||||
log::debug!("{:#?}", i.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let read_guard = loop {
|
let read_guard = loop {
|
||||||
match queue.prepare_read() {
|
match queue.prepare_read() {
|
||||||
@@ -379,6 +368,7 @@ impl LayerShellInputCapture {
|
|||||||
|
|
||||||
fn delete_client(&mut self, pos: Position) {
|
fn delete_client(&mut self, pos: Position) {
|
||||||
let inner = self.0.get_mut();
|
let inner = self.0.get_mut();
|
||||||
|
inner.state.active_positions.remove(&pos);
|
||||||
// remove all windows corresponding to this client
|
// remove all windows corresponding to this client
|
||||||
while let Some(i) = inner.state.active_windows.iter().position(|w| w.pos == pos) {
|
while let Some(i) = inner.state.active_windows.iter().position(|w| w.pos == pos) {
|
||||||
inner.state.active_windows.remove(i);
|
inner.state.active_windows.remove(i);
|
||||||
@@ -388,6 +378,52 @@ impl LayerShellInputCapture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
|
fn update_output_info(&mut self, name: u32) {
|
||||||
|
let output = self
|
||||||
|
.outputs
|
||||||
|
.iter_mut()
|
||||||
|
.find(|o| o.global.name == name)
|
||||||
|
.expect("output not found");
|
||||||
|
if output.has_xdg_info {
|
||||||
|
output.info.replace(output.pending_info.clone());
|
||||||
|
self.update_windows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_global(&mut self, global: Global) {
|
||||||
|
if global.interface.as_str() == "wl_output" {
|
||||||
|
log::debug!("new output global: wl_output {}", global.name);
|
||||||
|
let wl_output = self.global_list.registry().bind::<WlOutput, _, _>(
|
||||||
|
global.name,
|
||||||
|
4,
|
||||||
|
&self.qh,
|
||||||
|
global.name,
|
||||||
|
);
|
||||||
|
self.globals
|
||||||
|
.xdg_output_manager
|
||||||
|
.get_xdg_output(&wl_output, &self.qh, global.name);
|
||||||
|
self.outputs.push(Output {
|
||||||
|
wl_output,
|
||||||
|
global,
|
||||||
|
info: None,
|
||||||
|
has_xdg_info: false,
|
||||||
|
pending_info: Default::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deregister_global(&mut self, name: u32) {
|
||||||
|
self.outputs.retain(|o| {
|
||||||
|
if o.global.name == name {
|
||||||
|
log::debug!("{o} (global {:?}) removed", o.global);
|
||||||
|
o.wl_output.release();
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn grab(
|
fn grab(
|
||||||
&mut self,
|
&mut self,
|
||||||
surface: &WlSurface,
|
surface: &WlSurface,
|
||||||
@@ -408,7 +444,7 @@ impl State {
|
|||||||
|
|
||||||
// lock pointer
|
// lock pointer
|
||||||
if self.pointer_lock.is_none() {
|
if self.pointer_lock.is_none() {
|
||||||
self.pointer_lock = Some(self.g.pointer_constraints.lock_pointer(
|
self.pointer_lock = Some(self.globals.pointer_constraints.lock_pointer(
|
||||||
surface,
|
surface,
|
||||||
pointer,
|
pointer,
|
||||||
None,
|
None,
|
||||||
@@ -420,7 +456,7 @@ impl State {
|
|||||||
|
|
||||||
// request relative input
|
// request relative input
|
||||||
if self.rel_pointer.is_none() {
|
if self.rel_pointer.is_none() {
|
||||||
self.rel_pointer = Some(self.g.relative_pointer_manager.get_relative_pointer(
|
self.rel_pointer = Some(self.globals.relative_pointer_manager.get_relative_pointer(
|
||||||
pointer,
|
pointer,
|
||||||
qh,
|
qh,
|
||||||
(),
|
(),
|
||||||
@@ -428,10 +464,14 @@ impl State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// capture modifier keys
|
// capture modifier keys
|
||||||
if let Some(shortcut_inhibit_manager) = &self.g.shortcut_inhibit_manager {
|
if let Some(shortcut_inhibit_manager) = &self.globals.shortcut_inhibit_manager {
|
||||||
if self.shortcut_inhibitor.is_none() {
|
if self.shortcut_inhibitor.is_none() {
|
||||||
self.shortcut_inhibitor =
|
self.shortcut_inhibitor = Some(shortcut_inhibit_manager.inhibit_shortcuts(
|
||||||
Some(shortcut_inhibit_manager.inhibit_shortcuts(surface, &self.g.seat, qh, ()));
|
surface,
|
||||||
|
&self.globals.seat,
|
||||||
|
qh,
|
||||||
|
(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -469,21 +509,39 @@ impl State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn add_client(&mut self, pos: Position) {
|
fn add_client(&mut self, pos: Position) {
|
||||||
|
self.active_positions.insert(pos);
|
||||||
let outputs = get_output_configuration(self, pos);
|
let outputs = get_output_configuration(self, pos);
|
||||||
|
|
||||||
log::debug!("outputs: {outputs:?}");
|
log::info!(
|
||||||
outputs.iter().for_each(|(o, i)| {
|
"adding capture for position {pos} - using outputs: {:?}",
|
||||||
let window = Window::new(self, &self.qh, o, pos, i.size);
|
outputs
|
||||||
let window = Arc::new(window);
|
.iter()
|
||||||
self.active_windows.push(window);
|
.map(|o| o
|
||||||
|
.info
|
||||||
|
.as_ref()
|
||||||
|
.map(|i| i.name.to_owned())
|
||||||
|
.unwrap_or("unknown output".to_owned()))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
);
|
||||||
|
outputs.iter().for_each(|o| {
|
||||||
|
if let Some(info) = o.info.as_ref() {
|
||||||
|
let window = Window::new(self, &self.qh, &o.wl_output, pos, info.size);
|
||||||
|
let window = Arc::new(window);
|
||||||
|
self.active_windows.push(window);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_windows(&mut self) {
|
fn update_windows(&mut self) {
|
||||||
log::debug!("updating windows");
|
log::info!("active outputs: ");
|
||||||
log::debug!("output info: {:?}", self.output_info);
|
for output in self.outputs.iter().filter(|o| o.info.is_some()) {
|
||||||
let clients: Vec<_> = self.active_windows.drain(..).map(|w| w.pos).collect();
|
log::info!(" * {}", output);
|
||||||
for pos in clients {
|
}
|
||||||
|
|
||||||
|
self.active_windows.clear();
|
||||||
|
|
||||||
|
let active_positions = self.active_positions.iter().cloned().collect::<Vec<_>>();
|
||||||
|
for pos in active_positions {
|
||||||
self.add_client(pos);
|
self.add_client(pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -872,94 +930,89 @@ impl Dispatch<ZwlrLayerSurfaceV1, ()> for State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// delegate wl_registry events to App itself
|
// delegate wl_registry events to App itself
|
||||||
impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for State {
|
impl Dispatch<WlRegistry, GlobalListContents> for State {
|
||||||
fn event(
|
|
||||||
_state: &mut Self,
|
|
||||||
_proxy: &wl_registry::WlRegistry,
|
|
||||||
_event: <wl_registry::WlRegistry as wayland_client::Proxy>::Event,
|
|
||||||
_data: &GlobalListContents,
|
|
||||||
_conn: &Connection,
|
|
||||||
_qhandle: &QueueHandle<Self>,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dispatch<wl_registry::WlRegistry, ()> for State {
|
|
||||||
fn event(
|
fn event(
|
||||||
state: &mut Self,
|
state: &mut Self,
|
||||||
registry: &wl_registry::WlRegistry,
|
_registry: &WlRegistry,
|
||||||
event: <wl_registry::WlRegistry as wayland_client::Proxy>::Event,
|
event: <WlRegistry as wayland_client::Proxy>::Event,
|
||||||
_: &(),
|
_data: &GlobalListContents,
|
||||||
_: &Connection,
|
_conn: &Connection,
|
||||||
qh: &QueueHandle<Self>,
|
_qh: &QueueHandle<Self>,
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
wl_registry::Event::Global {
|
wl_registry::Event::Global {
|
||||||
name,
|
name,
|
||||||
interface,
|
interface,
|
||||||
version: _,
|
version,
|
||||||
} => {
|
} => {
|
||||||
if interface.as_str() == "wl_output" {
|
state.register_global(Global {
|
||||||
log::debug!("wl_output global");
|
name,
|
||||||
state
|
interface,
|
||||||
.g
|
version,
|
||||||
.outputs
|
});
|
||||||
.push(registry.bind::<WlOutput, _, _>(name, 4, qh, ()))
|
}
|
||||||
}
|
wl_registry::Event::GlobalRemove { name } => {
|
||||||
|
state.deregister_global(name);
|
||||||
}
|
}
|
||||||
wl_registry::Event::GlobalRemove { .. } => {}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dispatch<ZxdgOutputV1, WlOutput> for State {
|
impl Dispatch<ZxdgOutputV1, u32> for State {
|
||||||
fn event(
|
fn event(
|
||||||
state: &mut Self,
|
state: &mut Self,
|
||||||
_: &ZxdgOutputV1,
|
_: &ZxdgOutputV1,
|
||||||
event: <ZxdgOutputV1 as wayland_client::Proxy>::Event,
|
event: <ZxdgOutputV1 as wayland_client::Proxy>::Event,
|
||||||
wl_output: &WlOutput,
|
name: &u32,
|
||||||
_: &Connection,
|
_: &Connection,
|
||||||
_: &QueueHandle<Self>,
|
_: &QueueHandle<Self>,
|
||||||
) {
|
) {
|
||||||
log::debug!("xdg-output - {event:?}");
|
let output = state
|
||||||
let output_info = match state.output_info.iter_mut().find(|(o, _)| o == wl_output) {
|
.outputs
|
||||||
Some((_, c)) => c,
|
.iter_mut()
|
||||||
None => {
|
.find(|o| o.global.name == *name)
|
||||||
let output_info = OutputInfo::new();
|
.expect("output");
|
||||||
state.output_info.push((wl_output.clone(), output_info));
|
|
||||||
&mut state.output_info.last_mut().unwrap().1
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
log::debug!("xdg_output {name} - {:?}", event);
|
||||||
match event {
|
match event {
|
||||||
zxdg_output_v1::Event::LogicalPosition { x, y } => {
|
zxdg_output_v1::Event::LogicalPosition { x, y } => {
|
||||||
output_info.position = (x, y);
|
output.pending_info.position = (x, y);
|
||||||
|
output.has_xdg_info = true;
|
||||||
}
|
}
|
||||||
zxdg_output_v1::Event::LogicalSize { width, height } => {
|
zxdg_output_v1::Event::LogicalSize { width, height } => {
|
||||||
output_info.size = (width, height);
|
output.pending_info.size = (width, height);
|
||||||
|
output.has_xdg_info = true;
|
||||||
|
}
|
||||||
|
zxdg_output_v1::Event::Done => {
|
||||||
|
log::warn!("Use of deprecated xdg-output event \"done\"");
|
||||||
|
state.update_output_info(*name);
|
||||||
}
|
}
|
||||||
zxdg_output_v1::Event::Done => {}
|
|
||||||
zxdg_output_v1::Event::Name { name } => {
|
zxdg_output_v1::Event::Name { name } => {
|
||||||
output_info.name = name;
|
output.pending_info.name = name;
|
||||||
|
output.has_xdg_info = true;
|
||||||
}
|
}
|
||||||
zxdg_output_v1::Event::Description { .. } => {}
|
zxdg_output_v1::Event::Description { description } => {
|
||||||
_ => {}
|
output.pending_info.description = description;
|
||||||
|
output.has_xdg_info = true;
|
||||||
|
}
|
||||||
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dispatch<WlOutput, ()> for State {
|
impl Dispatch<WlOutput, u32> for State {
|
||||||
fn event(
|
fn event(
|
||||||
state: &mut Self,
|
state: &mut Self,
|
||||||
_proxy: &WlOutput,
|
_wl_output: &WlOutput,
|
||||||
event: <WlOutput as wayland_client::Proxy>::Event,
|
event: <WlOutput as wayland_client::Proxy>::Event,
|
||||||
_data: &(),
|
name: &u32,
|
||||||
_conn: &Connection,
|
_conn: &Connection,
|
||||||
_qhandle: &QueueHandle<Self>,
|
_qhandle: &QueueHandle<Self>,
|
||||||
) {
|
) {
|
||||||
|
log::debug!("wl_output {name} - {:?}", event);
|
||||||
if let wl_output::Event::Done = event {
|
if let wl_output::Event::Done = event {
|
||||||
state.update_windows();
|
state.update_output_info(*name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user