mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2024-12-27 21:58:18 +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
|
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||||
*.pdb
|
*.pdb
|
||||||
|
|
||||||
|
# Don't push local doc builds
|
||||||
api/lua/doc/doc
|
api/lua/doc/doc
|
||||||
|
# This is a library
|
||||||
api/rust/Cargo.lock
|
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",
|
"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]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
|
@ -1461,6 +1470,15 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memoffset"
|
||||||
|
version = "0.6.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memoffset"
|
name = "memoffset"
|
||||||
version = "0.9.1"
|
version = "0.9.1"
|
||||||
|
@ -1532,6 +1550,17 @@ dependencies = [
|
||||||
"jni-sys",
|
"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]]
|
[[package]]
|
||||||
name = "nix"
|
name = "nix"
|
||||||
version = "0.28.0"
|
version = "0.28.0"
|
||||||
|
@ -1765,7 +1794,7 @@ dependencies = [
|
||||||
"cliclack",
|
"cliclack",
|
||||||
"dircpy",
|
"dircpy",
|
||||||
"image",
|
"image",
|
||||||
"nix",
|
"nix 0.28.0",
|
||||||
"pinnacle",
|
"pinnacle",
|
||||||
"pinnacle-api",
|
"pinnacle-api",
|
||||||
"pinnacle-api-defs",
|
"pinnacle-api-defs",
|
||||||
|
@ -3071,7 +3100,7 @@ dependencies = [
|
||||||
"dlib",
|
"dlib",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"memoffset",
|
"memoffset 0.9.1",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
]
|
]
|
||||||
|
@ -3409,6 +3438,33 @@ dependencies = [
|
||||||
"memchr",
|
"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]]
|
[[package]]
|
||||||
name = "x11-dl"
|
name = "x11-dl"
|
||||||
version = "2.21.0"
|
version = "2.21.0"
|
||||||
|
|
23
Cargo.toml
23
Cargo.toml
|
@ -1,5 +1,10 @@
|
||||||
[workspace]
|
[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]
|
[workspace.package]
|
||||||
authors = ["Ottatop <ottatop1227@gmail.com>"]
|
authors = ["Ottatop <ottatop1227@gmail.com>"]
|
||||||
|
@ -15,6 +20,9 @@ prost = "0.12.4"
|
||||||
tonic = "0.11.0"
|
tonic = "0.11.0"
|
||||||
tonic-reflection = "0.11.0"
|
tonic-reflection = "0.11.0"
|
||||||
tonic-build = "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
|
# API definitions
|
||||||
pinnacle-api-defs = { path = "./pinnacle-api-defs" }
|
pinnacle-api-defs = { path = "./pinnacle-api-defs" }
|
||||||
# Misc.
|
# Misc.
|
||||||
|
@ -23,6 +31,7 @@ xdg = "2.5.2"
|
||||||
bitflags = "2.5.0"
|
bitflags = "2.5.0"
|
||||||
clap = { version = "4.5.4", features = ["derive"] }
|
clap = { version = "4.5.4", features = ["derive"] }
|
||||||
dircpy = "0.3.16"
|
dircpy = "0.3.16"
|
||||||
|
tempfile = "3.10.1"
|
||||||
|
|
||||||
########################################################################yo😎###########
|
########################################################################yo😎###########
|
||||||
|
|
||||||
|
@ -42,8 +51,8 @@ keywords = ["wayland", "compositor", "smithay", "lua"]
|
||||||
# smithay is down there somewhere
|
# smithay is down there somewhere
|
||||||
smithay-drm-extras = { git = "https://github.com/Smithay/smithay", rev = "c293ec7" }
|
smithay-drm-extras = { git = "https://github.com/Smithay/smithay", rev = "c293ec7" }
|
||||||
# Tracing
|
# Tracing
|
||||||
tracing = "0.1.40"
|
tracing = { workspace = true }
|
||||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "registry"] }
|
tracing-subscriber = { workspace = true }
|
||||||
tracing-appender = "0.2.3"
|
tracing-appender = "0.2.3"
|
||||||
# Errors
|
# Errors
|
||||||
anyhow = { version = "1.0.81", features = ["backtrace"] }
|
anyhow = { version = "1.0.81", features = ["backtrace"] }
|
||||||
|
@ -76,8 +85,9 @@ dircpy = { workspace = true }
|
||||||
chrono = "0.4.37"
|
chrono = "0.4.37"
|
||||||
bytemuck = "1.15.0"
|
bytemuck = "1.15.0"
|
||||||
pinnacle-api = { path = "./api/rust" }
|
pinnacle-api = { path = "./api/rust" }
|
||||||
|
smithay = { workspace = true }
|
||||||
|
|
||||||
[dependencies.smithay]
|
[workspace.dependencies.smithay]
|
||||||
git = "https://github.com/Smithay/smithay"
|
git = "https://github.com/Smithay/smithay"
|
||||||
rev = "c293ec7"
|
rev = "c293ec7"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
@ -110,12 +120,13 @@ xdg = { workspace = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
temp-env = "0.3.6"
|
temp-env = "0.3.6"
|
||||||
tempfile = "3.10.1"
|
tempfile = { workspace = true }
|
||||||
test-log = { version = "0.2.15", default-features = false, features = ["trace"] }
|
test-log = { version = "0.2.15", default-features = false, features = ["trace"] }
|
||||||
pinnacle = { path = ".", features = ["testing"] }
|
pinnacle = { path = ".", features = ["wlcs"] }
|
||||||
pinnacle-api = { path = "./api/rust" }
|
pinnacle-api = { path = "./api/rust" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
testing = [
|
testing = [
|
||||||
"smithay/renderer_test",
|
"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
|
rust-analyzer
|
||||||
cargo-outdated
|
cargo-outdated
|
||||||
|
|
||||||
|
# wlcs
|
||||||
|
(writeScriptBin "wlcs" ''
|
||||||
|
#!/bin/sh
|
||||||
|
${wlcs}/libexec/wlcs/wlcs "$@"
|
||||||
|
'')
|
||||||
|
|
||||||
wayland
|
wayland
|
||||||
|
|
||||||
# build time stuff
|
# build time stuff
|
||||||
|
|
|
@ -45,6 +45,8 @@ use self::{udev::Udev, winit::Winit};
|
||||||
pub mod dummy;
|
pub mod dummy;
|
||||||
pub mod udev;
|
pub mod udev;
|
||||||
pub mod winit;
|
pub mod winit;
|
||||||
|
#[cfg(feature = "wlcs")]
|
||||||
|
pub mod wlcs;
|
||||||
|
|
||||||
pub enum Backend {
|
pub enum Backend {
|
||||||
/// The compositor is running in a Winit window
|
/// The compositor is running in a Winit window
|
||||||
|
|
|
@ -16,6 +16,8 @@ use smithay::{
|
||||||
|
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
|
|
||||||
|
#[cfg(feature = "wlcs")]
|
||||||
|
use super::wlcs::Wlcs;
|
||||||
use super::Backend;
|
use super::Backend;
|
||||||
use super::BackendData;
|
use super::BackendData;
|
||||||
|
|
||||||
|
@ -24,6 +26,8 @@ pub const DUMMY_OUTPUT_NAME: &str = "Dummy Window";
|
||||||
pub struct Dummy {
|
pub struct Dummy {
|
||||||
pub renderer: DummyRenderer,
|
pub renderer: DummyRenderer,
|
||||||
// pub dmabuf_state: (DmabufState, DmabufGlobal, Option<DmabufFeedback>),
|
// pub dmabuf_state: (DmabufState, DmabufGlobal, Option<DmabufFeedback>),
|
||||||
|
#[cfg(feature = "wlcs")]
|
||||||
|
pub wlcs_state: Wlcs,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Backend {
|
impl Backend {
|
||||||
|
@ -63,7 +67,7 @@ pub fn setup_dummy(
|
||||||
size: (0, 0).into(),
|
size: (0, 0).into(),
|
||||||
subpixel: Subpixel::Unknown,
|
subpixel: Subpixel::Unknown,
|
||||||
make: "Pinnacle".to_string(),
|
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);
|
let output = Output::new(DUMMY_OUTPUT_NAME.to_string(), physical_properties);
|
||||||
|
@ -91,6 +95,8 @@ pub fn setup_dummy(
|
||||||
let backend = Dummy {
|
let backend = Dummy {
|
||||||
renderer,
|
renderer,
|
||||||
// dmabuf_state,
|
// dmabuf_state,
|
||||||
|
#[cfg(feature = "wlcs")]
|
||||||
|
wlcs_state: Wlcs::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut state = State::init(
|
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 connector_saved_states: HashMap<OutputName, ConnectorSavedState>,
|
||||||
|
|
||||||
pub config_join_handle: Option<JoinHandle<()>>,
|
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:
|
pub shutdown_sender:
|
||||||
Option<tokio::sync::mpsc::UnboundedSender<Result<ShutdownWatchResponse, tonic::Status>>>,
|
Option<tokio::sync::mpsc::UnboundedSender<Result<ShutdownWatchResponse, tonic::Status>>>,
|
||||||
|
@ -208,7 +208,7 @@ impl Config {
|
||||||
.unwrap_or_else(|| get_config_dir(xdg_base_dirs))
|
.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.window_rules.clear();
|
||||||
self.connector_saved_states.clear();
|
self.connector_saved_states.clear();
|
||||||
if let Some(join_handle) = self.config_join_handle.take() {
|
if let Some(join_handle) = self.config_join_handle.take() {
|
||||||
|
|
|
@ -483,7 +483,7 @@ mod output {
|
||||||
local props = Pinnacle.output.get_focused():props()
|
local props = Pinnacle.output.get_focused():props()
|
||||||
|
|
||||||
assert(props.make == "Pinnacle")
|
assert(props.make == "Pinnacle")
|
||||||
assert(props.model == "Winit Window")
|
assert(props.model == "Dummy Window")
|
||||||
assert(props.x == 0)
|
assert(props.x == 0)
|
||||||
assert(props.y == 0)
|
assert(props.y == 0)
|
||||||
assert(props.logical_width == 1920)
|
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