Fix xwayland and cleanup

This commit is contained in:
Leon Vack 2024-04-19 18:32:05 +02:00
parent abb21d9924
commit c0fe55003b
7 changed files with 116 additions and 98 deletions

View file

@ -31,15 +31,10 @@ pub struct Dummy {
}
impl Backend {
fn dummy_mut(&mut self) -> &mut Dummy {
fn dummy_mut(&mut self) -> &Dummy {
let Backend::Dummy(dummy) = self else { unreachable!() };
dummy
}
#[cfg(feature = "wlcs")]
pub fn wlcs_mut(&mut self) -> &mut Wlcs {
&mut self.dummy_mut().wlcs_state
}
}
impl BackendData for Dummy {
@ -121,7 +116,7 @@ pub fn setup_dummy(
state.space.map_output(&output, (0, 0));
/* if let Err(err) = state.xwayland.start(
if let Err(err) = state.xwayland.start(
state.loop_handle.clone(),
None,
std::iter::empty::<(OsString, OsString)>(),
@ -129,7 +124,7 @@ pub fn setup_dummy(
|_| {},
) {
tracing::error!("Failed to start XWayland: {err}");
} */
}
Ok((state, event_loop))
}

View file

@ -1,9 +1,89 @@
use std::{collections::HashMap, sync::{atomic::AtomicBool, Arc}};
use std::{collections::HashMap, path::PathBuf};
use smithay::reexports::wayland_server::Client;
use smithay::{
backend::renderer::{test::DummyRenderer, ImportMemWl},
output::{Output, Subpixel},
reexports::{
calloop::EventLoop,
wayland_server::{Client, Display},
},
utils::Transform,
};
use crate::state::State;
use super::{dummy::Dummy, Backend};
#[derive(Default)]
pub struct Wlcs {
pub clients: HashMap<i32, Client>,
pub running: Arc<AtomicBool>,
}
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(
no_config: bool,
config_dir: Option<PathBuf>,
) -> 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,
no_config,
config_dir,
)?;
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))
}

View file

@ -564,17 +564,10 @@ impl State {
}
}));
}
None => {
self.grpc_server_join_handle = Some(tokio::spawn(async move {
if let Err(err) = grpc_server.serve_with_incoming(uds_stream).await {
error!("gRPC server error: {err}");
}
}));
}
// FIXME: Not really high priority but if you somehow reload the config really, REALLY
// | fast at startup then I think there's a chance that the gRPC server
// | could get started twice.
/* None => self.schedule(
None => self.schedule(
|state| state.xdisplay.is_some(),
move |state| {
state.grpc_server_join_handle = Some(tokio::spawn(async move {
@ -583,7 +576,7 @@ impl State {
}
}));
},
), */
),
}
Ok(())

View file

@ -1,46 +1,6 @@
# This metaconfig.toml file dictates what config Pinnacle will run.
#
# When running Pinnacle, the compositor will look in the following directories for a metaconfig.toml file,
# in order from top to bottom:
# $PINNACLE_CONFIG_DIR
# $XDG_CONFIG_HOME/pinnacle/
# ~/.config/pinnacle/
#
# When Pinnacle finds a metaconfig.toml file, it will execute the command provided to `command`.
# To use a Rust config, this should be changed to something like ["cargo", "run"].
#
# Because configuration is done using an external process, if it ever crashes, you lose all of your keybinds.
# The compositor will load the default config if that happens, but in the event that you don't have
# the necessary dependencies for it to run, you may get softlocked.
# In order prevent you from getting stuck in the compositor, you must define keybinds to reload your config
# and kill Pinnacle.
#
# More details on each setting can be found below.
# The command Pinnacle will run on startup and when you reload your config.
# Paths are relative to the directory the metaconfig.toml file is in.
# This must be an array.
command = ["./pinnacle-config"]
### Keybinds ###
# Each keybind takes in a table with two fields: `modifiers` and `key`.
# - `modifiers` can be one of "Ctrl", "Alt", "Shift", or "Super".
# - `key` can be a string of any lowercase letter, number,
# "numN" where N is a number for numpad keys, or "esc"/"escape".
# Support for any xkbcommon key is planned for a future update.
# The keybind that will reload your config.
reload_keybind = { modifiers = ["Ctrl", "Alt"], key = "r" }
# The keybind that will kill Pinnacle.
kill_keybind = { modifiers = ["Ctrl", "Alt", "Shift"], key = "escape" }
### Socket directory ###
# Pinnacle will open a Unix socket at `$XDG_RUNTIME_DIR` by default, falling back to `/tmp` if it doesn't exist.
# If you want/need to change this, use the `socket_dir` setting set to the directory of your choosing.
#
# socket_dir = "/your/dir/here/"
### Environment Variables ###
# If you need to spawn your config with any environment variables, list them here.
[envs]
# key = "value"

View file

@ -1,36 +1,12 @@
use pinnacle_api::layout::{CyclingLayoutManager, MasterStackLayout};
use pinnacle_api::ApiModules;
// Pinnacle needs to perform some setup before and after your config.
// The `#[pinnacle_api::config(modules)]` attribute does so and
// will bind all the config structs to the provided identifier.
#[pinnacle_api::config(modules)]
async fn main() {
// Deconstruct to get all the APIs.
#[allow(unused_variables)]
let ApiModules {
pinnacle,
process,
window,
input,
output,
tag,
layout,
render,
} = modules;
let ApiModules { layout, .. } = modules;
let _layout_requester = layout.set_manager(CyclingLayoutManager::new([
Box::<MasterStackLayout>::default() as _,
]));
// Setup all monitors with tags "1" through "5"
output.connect_for_all(move |op| {
let tags = tag.add(op, ["tag"]);
tags.first().unwrap().set_active(true);
});
// Enable sloppy focus
/* window.connect_signal(WindowSignal::PointerEnter(Box::new(|win| {
win.set_focused(true);
}))); */
}

View file

@ -202,22 +202,28 @@ impl Wlcs for PinnacleHandle {
}
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| PointerHandle {
device_id: new_device_id(),
sender,
.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| TouchHandle {
device_id: new_device_id(),
sender,
.map(|sender| {
sender
.send(WlcsEvent::NewTouch { device_id })
.expect("failed to send new_touch");
TouchHandle { device_id, sender }
})
}

View file

@ -1,14 +1,14 @@
use std::{sync::Arc, time::Duration};
use pinnacle::{
backend::dummy::setup_dummy,
backend::wlcs::setup_wlcs_dummy,
state::{ClientState, State},
};
use smithay::{
backend::input::{ButtonState, DeviceCapability, InputEvent},
reexports::{
calloop::channel::{Channel, Event},
wayland_server::Resource,
wayland_server::{Client, Resource},
},
wayland::seat::WaylandFocus,
};
@ -26,7 +26,7 @@ pub(crate) fn run(channel: Channel<WlcsEvent>) {
&std::env::var("PINNACLE_WLCS_CONFIG_PATH").expect("PINNACLE_WLCS_CONFIG_PATH not set");
let (mut state, mut event_loop) =
setup_dummy(false, Some(config_path.into())).expect("failed to setup dummy backend");
setup_wlcs_dummy(false, Some(config_path.into())).expect("failed to setup dummy backend");
event_loop
.handle()
@ -40,19 +40,27 @@ pub(crate) fn run(channel: Channel<WlcsEvent>) {
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);
if let Err(err) = state.start_config(config_path) {
panic!("failed to start config: {err}");
}
// FIXME: different sock_dir per instance?
// FIXME: use a custom socker_dir to avoid having to number sockets
// 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");
}
// TODO: handle no-xwayland properly
event_loop
.run(None, &mut state, |state| {
state.update_pointer_focus();
@ -72,7 +80,7 @@ fn handle_event(event: WlcsEvent, state: &mut State) {
match event {
WlcsEvent::Stop => state.shutdown(),
WlcsEvent::NewClient { stream, client_id } => {
let client: smithay::reexports::wayland_server::Client = state
let client: Client = state
.display_handle
.insert_client(stream, Arc::new(ClientState::default()))
.expect("failed to insert new client");