mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2024-12-26 21:58:10 +01:00
Merge pull request #204 from LogicalOverflow/wlcs
Add wlcs tests Big thanks to @LogicalOverflow!
This commit is contained in:
commit
a21eb9bcec
15 changed files with 1176 additions and 12 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -9,5 +9,9 @@ target/
|
|||
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||
*.pdb
|
||||
|
||||
# Don't push local doc builds
|
||||
api/lua/doc/doc
|
||||
# This is a library
|
||||
api/rust/Cargo.lock
|
||||
# Don't push compiled WLCS
|
||||
wlcs
|
||||
|
|
60
Cargo.lock
generated
60
Cargo.lock
generated
|
@ -562,6 +562,15 @@ dependencies = [
|
|||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "container_of"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89f5bbeb86761f66a87f8e327265ea0111f82f1928a84037b9abedab9f79472b"
|
||||
dependencies = [
|
||||
"memoffset 0.6.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.4"
|
||||
|
@ -1461,6 +1470,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.9.1"
|
||||
|
@ -1532,6 +1550,17 @@ dependencies = [
|
|||
"jni-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.27.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.28.0"
|
||||
|
@ -1765,7 +1794,7 @@ dependencies = [
|
|||
"cliclack",
|
||||
"dircpy",
|
||||
"image",
|
||||
"nix",
|
||||
"nix 0.28.0",
|
||||
"pinnacle",
|
||||
"pinnacle-api",
|
||||
"pinnacle-api-defs",
|
||||
|
@ -3071,7 +3100,7 @@ dependencies = [
|
|||
"dlib",
|
||||
"libc",
|
||||
"log",
|
||||
"memoffset",
|
||||
"memoffset 0.9.1",
|
||||
"once_cell",
|
||||
"pkg-config",
|
||||
]
|
||||
|
@ -3409,6 +3438,33 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wlcs"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d99c305ce368db32f0c675a3a17abbfd4123a59f4a1c56c0ee70b372cb7609e"
|
||||
dependencies = [
|
||||
"container_of",
|
||||
"memoffset 0.9.1",
|
||||
"nix 0.27.1",
|
||||
"wayland-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wlcs_pinnacle"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"pinnacle",
|
||||
"pinnacle-api",
|
||||
"smithay",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"wayland-sys",
|
||||
"wlcs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x11-dl"
|
||||
version = "2.21.0"
|
||||
|
|
23
Cargo.toml
23
Cargo.toml
|
@ -1,5 +1,10 @@
|
|||
[workspace]
|
||||
members = ["pinnacle-api-defs", "api/rust", "api/rust/pinnacle-api-macros"]
|
||||
members = [
|
||||
"pinnacle-api-defs",
|
||||
"api/rust",
|
||||
"api/rust/pinnacle-api-macros",
|
||||
"wlcs_pinnacle",
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
authors = ["Ottatop <ottatop1227@gmail.com>"]
|
||||
|
@ -15,6 +20,9 @@ prost = "0.12.4"
|
|||
tonic = "0.11.0"
|
||||
tonic-reflection = "0.11.0"
|
||||
tonic-build = "0.11.0"
|
||||
# Tracing
|
||||
tracing = "0.1.40"
|
||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "registry"] }
|
||||
# API definitions
|
||||
pinnacle-api-defs = { path = "./pinnacle-api-defs" }
|
||||
# Misc.
|
||||
|
@ -23,6 +31,7 @@ xdg = "2.5.2"
|
|||
bitflags = "2.5.0"
|
||||
clap = { version = "4.5.4", features = ["derive"] }
|
||||
dircpy = "0.3.16"
|
||||
tempfile = "3.10.1"
|
||||
|
||||
########################################################################yo😎###########
|
||||
|
||||
|
@ -42,8 +51,8 @@ keywords = ["wayland", "compositor", "smithay", "lua"]
|
|||
# smithay is down there somewhere
|
||||
smithay-drm-extras = { git = "https://github.com/Smithay/smithay", rev = "c293ec7" }
|
||||
# Tracing
|
||||
tracing = "0.1.40"
|
||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "registry"] }
|
||||
tracing = { workspace = true }
|
||||
tracing-subscriber = { workspace = true }
|
||||
tracing-appender = "0.2.3"
|
||||
# Errors
|
||||
anyhow = { version = "1.0.81", features = ["backtrace"] }
|
||||
|
@ -76,8 +85,9 @@ dircpy = { workspace = true }
|
|||
chrono = "0.4.37"
|
||||
bytemuck = "1.15.0"
|
||||
pinnacle-api = { path = "./api/rust" }
|
||||
smithay = { workspace = true }
|
||||
|
||||
[dependencies.smithay]
|
||||
[workspace.dependencies.smithay]
|
||||
git = "https://github.com/Smithay/smithay"
|
||||
rev = "c293ec7"
|
||||
default-features = false
|
||||
|
@ -110,12 +120,13 @@ xdg = { workspace = true }
|
|||
|
||||
[dev-dependencies]
|
||||
temp-env = "0.3.6"
|
||||
tempfile = "3.10.1"
|
||||
tempfile = { workspace = true }
|
||||
test-log = { version = "0.2.15", default-features = false, features = ["trace"] }
|
||||
pinnacle = { path = ".", features = ["testing"] }
|
||||
pinnacle = { path = ".", features = ["wlcs"] }
|
||||
pinnacle-api = { path = "./api/rust" }
|
||||
|
||||
[features]
|
||||
testing = [
|
||||
"smithay/renderer_test",
|
||||
]
|
||||
wlcs = [ "testing" ]
|
||||
|
|
15
compile_wlcs.sh
Executable file
15
compile_wlcs.sh
Executable file
|
@ -0,0 +1,15 @@
|
|||
#!/bin/sh
|
||||
|
||||
WLCS_SHA=26c5a8cfef265b4ae021adebfec90d758c08792e
|
||||
|
||||
if [ -f "./wlcs/wlcs" ] && [ "$(cd wlcs; git rev-parse HEAD)" = "${WLCS_SHA}" ] ; then
|
||||
echo "WLCS commit 26c5a8c is already compiled"
|
||||
else
|
||||
echo "Compiling WLCS"
|
||||
git clone https://github.com/canonical/wlcs
|
||||
cd wlcs || exit
|
||||
# checkout a specific revision
|
||||
git reset --hard "${WLCS_SHA}"
|
||||
cmake -DWLCS_BUILD_ASAN=False -DWLCS_BUILD_TSAN=False -DWLCS_BUILD_UBSAN=False -DCMAKE_EXPORT_COMPILE_COMMANDS=1 .
|
||||
make
|
||||
fi
|
|
@ -31,6 +31,12 @@
|
|||
rust-analyzer
|
||||
cargo-outdated
|
||||
|
||||
# wlcs
|
||||
(writeScriptBin "wlcs" ''
|
||||
#!/bin/sh
|
||||
${wlcs}/libexec/wlcs/wlcs "$@"
|
||||
'')
|
||||
|
||||
wayland
|
||||
|
||||
# build time stuff
|
||||
|
|
|
@ -45,6 +45,8 @@ use self::{udev::Udev, winit::Winit};
|
|||
pub mod dummy;
|
||||
pub mod udev;
|
||||
pub mod winit;
|
||||
#[cfg(feature = "wlcs")]
|
||||
pub mod wlcs;
|
||||
|
||||
pub enum Backend {
|
||||
/// The compositor is running in a Winit window
|
||||
|
|
|
@ -16,6 +16,8 @@ use smithay::{
|
|||
|
||||
use crate::state::State;
|
||||
|
||||
#[cfg(feature = "wlcs")]
|
||||
use super::wlcs::Wlcs;
|
||||
use super::Backend;
|
||||
use super::BackendData;
|
||||
|
||||
|
@ -24,6 +26,8 @@ pub const DUMMY_OUTPUT_NAME: &str = "Dummy Window";
|
|||
pub struct Dummy {
|
||||
pub renderer: DummyRenderer,
|
||||
// pub dmabuf_state: (DmabufState, DmabufGlobal, Option<DmabufFeedback>),
|
||||
#[cfg(feature = "wlcs")]
|
||||
pub wlcs_state: Wlcs,
|
||||
}
|
||||
|
||||
impl Backend {
|
||||
|
@ -63,7 +67,7 @@ pub fn setup_dummy(
|
|||
size: (0, 0).into(),
|
||||
subpixel: Subpixel::Unknown,
|
||||
make: "Pinnacle".to_string(),
|
||||
model: "Winit Window".to_string(),
|
||||
model: "Dummy Window".to_string(),
|
||||
};
|
||||
|
||||
let output = Output::new(DUMMY_OUTPUT_NAME.to_string(), physical_properties);
|
||||
|
@ -91,6 +95,8 @@ pub fn setup_dummy(
|
|||
let backend = Dummy {
|
||||
renderer,
|
||||
// dmabuf_state,
|
||||
#[cfg(feature = "wlcs")]
|
||||
wlcs_state: Wlcs::default(),
|
||||
};
|
||||
|
||||
let mut state = State::init(
|
||||
|
|
135
src/backend/wlcs.rs
Normal file
135
src/backend/wlcs.rs
Normal file
|
@ -0,0 +1,135 @@
|
|||
use std::{collections::HashMap, path::Path};
|
||||
|
||||
use smithay::{
|
||||
backend::renderer::{test::DummyRenderer, ImportMemWl},
|
||||
output::{Output, Subpixel},
|
||||
reexports::{
|
||||
calloop::{self, EventLoop},
|
||||
wayland_server::{Client, Display},
|
||||
},
|
||||
utils::Transform,
|
||||
};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::{
|
||||
state::{State, WithState},
|
||||
tag::TagId,
|
||||
};
|
||||
|
||||
use super::{dummy::Dummy, Backend};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Wlcs {
|
||||
pub clients: HashMap<i32, Client>,
|
||||
}
|
||||
|
||||
impl Backend {
|
||||
pub fn wlcs_mut(&mut self) -> &mut Wlcs {
|
||||
let Backend::Dummy(dummy) = self else { unreachable!() };
|
||||
&mut dummy.wlcs_state
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_wlcs_dummy() -> anyhow::Result<(State, EventLoop<'static, State>)> {
|
||||
let event_loop: EventLoop<State> = EventLoop::try_new()?;
|
||||
|
||||
let display: Display<State> = Display::new()?;
|
||||
let display_handle = display.handle();
|
||||
|
||||
let loop_handle = event_loop.handle();
|
||||
|
||||
let mode = smithay::output::Mode {
|
||||
size: (1920, 1080).into(),
|
||||
refresh: 60_000,
|
||||
};
|
||||
|
||||
let physical_properties = smithay::output::PhysicalProperties {
|
||||
size: (0, 0).into(),
|
||||
subpixel: Subpixel::Unknown,
|
||||
make: "Pinnacle".to_string(),
|
||||
model: "Dummy Window".to_string(),
|
||||
};
|
||||
|
||||
let output = Output::new("Pinnacle Window".to_string(), physical_properties);
|
||||
|
||||
output.create_global::<State>(&display_handle);
|
||||
|
||||
output.change_current_state(
|
||||
Some(mode),
|
||||
Some(Transform::Flipped180),
|
||||
None,
|
||||
Some((0, 0).into()),
|
||||
);
|
||||
|
||||
output.set_preferred(mode);
|
||||
|
||||
let renderer = DummyRenderer::new();
|
||||
let shm_formats = renderer.shm_formats();
|
||||
|
||||
let backend = Dummy {
|
||||
renderer,
|
||||
wlcs_state: Wlcs::default(),
|
||||
};
|
||||
|
||||
let mut state = State::init(
|
||||
super::Backend::Dummy(backend),
|
||||
display,
|
||||
event_loop.get_signal(),
|
||||
loop_handle,
|
||||
false,
|
||||
None,
|
||||
)?;
|
||||
|
||||
state.output_focus_stack.set_focus(output.clone());
|
||||
|
||||
state.shm_state.update_formats(shm_formats);
|
||||
|
||||
state.space.map_output(&output, (0, 0));
|
||||
|
||||
Ok((state, event_loop))
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub fn start_wlcs_config<F>(&mut self, socket_dir: &Path, run_config: F) -> anyhow::Result<()>
|
||||
where
|
||||
F: FnOnce() + Send + 'static,
|
||||
{
|
||||
// Clear state
|
||||
debug!("Clearing tags");
|
||||
for output in self.space.outputs() {
|
||||
output.with_state_mut(|state| state.tags.clear());
|
||||
}
|
||||
|
||||
TagId::reset();
|
||||
|
||||
debug!("Clearing input state");
|
||||
|
||||
self.input_state.clear();
|
||||
|
||||
self.config.clear(&self.loop_handle);
|
||||
|
||||
self.signal_state.clear();
|
||||
|
||||
self.input_state.reload_keybind = None;
|
||||
self.input_state.kill_keybind = None;
|
||||
|
||||
if self.grpc_server_join_handle.is_none() {
|
||||
self.start_grpc_server(socket_dir)?;
|
||||
}
|
||||
|
||||
let (pinger, ping_source) = calloop::ping::make_ping()?;
|
||||
|
||||
let token = self
|
||||
.loop_handle
|
||||
.insert_source(ping_source, move |_, _, _state| {})?;
|
||||
|
||||
std::thread::spawn(move || {
|
||||
run_config();
|
||||
pinger.ping();
|
||||
});
|
||||
|
||||
self.config.config_reload_on_crash_token = Some(token);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -184,7 +184,7 @@ pub struct Config {
|
|||
pub connector_saved_states: HashMap<OutputName, ConnectorSavedState>,
|
||||
|
||||
pub config_join_handle: Option<JoinHandle<()>>,
|
||||
config_reload_on_crash_token: Option<RegistrationToken>,
|
||||
pub(crate) config_reload_on_crash_token: Option<RegistrationToken>,
|
||||
|
||||
pub shutdown_sender:
|
||||
Option<tokio::sync::mpsc::UnboundedSender<Result<ShutdownWatchResponse, tonic::Status>>>,
|
||||
|
@ -208,7 +208,7 @@ impl Config {
|
|||
.unwrap_or_else(|| get_config_dir(xdg_base_dirs))
|
||||
}
|
||||
|
||||
fn clear(&mut self, loop_handle: &LoopHandle<State>) {
|
||||
pub(crate) fn clear(&mut self, loop_handle: &LoopHandle<State>) {
|
||||
self.window_rules.clear();
|
||||
self.connector_saved_states.clear();
|
||||
if let Some(join_handle) = self.config_join_handle.take() {
|
||||
|
|
|
@ -483,7 +483,7 @@ mod output {
|
|||
local props = Pinnacle.output.get_focused():props()
|
||||
|
||||
assert(props.make == "Pinnacle")
|
||||
assert(props.model == "Winit Window")
|
||||
assert(props.model == "Dummy Window")
|
||||
assert(props.x == 0)
|
||||
assert(props.y == 0)
|
||||
assert(props.logical_width == 1920)
|
||||
|
|
24
wlcs_pinnacle/Cargo.toml
Normal file
24
wlcs_pinnacle/Cargo.toml
Normal file
|
@ -0,0 +1,24 @@
|
|||
[package]
|
||||
name = "wlcs_pinnacle"
|
||||
version = "0.0.1"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
repository.workspace = true
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
smithay = { workspace = true }
|
||||
pinnacle = { path = "..", features = [ "wlcs" ] }
|
||||
pinnacle-api = { path = "../api/rust" }
|
||||
wayland-sys = { version = "0.31.1", features = ["client", "server"] }
|
||||
wlcs = "0.1"
|
||||
|
||||
tracing = { workspace = true }
|
||||
tracing-subscriber = { workspace = true }
|
||||
|
||||
tokio = { workspace = true, features = ["net", "rt"] }
|
||||
|
||||
tempfile = { workspace = true }
|
36
wlcs_pinnacle/src/config.rs
Normal file
36
wlcs_pinnacle/src/config.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
use pinnacle::state::State;
|
||||
mod inner {
|
||||
use pinnacle_api::layout::{CyclingLayoutManager, MasterStackLayout};
|
||||
use pinnacle_api::window::rules::{WindowRule, WindowRuleCondition};
|
||||
use pinnacle_api::ApiModules;
|
||||
|
||||
#[pinnacle_api::config(modules)]
|
||||
async fn main() {
|
||||
#[allow(unused_variables)]
|
||||
let ApiModules { layout, window, .. } = modules;
|
||||
|
||||
window.add_window_rule(
|
||||
WindowRuleCondition::default().all(vec![]),
|
||||
WindowRule::new().floating(true),
|
||||
);
|
||||
|
||||
let _layout_requester = layout.set_manager(CyclingLayoutManager::new([
|
||||
Box::<MasterStackLayout>::default() as _,
|
||||
]));
|
||||
}
|
||||
|
||||
pub(crate) fn start_config() {
|
||||
main()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_config(state: &mut State) {
|
||||
let temp_dir = tempfile::tempdir().expect("failed to setup temp dir for socket");
|
||||
let socket_dir = temp_dir.path().to_owned();
|
||||
state
|
||||
.start_wlcs_config(&socket_dir, move || {
|
||||
inner::start_config();
|
||||
drop(temp_dir);
|
||||
})
|
||||
.expect("failed to start wlcs config");
|
||||
}
|
332
wlcs_pinnacle/src/input_backend.rs
Normal file
332
wlcs_pinnacle/src/input_backend.rs
Normal file
|
@ -0,0 +1,332 @@
|
|||
use core::hash::Hash;
|
||||
|
||||
use smithay::{
|
||||
backend::input::{
|
||||
AbsolutePositionEvent, ButtonState, Device, DeviceCapability, Event, InputBackend,
|
||||
InputEvent, PointerButtonEvent, PointerMotionAbsoluteEvent, PointerMotionEvent,
|
||||
TouchDownEvent, TouchEvent, TouchMotionEvent, TouchSlot, TouchUpEvent, UnusedEvent,
|
||||
},
|
||||
utils::{Logical, Point},
|
||||
};
|
||||
|
||||
pub struct WlcsInputBackend {}
|
||||
|
||||
impl InputBackend for WlcsInputBackend {
|
||||
type Device = WlcsDevice;
|
||||
type KeyboardKeyEvent = UnusedEvent;
|
||||
type PointerAxisEvent = UnusedEvent;
|
||||
type PointerButtonEvent = WlcsPointerButtonEvent;
|
||||
type PointerMotionEvent = WlcsPointerMotionEvent;
|
||||
type PointerMotionAbsoluteEvent = WlcsPointerMotionAbsoluteEvent;
|
||||
type GestureSwipeBeginEvent = UnusedEvent;
|
||||
type GestureSwipeUpdateEvent = UnusedEvent;
|
||||
type GestureSwipeEndEvent = UnusedEvent;
|
||||
type GesturePinchBeginEvent = UnusedEvent;
|
||||
type GesturePinchUpdateEvent = UnusedEvent;
|
||||
type GesturePinchEndEvent = UnusedEvent;
|
||||
type GestureHoldBeginEvent = UnusedEvent;
|
||||
type GestureHoldEndEvent = UnusedEvent;
|
||||
type TouchDownEvent = WlcsTouchDownEvent;
|
||||
type TouchUpEvent = WlcsTouchUpEvent;
|
||||
type TouchMotionEvent = WlcsTouchMotionEvent;
|
||||
type TouchCancelEvent = UnusedEvent;
|
||||
type TouchFrameEvent = UnusedEvent;
|
||||
type TabletToolAxisEvent = UnusedEvent;
|
||||
type TabletToolProximityEvent = UnusedEvent;
|
||||
type TabletToolTipEvent = UnusedEvent;
|
||||
type TabletToolButtonEvent = UnusedEvent;
|
||||
type SwitchToggleEvent = UnusedEvent;
|
||||
type SpecialEvent = ();
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct WlcsDevice {
|
||||
pub device_id: u32,
|
||||
pub capability: DeviceCapability,
|
||||
}
|
||||
|
||||
impl Hash for WlcsDevice {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.device_id.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for WlcsDevice {
|
||||
fn id(&self) -> String {
|
||||
format!("{}", self.device_id)
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
format!("wlcs-device-{}", self.device_id)
|
||||
}
|
||||
|
||||
fn has_capability(&self, capability: DeviceCapability) -> bool {
|
||||
self.capability == capability
|
||||
}
|
||||
|
||||
fn usb_id(&self) -> Option<(u32, u32)> {
|
||||
None
|
||||
}
|
||||
|
||||
fn syspath(&self) -> Option<std::path::PathBuf> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WlcsPointerButtonEvent {
|
||||
pub device_id: u32,
|
||||
pub time: u64,
|
||||
pub button_code: u32,
|
||||
pub state: ButtonState,
|
||||
}
|
||||
|
||||
impl From<WlcsPointerButtonEvent> for InputEvent<WlcsInputBackend> {
|
||||
fn from(event: WlcsPointerButtonEvent) -> Self {
|
||||
InputEvent::<WlcsInputBackend>::PointerButton { event }
|
||||
}
|
||||
}
|
||||
|
||||
impl Event<WlcsInputBackend> for WlcsPointerButtonEvent {
|
||||
fn time(&self) -> u64 {
|
||||
self.time
|
||||
}
|
||||
|
||||
fn device(&self) -> <WlcsInputBackend as InputBackend>::Device {
|
||||
WlcsDevice {
|
||||
device_id: self.device_id,
|
||||
capability: DeviceCapability::Pointer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PointerButtonEvent<WlcsInputBackend> for WlcsPointerButtonEvent {
|
||||
fn button_code(&self) -> u32 {
|
||||
self.button_code
|
||||
}
|
||||
|
||||
fn state(&self) -> ButtonState {
|
||||
self.state
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WlcsPointerMotionEvent {
|
||||
pub device_id: u32,
|
||||
pub time: u64,
|
||||
pub delta: Point<f64, Logical>,
|
||||
}
|
||||
|
||||
impl From<WlcsPointerMotionEvent> for InputEvent<WlcsInputBackend> {
|
||||
fn from(event: WlcsPointerMotionEvent) -> Self {
|
||||
InputEvent::<WlcsInputBackend>::PointerMotion { event }
|
||||
}
|
||||
}
|
||||
|
||||
impl Event<WlcsInputBackend> for WlcsPointerMotionEvent {
|
||||
fn time(&self) -> u64 {
|
||||
self.time
|
||||
}
|
||||
|
||||
fn device(&self) -> <WlcsInputBackend as InputBackend>::Device {
|
||||
WlcsDevice {
|
||||
device_id: self.device_id,
|
||||
capability: DeviceCapability::Pointer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PointerMotionEvent<WlcsInputBackend> for WlcsPointerMotionEvent {
|
||||
fn delta_x(&self) -> f64 {
|
||||
self.delta.x
|
||||
}
|
||||
|
||||
fn delta_y(&self) -> f64 {
|
||||
self.delta.y
|
||||
}
|
||||
|
||||
fn delta_x_unaccel(&self) -> f64 {
|
||||
self.delta_x()
|
||||
}
|
||||
|
||||
fn delta_y_unaccel(&self) -> f64 {
|
||||
self.delta_y()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WlcsPointerMotionAbsoluteEvent {
|
||||
pub device_id: u32,
|
||||
pub time: u64,
|
||||
pub position: Point<f64, Logical>,
|
||||
}
|
||||
|
||||
impl From<WlcsPointerMotionAbsoluteEvent> for InputEvent<WlcsInputBackend> {
|
||||
fn from(event: WlcsPointerMotionAbsoluteEvent) -> Self {
|
||||
InputEvent::<WlcsInputBackend>::PointerMotionAbsolute { event }
|
||||
}
|
||||
}
|
||||
|
||||
impl Event<WlcsInputBackend> for WlcsPointerMotionAbsoluteEvent {
|
||||
fn time(&self) -> u64 {
|
||||
self.time
|
||||
}
|
||||
|
||||
fn device(&self) -> <WlcsInputBackend as InputBackend>::Device {
|
||||
WlcsDevice {
|
||||
device_id: self.device_id,
|
||||
capability: DeviceCapability::Pointer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AbsolutePositionEvent<WlcsInputBackend> for WlcsPointerMotionAbsoluteEvent {
|
||||
fn x(&self) -> f64 {
|
||||
self.position.x
|
||||
}
|
||||
|
||||
fn y(&self) -> f64 {
|
||||
self.position.y
|
||||
}
|
||||
|
||||
fn x_transformed(&self, _width: i32) -> f64 {
|
||||
self.x()
|
||||
}
|
||||
|
||||
fn y_transformed(&self, _height: i32) -> f64 {
|
||||
self.y()
|
||||
}
|
||||
}
|
||||
|
||||
impl PointerMotionAbsoluteEvent<WlcsInputBackend> for WlcsPointerMotionAbsoluteEvent {}
|
||||
|
||||
pub struct WlcsTouchDownEvent {
|
||||
pub device_id: u32,
|
||||
pub time: u64,
|
||||
pub position: Point<f64, Logical>,
|
||||
}
|
||||
|
||||
impl From<WlcsTouchDownEvent> for InputEvent<WlcsInputBackend> {
|
||||
fn from(event: WlcsTouchDownEvent) -> Self {
|
||||
InputEvent::<WlcsInputBackend>::TouchDown { event }
|
||||
}
|
||||
}
|
||||
|
||||
impl Event<WlcsInputBackend> for WlcsTouchDownEvent {
|
||||
fn time(&self) -> u64 {
|
||||
self.time
|
||||
}
|
||||
|
||||
fn device(&self) -> <WlcsInputBackend as InputBackend>::Device {
|
||||
WlcsDevice {
|
||||
device_id: self.device_id,
|
||||
capability: DeviceCapability::Touch,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TouchEvent<WlcsInputBackend> for WlcsTouchDownEvent {
|
||||
fn slot(&self) -> TouchSlot {
|
||||
None.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl AbsolutePositionEvent<WlcsInputBackend> for WlcsTouchDownEvent {
|
||||
fn x(&self) -> f64 {
|
||||
self.position.x
|
||||
}
|
||||
|
||||
fn y(&self) -> f64 {
|
||||
self.position.y
|
||||
}
|
||||
|
||||
fn x_transformed(&self, _width: i32) -> f64 {
|
||||
self.x()
|
||||
}
|
||||
|
||||
fn y_transformed(&self, _height: i32) -> f64 {
|
||||
self.y()
|
||||
}
|
||||
}
|
||||
|
||||
impl TouchDownEvent<WlcsInputBackend> for WlcsTouchDownEvent {}
|
||||
|
||||
pub struct WlcsTouchUpEvent {
|
||||
pub device_id: u32,
|
||||
pub time: u64,
|
||||
}
|
||||
|
||||
impl From<WlcsTouchUpEvent> for InputEvent<WlcsInputBackend> {
|
||||
fn from(event: WlcsTouchUpEvent) -> Self {
|
||||
InputEvent::<WlcsInputBackend>::TouchUp { event }
|
||||
}
|
||||
}
|
||||
|
||||
impl Event<WlcsInputBackend> for WlcsTouchUpEvent {
|
||||
fn time(&self) -> u64 {
|
||||
self.time
|
||||
}
|
||||
|
||||
fn device(&self) -> <WlcsInputBackend as InputBackend>::Device {
|
||||
WlcsDevice {
|
||||
device_id: self.device_id,
|
||||
capability: DeviceCapability::Touch,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TouchEvent<WlcsInputBackend> for WlcsTouchUpEvent {
|
||||
fn slot(&self) -> TouchSlot {
|
||||
None.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl TouchUpEvent<WlcsInputBackend> for WlcsTouchUpEvent {}
|
||||
|
||||
pub struct WlcsTouchMotionEvent {
|
||||
pub device_id: u32,
|
||||
pub time: u64,
|
||||
pub position: Point<f64, Logical>,
|
||||
}
|
||||
|
||||
impl From<WlcsTouchMotionEvent> for InputEvent<WlcsInputBackend> {
|
||||
fn from(event: WlcsTouchMotionEvent) -> Self {
|
||||
InputEvent::<WlcsInputBackend>::TouchMotion { event }
|
||||
}
|
||||
}
|
||||
|
||||
impl Event<WlcsInputBackend> for WlcsTouchMotionEvent {
|
||||
fn time(&self) -> u64 {
|
||||
self.time
|
||||
}
|
||||
|
||||
fn device(&self) -> <WlcsInputBackend as InputBackend>::Device {
|
||||
WlcsDevice {
|
||||
device_id: self.device_id,
|
||||
capability: DeviceCapability::Touch,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TouchEvent<WlcsInputBackend> for WlcsTouchMotionEvent {
|
||||
fn slot(&self) -> TouchSlot {
|
||||
None.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl AbsolutePositionEvent<WlcsInputBackend> for WlcsTouchMotionEvent {
|
||||
fn x(&self) -> f64 {
|
||||
self.position.x
|
||||
}
|
||||
|
||||
fn y(&self) -> f64 {
|
||||
self.position.y
|
||||
}
|
||||
|
||||
fn x_transformed(&self, _width: i32) -> f64 {
|
||||
self.x()
|
||||
}
|
||||
|
||||
fn y_transformed(&self, _height: i32) -> f64 {
|
||||
self.y()
|
||||
}
|
||||
}
|
||||
|
||||
impl TouchMotionEvent<WlcsInputBackend> for WlcsTouchMotionEvent {}
|
327
wlcs_pinnacle/src/lib.rs
Normal file
327
wlcs_pinnacle/src/lib.rs
Normal file
|
@ -0,0 +1,327 @@
|
|||
pub(crate) mod config;
|
||||
mod input_backend;
|
||||
mod main_loop;
|
||||
|
||||
use std::{
|
||||
io,
|
||||
os::{
|
||||
fd::{AsRawFd, OwnedFd},
|
||||
unix::net::UnixStream,
|
||||
},
|
||||
sync::{
|
||||
atomic::{AtomicU32, Ordering},
|
||||
Once,
|
||||
},
|
||||
thread::{spawn, JoinHandle},
|
||||
};
|
||||
|
||||
use smithay::{
|
||||
reexports::calloop::channel::{channel, Sender},
|
||||
utils::{Logical, Point},
|
||||
};
|
||||
use tracing::{info, warn};
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Layer};
|
||||
use wayland_sys::{
|
||||
client::{wayland_client_handle, wl_display, wl_proxy},
|
||||
common::{wl_fixed_t, wl_fixed_to_double},
|
||||
ffi_dispatch,
|
||||
};
|
||||
use wlcs::{
|
||||
extension_list,
|
||||
ffi_display_server_api::{
|
||||
WlcsExtensionDescriptor, WlcsIntegrationDescriptor, WlcsServerIntegration,
|
||||
},
|
||||
ffi_wrappers::wlcs_server,
|
||||
wlcs_server_integration, Pointer, Touch, Wlcs,
|
||||
};
|
||||
|
||||
wlcs_server_integration!(PinnacleHandle);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum WlcsEvent {
|
||||
Stop,
|
||||
NewClient {
|
||||
stream: UnixStream,
|
||||
client_id: i32,
|
||||
},
|
||||
PositionWindow {
|
||||
client_id: i32,
|
||||
surface_id: u32,
|
||||
location: Point<i32, Logical>,
|
||||
},
|
||||
NewPointer {
|
||||
device_id: u32,
|
||||
},
|
||||
PointerMoveRelative {
|
||||
device_id: u32,
|
||||
delta: Point<f64, Logical>,
|
||||
},
|
||||
PointerMoveAbsolute {
|
||||
device_id: u32,
|
||||
position: Point<f64, Logical>,
|
||||
},
|
||||
PointerButton {
|
||||
device_id: u32,
|
||||
button_id: i32,
|
||||
pressed: bool,
|
||||
},
|
||||
NewTouch {
|
||||
device_id: u32,
|
||||
},
|
||||
TouchDown {
|
||||
device_id: u32,
|
||||
position: Point<f64, Logical>,
|
||||
},
|
||||
TouchMove {
|
||||
device_id: u32,
|
||||
position: Point<f64, Logical>,
|
||||
},
|
||||
TouchUp {
|
||||
device_id: u32,
|
||||
},
|
||||
}
|
||||
|
||||
struct PinnacleConnection {
|
||||
sender: Sender<WlcsEvent>,
|
||||
join: JoinHandle<()>,
|
||||
}
|
||||
|
||||
impl PinnacleConnection {
|
||||
fn start() -> Self {
|
||||
let (sender, receiver) = channel();
|
||||
let join = spawn(move || main_loop::run(receiver));
|
||||
Self { sender, join }
|
||||
}
|
||||
}
|
||||
|
||||
struct PinnacleHandle {
|
||||
server_conn: Option<PinnacleConnection>,
|
||||
}
|
||||
|
||||
static SUPPORTED_EXTENSIONS: &[WlcsExtensionDescriptor] = extension_list!(
|
||||
// Skip reasons:
|
||||
// 5 Missing extension: gtk_primary_selection_device_manager>= 1
|
||||
// 1 Missing extension: wlcs_non_existent_extension>= 1
|
||||
// 89 Missing extension: wl_shell>= 2
|
||||
// 1 Missing extension: xdg_not_really_an_extension>= 1
|
||||
// 30 Missing extension: zwlr_foreign_toplevel_manager_v1>= 1
|
||||
// 12 Missing extension: zwlr_virtual_pointer_manager_v1>= 1
|
||||
// 15 Missing extension: zwp_pointer_constraints_v1>= 1
|
||||
// 3 Missing extension: zwp_relative_pointer_manager_v1>= 1
|
||||
// 12 Missing extension: zwp_text_input_manager_v2>= 1
|
||||
// 11 Missing extension: zwp_text_input_manager_v3>= 1
|
||||
// 180 Missing extension: zxdg_shell_v6>= 1
|
||||
|
||||
// mostly from https://github.com/Smithay/smithay/issues/781
|
||||
("wl_compositor", 6),
|
||||
("wl_subcompositor", 1),
|
||||
("wl_shm", 1),
|
||||
("wl_data_device_manager", 3),
|
||||
("wl_seat", 9),
|
||||
("wl_output", 4),
|
||||
("wp_presentation", 1),
|
||||
("wp_viewporter", 1),
|
||||
("xdg_shell", 6),
|
||||
("linux-dmabuf-v1", 5),
|
||||
("xdg_shell", 6),
|
||||
);
|
||||
|
||||
static DESCRIPTOR: WlcsIntegrationDescriptor = WlcsIntegrationDescriptor {
|
||||
version: 1,
|
||||
num_extensions: SUPPORTED_EXTENSIONS.len(),
|
||||
supported_extensions: SUPPORTED_EXTENSIONS.as_ptr(),
|
||||
};
|
||||
|
||||
static DEVICE_ID: AtomicU32 = AtomicU32::new(0);
|
||||
|
||||
fn new_device_id() -> u32 {
|
||||
DEVICE_ID.fetch_add(1, Ordering::Relaxed)
|
||||
}
|
||||
|
||||
fn init() {
|
||||
let env_filter = EnvFilter::try_from_default_env();
|
||||
|
||||
let stdout_env_filter = env_filter.unwrap_or_else(|_| EnvFilter::new("info"));
|
||||
let stdout_layer = tracing_subscriber::fmt::layer()
|
||||
.compact()
|
||||
.with_writer(std::io::stdout)
|
||||
.with_filter(stdout_env_filter);
|
||||
|
||||
tracing_subscriber::registry().with(stdout_layer).init();
|
||||
}
|
||||
|
||||
static INIT_ONCE: Once = Once::new();
|
||||
|
||||
impl Wlcs for PinnacleHandle {
|
||||
type Pointer = PointerHandle;
|
||||
type Touch = TouchHandle;
|
||||
|
||||
fn new() -> Self {
|
||||
INIT_ONCE.call_once(init);
|
||||
Self { server_conn: None }
|
||||
}
|
||||
|
||||
fn start(&mut self) {
|
||||
self.server_conn = Some(PinnacleConnection::start());
|
||||
}
|
||||
|
||||
fn stop(&mut self) {
|
||||
if let Some(conn) = self.server_conn.take() {
|
||||
let _ = conn.sender.send(WlcsEvent::Stop);
|
||||
let _ = conn.join.join();
|
||||
}
|
||||
}
|
||||
|
||||
fn create_client_socket(&self) -> io::Result<OwnedFd> {
|
||||
info!("new client start");
|
||||
let conn = self
|
||||
.server_conn
|
||||
.as_ref()
|
||||
.ok_or(io::Error::from(io::ErrorKind::NotFound))?;
|
||||
|
||||
let (client, server) = UnixStream::pair()?;
|
||||
|
||||
conn.sender
|
||||
.send(WlcsEvent::NewClient {
|
||||
stream: server,
|
||||
client_id: client.as_raw_fd(),
|
||||
})
|
||||
.map_err(|e| {
|
||||
warn!("failed to send NewClient event");
|
||||
io::Error::new(io::ErrorKind::ConnectionReset, e)
|
||||
})?;
|
||||
|
||||
info!("new client end");
|
||||
Ok(client.into())
|
||||
}
|
||||
|
||||
fn position_window_absolute(
|
||||
&self,
|
||||
display: *mut wl_display,
|
||||
surface: *mut wl_proxy,
|
||||
x: i32,
|
||||
y: i32,
|
||||
) {
|
||||
if let Some(conn) = &self.server_conn {
|
||||
let client_id =
|
||||
unsafe { ffi_dispatch!(wayland_client_handle(), wl_display_get_fd, display) };
|
||||
let surface_id =
|
||||
unsafe { ffi_dispatch!(wayland_client_handle(), wl_proxy_get_id, surface) };
|
||||
conn.sender
|
||||
.send(WlcsEvent::PositionWindow {
|
||||
client_id,
|
||||
surface_id,
|
||||
location: (x, y).into(),
|
||||
})
|
||||
.expect("failed to send position_window_absolute");
|
||||
}
|
||||
}
|
||||
|
||||
fn create_pointer(&mut self) -> Option<Self::Pointer> {
|
||||
let device_id = new_device_id();
|
||||
self.server_conn
|
||||
.as_ref()
|
||||
.map(|conn| conn.sender.clone())
|
||||
.map(|sender| {
|
||||
sender
|
||||
.send(WlcsEvent::NewPointer { device_id })
|
||||
.expect("failed to send new_pointer");
|
||||
PointerHandle { device_id, sender }
|
||||
})
|
||||
}
|
||||
|
||||
fn create_touch(&mut self) -> Option<Self::Touch> {
|
||||
let device_id = new_device_id();
|
||||
self.server_conn
|
||||
.as_ref()
|
||||
.map(|conn| conn.sender.clone())
|
||||
.map(|sender| {
|
||||
sender
|
||||
.send(WlcsEvent::NewTouch { device_id })
|
||||
.expect("failed to send new_touch");
|
||||
TouchHandle { device_id, sender }
|
||||
})
|
||||
}
|
||||
|
||||
fn get_descriptor(&self) -> &WlcsIntegrationDescriptor {
|
||||
&DESCRIPTOR
|
||||
}
|
||||
}
|
||||
|
||||
struct PointerHandle {
|
||||
device_id: u32,
|
||||
sender: Sender<WlcsEvent>,
|
||||
}
|
||||
|
||||
impl Pointer for PointerHandle {
|
||||
fn move_absolute(&mut self, x: wl_fixed_t, y: wl_fixed_t) {
|
||||
self.sender
|
||||
.send(WlcsEvent::PointerMoveAbsolute {
|
||||
device_id: self.device_id,
|
||||
position: (wl_fixed_to_double(x), wl_fixed_to_double(y)).into(),
|
||||
})
|
||||
.expect("failed to send move_absolute");
|
||||
}
|
||||
|
||||
fn move_relative(&mut self, dx: wl_fixed_t, dy: wl_fixed_t) {
|
||||
self.sender
|
||||
.send(WlcsEvent::PointerMoveRelative {
|
||||
device_id: self.device_id,
|
||||
delta: (wl_fixed_to_double(dx), wl_fixed_to_double(dy)).into(),
|
||||
})
|
||||
.expect("failed to send move_relative");
|
||||
}
|
||||
|
||||
fn button_up(&mut self, button: i32) {
|
||||
self.sender
|
||||
.send(WlcsEvent::PointerButton {
|
||||
device_id: self.device_id,
|
||||
button_id: button,
|
||||
pressed: false,
|
||||
})
|
||||
.expect("failed to send button_up");
|
||||
}
|
||||
|
||||
fn button_down(&mut self, button: i32) {
|
||||
self.sender
|
||||
.send(WlcsEvent::PointerButton {
|
||||
device_id: self.device_id,
|
||||
button_id: button,
|
||||
pressed: true,
|
||||
})
|
||||
.expect("failed to send button_down");
|
||||
}
|
||||
}
|
||||
|
||||
struct TouchHandle {
|
||||
device_id: u32,
|
||||
sender: Sender<WlcsEvent>,
|
||||
}
|
||||
|
||||
impl Touch for TouchHandle {
|
||||
fn touch_down(&mut self, x: wl_fixed_t, y: wl_fixed_t) {
|
||||
self.sender
|
||||
.send(WlcsEvent::TouchDown {
|
||||
device_id: self.device_id,
|
||||
position: (wl_fixed_to_double(x), wl_fixed_to_double(y)).into(),
|
||||
})
|
||||
.expect("failed to send touch_down");
|
||||
}
|
||||
|
||||
fn touch_move(&mut self, x: wl_fixed_t, y: wl_fixed_t) {
|
||||
self.sender
|
||||
.send(WlcsEvent::TouchMove {
|
||||
device_id: self.device_id,
|
||||
position: (wl_fixed_to_double(x), wl_fixed_to_double(y)).into(),
|
||||
})
|
||||
.expect("failed to send touch_move");
|
||||
}
|
||||
|
||||
fn touch_up(&mut self) {
|
||||
self.sender
|
||||
.send(WlcsEvent::TouchUp {
|
||||
device_id: self.device_id,
|
||||
})
|
||||
.expect("failed to send touch_up");
|
||||
}
|
||||
}
|
210
wlcs_pinnacle/src/main_loop.rs
Normal file
210
wlcs_pinnacle/src/main_loop.rs
Normal file
|
@ -0,0 +1,210 @@
|
|||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
use pinnacle::{
|
||||
backend::wlcs::setup_wlcs_dummy,
|
||||
state::{ClientState, State, WithState},
|
||||
window::window_state::FloatingOrTiled,
|
||||
};
|
||||
use smithay::{
|
||||
backend::input::{ButtonState, DeviceCapability, InputEvent},
|
||||
reexports::{
|
||||
calloop::channel::{Channel, Event},
|
||||
wayland_server::{Client, Resource},
|
||||
},
|
||||
utils::Rectangle,
|
||||
wayland::seat::WaylandFocus,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
config::run_config,
|
||||
input_backend::{
|
||||
WlcsDevice, WlcsInputBackend, WlcsPointerButtonEvent, WlcsPointerMotionAbsoluteEvent,
|
||||
WlcsPointerMotionEvent, WlcsTouchDownEvent, WlcsTouchUpEvent,
|
||||
},
|
||||
WlcsEvent,
|
||||
};
|
||||
|
||||
pub(crate) fn run(channel: Channel<WlcsEvent>) {
|
||||
let (mut state, mut event_loop) = setup_wlcs_dummy().expect("failed to setup dummy backend");
|
||||
|
||||
event_loop
|
||||
.handle()
|
||||
.insert_source(channel, move |event, &mut (), data| match event {
|
||||
Event::Msg(msg) => handle_event(msg, data),
|
||||
Event::Closed => handle_event(WlcsEvent::Stop, data),
|
||||
})
|
||||
.expect("failed to add wlcs event handler");
|
||||
|
||||
// FIXME: a better way to deal with tokio here?
|
||||
let rt = tokio::runtime::Runtime::new().expect("failed to create tokio runtime");
|
||||
let _handle = rt.enter();
|
||||
|
||||
// FIXME: once starting pinnacle without xwayland is a thing, handle this
|
||||
// | properly; in this case, we probably no longer need to start the
|
||||
// | config manually anymore either, as this is only needed now,
|
||||
// | because the config is started after xwayland reports its ready
|
||||
|
||||
// when xdiplay is None when starting the config, the grpc server is not
|
||||
// started, until it is set; this bypasses this for now
|
||||
state.xdisplay = Some(u32::MAX);
|
||||
run_config(&mut state);
|
||||
|
||||
// wait for the config to connect to the layout service
|
||||
while state.layout_state.layout_request_sender.is_none() {
|
||||
event_loop
|
||||
.dispatch(Some(Duration::from_millis(10)), &mut state)
|
||||
.expect("event_loop error while waiting for config");
|
||||
}
|
||||
|
||||
event_loop
|
||||
.run(None, &mut state, |state| {
|
||||
state.update_pointer_focus();
|
||||
state.fixup_z_layering();
|
||||
state.space.refresh();
|
||||
state.popup_manager.cleanup();
|
||||
|
||||
state
|
||||
.display_handle
|
||||
.flush_clients()
|
||||
.expect("failed to flush client buffers");
|
||||
})
|
||||
.expect("failed to run event_loop");
|
||||
}
|
||||
|
||||
fn handle_event(event: WlcsEvent, state: &mut State) {
|
||||
tracing::debug!("handle_event {:?}", event);
|
||||
match event {
|
||||
WlcsEvent::Stop => state.shutdown(),
|
||||
WlcsEvent::NewClient { stream, client_id } => {
|
||||
let client: Client = state
|
||||
.display_handle
|
||||
.insert_client(stream, Arc::new(ClientState::default()))
|
||||
.expect("failed to insert new client");
|
||||
state.backend.wlcs_mut().clients.insert(client_id, client);
|
||||
}
|
||||
WlcsEvent::PositionWindow {
|
||||
client_id,
|
||||
surface_id,
|
||||
location,
|
||||
} => {
|
||||
let client = state.backend.wlcs_mut().clients.get(&client_id);
|
||||
let window = state
|
||||
.space
|
||||
.elements()
|
||||
.find(|w| {
|
||||
if let Some(surface) = w.wl_surface() {
|
||||
state.display_handle.get_client(surface.id()).ok().as_ref() == client
|
||||
&& surface.id().protocol_id() == surface_id
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.cloned();
|
||||
|
||||
if let Some(window) = window {
|
||||
state.space.map_element(window.clone(), location, false);
|
||||
|
||||
let size = state
|
||||
.space
|
||||
.element_geometry(&window)
|
||||
.expect("window to be positioned was not mapped")
|
||||
.size;
|
||||
|
||||
if window.with_state(|state| state.floating_or_tiled.is_tiled()) {
|
||||
window.toggle_floating();
|
||||
}
|
||||
|
||||
window.with_state_mut(|state| {
|
||||
state.floating_or_tiled =
|
||||
FloatingOrTiled::Floating(Rectangle::from_loc_and_size(location, size));
|
||||
});
|
||||
|
||||
for output in state.space.outputs_for_element(&window) {
|
||||
state.schedule_render(&output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WlcsEvent::NewPointer { device_id } => {
|
||||
state.process_input_event(InputEvent::<WlcsInputBackend>::DeviceAdded {
|
||||
device: WlcsDevice {
|
||||
device_id,
|
||||
capability: DeviceCapability::Pointer,
|
||||
},
|
||||
})
|
||||
}
|
||||
WlcsEvent::PointerMoveAbsolute {
|
||||
device_id,
|
||||
position,
|
||||
} => state.process_input_event(
|
||||
WlcsPointerMotionAbsoluteEvent {
|
||||
device_id,
|
||||
time: Duration::from(state.clock.now()).as_millis() as u64,
|
||||
position,
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
WlcsEvent::PointerMoveRelative { device_id, delta } => state.process_input_event(
|
||||
WlcsPointerMotionEvent {
|
||||
device_id,
|
||||
time: Duration::from(state.clock.now()).as_millis() as u64,
|
||||
delta,
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
WlcsEvent::PointerButton {
|
||||
device_id,
|
||||
button_id,
|
||||
pressed,
|
||||
} => state.process_input_event(
|
||||
WlcsPointerButtonEvent {
|
||||
device_id,
|
||||
time: Duration::from(state.clock.now()).as_millis() as u64,
|
||||
button_code: button_id as u32,
|
||||
state: if pressed {
|
||||
ButtonState::Pressed
|
||||
} else {
|
||||
ButtonState::Released
|
||||
},
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
WlcsEvent::NewTouch { device_id } => {
|
||||
state.process_input_event(InputEvent::<WlcsInputBackend>::DeviceAdded {
|
||||
device: WlcsDevice {
|
||||
device_id,
|
||||
capability: DeviceCapability::Pointer,
|
||||
},
|
||||
})
|
||||
}
|
||||
WlcsEvent::TouchDown {
|
||||
device_id,
|
||||
position,
|
||||
} => state.process_input_event(
|
||||
WlcsTouchDownEvent {
|
||||
device_id,
|
||||
time: Duration::from(state.clock.now()).as_millis() as u64,
|
||||
position,
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
WlcsEvent::TouchMove {
|
||||
device_id,
|
||||
position,
|
||||
} => state.process_input_event(
|
||||
WlcsTouchDownEvent {
|
||||
device_id,
|
||||
time: Duration::from(state.clock.now()).as_millis() as u64,
|
||||
position,
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
WlcsEvent::TouchUp { device_id } => state.process_input_event(
|
||||
WlcsTouchUpEvent {
|
||||
device_id,
|
||||
time: Duration::from(state.clock.now()).as_millis() as u64,
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue