mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2025-01-14 08:01:14 +01:00
Move config handling out of state.rs
This commit is contained in:
parent
5c88ceac83
commit
c83f136cf7
4 changed files with 203 additions and 173 deletions
|
@ -1490,7 +1490,7 @@ fn render_surface<'a>(
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if !pending_wins.is_empty() {
|
if !pending_wins.is_empty() {
|
||||||
tracing::debug!("Skipping frame, waiting on {pending_wins:?}");
|
// tracing::debug!("Skipping frame, waiting on {pending_wins:?}");
|
||||||
for win in windows.iter() {
|
for win in windows.iter() {
|
||||||
win.send_frame(output, clock.now(), Some(Duration::ZERO), |_, _| {
|
win.send_frame(output, clock.now(), Some(Duration::ZERO), |_, _| {
|
||||||
Some(output.clone())
|
Some(output.clone())
|
||||||
|
|
|
@ -252,7 +252,7 @@ pub fn run_winit() -> anyhow::Result<()> {
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if !pending_wins.is_empty() {
|
if !pending_wins.is_empty() {
|
||||||
tracing::debug!("Skipping frame, waiting on {pending_wins:?}");
|
// tracing::debug!("Skipping frame, waiting on {pending_wins:?}");
|
||||||
for win in state.windows.iter() {
|
for win in state.windows.iter() {
|
||||||
win.send_frame(
|
win.send_frame(
|
||||||
&output,
|
&output,
|
||||||
|
|
172
src/config.rs
172
src/config.rs
|
@ -1,13 +1,23 @@
|
||||||
pub mod api;
|
pub mod api;
|
||||||
|
|
||||||
use std::path::Path;
|
use crate::config::api::{msg::ModifierMask, PinnacleSocketSource};
|
||||||
|
use std::{
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
use calloop::channel::Sender;
|
||||||
use smithay::input::keyboard::keysyms;
|
use smithay::input::keyboard::keysyms;
|
||||||
use toml::Table;
|
use toml::Table;
|
||||||
|
|
||||||
use api::msg::Modifier;
|
use api::msg::Modifier;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
state::{State, WithState},
|
||||||
|
tag::TagId,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(serde::Deserialize, Debug)]
|
#[derive(serde::Deserialize, Debug)]
|
||||||
pub struct Metaconfig {
|
pub struct Metaconfig {
|
||||||
pub command: String,
|
pub command: String,
|
||||||
|
@ -97,7 +107,7 @@ pub enum Key {
|
||||||
Escape = keysyms::KEY_Escape,
|
Escape = keysyms::KEY_Escape,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(config_dir: &Path) -> anyhow::Result<Metaconfig> {
|
fn parse(config_dir: &Path) -> anyhow::Result<Metaconfig> {
|
||||||
let config_dir = config_dir.join("metaconfig.toml");
|
let config_dir = config_dir.join("metaconfig.toml");
|
||||||
|
|
||||||
let metaconfig =
|
let metaconfig =
|
||||||
|
@ -105,3 +115,161 @@ pub fn parse(config_dir: &Path) -> anyhow::Result<Metaconfig> {
|
||||||
|
|
||||||
toml::from_str(&metaconfig).context("Failed to deserialize toml")
|
toml::from_str(&metaconfig).context("Failed to deserialize toml")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_config_dir() -> PathBuf {
|
||||||
|
let config_dir = std::env::var("PINNACLE_CONFIG_DIR")
|
||||||
|
.ok()
|
||||||
|
.and_then(|s| Some(PathBuf::from(shellexpand::full(&s).ok()?.to_string())));
|
||||||
|
|
||||||
|
config_dir.unwrap_or(crate::XDG_BASE_DIRS.get_config_home())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_config(tx_channel: Sender<api::msg::Msg>) -> anyhow::Result<ConfigReturn> {
|
||||||
|
let config_dir = get_config_dir();
|
||||||
|
tracing::debug!("config dir is {:?}", config_dir);
|
||||||
|
|
||||||
|
let metaconfig = parse(&config_dir)?;
|
||||||
|
|
||||||
|
// If a socket is provided in the metaconfig, use it.
|
||||||
|
let socket_dir = if let Some(socket_dir) = &metaconfig.socket_dir {
|
||||||
|
// cd into the metaconfig dir and canonicalize to preserve relative paths
|
||||||
|
// like ./dir/here
|
||||||
|
let current_dir = std::env::current_dir()?;
|
||||||
|
|
||||||
|
std::env::set_current_dir(&config_dir)?;
|
||||||
|
let socket_dir = PathBuf::from(socket_dir).canonicalize()?;
|
||||||
|
std::env::set_current_dir(current_dir)?;
|
||||||
|
socket_dir
|
||||||
|
} else {
|
||||||
|
// Otherwise, use $XDG_RUNTIME_DIR. If that doesn't exist, use /tmp.
|
||||||
|
crate::XDG_BASE_DIRS
|
||||||
|
.get_runtime_directory()
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or(PathBuf::from(crate::config::api::DEFAULT_SOCKET_DIR))
|
||||||
|
};
|
||||||
|
|
||||||
|
let socket_source = PinnacleSocketSource::new(tx_channel, &socket_dir)
|
||||||
|
.context("Failed to create socket source")?;
|
||||||
|
|
||||||
|
let reload_keybind = metaconfig.reload_keybind;
|
||||||
|
let kill_keybind = metaconfig.kill_keybind;
|
||||||
|
|
||||||
|
let mut command = metaconfig.command.split(' ');
|
||||||
|
|
||||||
|
let arg1 = command
|
||||||
|
.next()
|
||||||
|
.context("command in metaconfig.toml was empty")?;
|
||||||
|
|
||||||
|
std::env::set_var("PINNACLE_DIR", std::env::current_dir()?);
|
||||||
|
|
||||||
|
let envs = metaconfig
|
||||||
|
.envs
|
||||||
|
.unwrap_or(toml::map::Map::new())
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|(key, val)| {
|
||||||
|
if let toml::Value::String(string) = val {
|
||||||
|
Some((
|
||||||
|
key,
|
||||||
|
shellexpand::full_with_context(
|
||||||
|
&string,
|
||||||
|
|| std::env::var("HOME").ok(),
|
||||||
|
// Expand nonexistent vars to an empty string instead of crashing
|
||||||
|
|var| Ok::<_, ()>(Some(std::env::var(var).unwrap_or("".to_string()))),
|
||||||
|
)
|
||||||
|
.ok()?
|
||||||
|
.to_string(),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
tracing::debug!("Config envs are {:?}", envs);
|
||||||
|
|
||||||
|
// Using async_process's Child instead of std::process because I don't have to spawn my own
|
||||||
|
// thread to wait for the child
|
||||||
|
let child = async_process::Command::new(arg1)
|
||||||
|
.args(command)
|
||||||
|
.envs(envs)
|
||||||
|
.current_dir(config_dir)
|
||||||
|
.stdout(async_process::Stdio::inherit())
|
||||||
|
.stderr(async_process::Stdio::inherit())
|
||||||
|
.spawn()
|
||||||
|
.expect("failed to spawn config");
|
||||||
|
|
||||||
|
tracing::info!("Started config with {}", metaconfig.command);
|
||||||
|
|
||||||
|
let reload_mask = ModifierMask::from(reload_keybind.modifiers);
|
||||||
|
let kill_mask = ModifierMask::from(kill_keybind.modifiers);
|
||||||
|
|
||||||
|
Ok(ConfigReturn {
|
||||||
|
reload_keybind: (reload_mask, reload_keybind.key as u32),
|
||||||
|
kill_keybind: (kill_mask, kill_keybind.key as u32),
|
||||||
|
config_child_handle: child,
|
||||||
|
socket_source,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ConfigReturn {
|
||||||
|
pub reload_keybind: (ModifierMask, u32),
|
||||||
|
pub kill_keybind: (ModifierMask, u32),
|
||||||
|
pub config_child_handle: async_process::Child,
|
||||||
|
pub socket_source: PinnacleSocketSource,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
pub fn restart_config(&mut self) -> anyhow::Result<()> {
|
||||||
|
tracing::info!("Restarting config");
|
||||||
|
tracing::debug!("Clearing tags");
|
||||||
|
|
||||||
|
for output in self.space.outputs() {
|
||||||
|
output.with_state(|state| state.tags.clear());
|
||||||
|
}
|
||||||
|
|
||||||
|
TagId::reset();
|
||||||
|
|
||||||
|
tracing::debug!("Clearing mouse and keybinds");
|
||||||
|
self.input_state.keybinds.clear();
|
||||||
|
self.input_state.mousebinds.clear();
|
||||||
|
self.window_rules.clear();
|
||||||
|
|
||||||
|
tracing::debug!("Killing old config");
|
||||||
|
if let Err(err) = self.api_state.config_process.kill() {
|
||||||
|
tracing::warn!("Error when killing old config: {err}");
|
||||||
|
}
|
||||||
|
|
||||||
|
self.loop_handle.remove(self.api_state.socket_token);
|
||||||
|
|
||||||
|
let ConfigReturn {
|
||||||
|
reload_keybind,
|
||||||
|
kill_keybind,
|
||||||
|
config_child_handle,
|
||||||
|
socket_source,
|
||||||
|
} = start_config(self.api_state.tx_channel.clone())?;
|
||||||
|
|
||||||
|
let socket_token = self
|
||||||
|
.loop_handle
|
||||||
|
.insert_source(socket_source, |stream, _, data| {
|
||||||
|
if let Some(old_stream) = data
|
||||||
|
.state
|
||||||
|
.api_state
|
||||||
|
.stream
|
||||||
|
.replace(Arc::new(Mutex::new(stream)))
|
||||||
|
{
|
||||||
|
old_stream
|
||||||
|
.lock()
|
||||||
|
.expect("Couldn't lock old stream")
|
||||||
|
.shutdown(std::net::Shutdown::Both)
|
||||||
|
.expect("Couldn't shutdown old stream");
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.input_state.reload_keybind = reload_keybind;
|
||||||
|
self.input_state.kill_keybind = kill_keybind;
|
||||||
|
self.api_state.config_process = config_child_handle;
|
||||||
|
self.api_state.socket_token = socket_token;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
200
src/state.rs
200
src/state.rs
|
@ -5,29 +5,25 @@ mod api_handlers;
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
os::{fd::AsRawFd, unix::net::UnixStream},
|
os::{fd::AsRawFd, unix::net::UnixStream},
|
||||||
path::{Path, PathBuf},
|
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{udev::Udev, winit::Winit, BackendData},
|
backend::{udev::Udev, winit::Winit, BackendData},
|
||||||
config::api::{
|
config::{
|
||||||
msg::{
|
api::msg::{
|
||||||
window_rules::{WindowRule, WindowRuleCondition},
|
window_rules::{WindowRule, WindowRuleCondition},
|
||||||
CallbackId, ModifierMask, Msg,
|
CallbackId, Msg,
|
||||||
},
|
},
|
||||||
PinnacleSocketSource,
|
ConfigReturn,
|
||||||
},
|
},
|
||||||
config::Metaconfig,
|
|
||||||
cursor::Cursor,
|
cursor::Cursor,
|
||||||
focus::FocusState,
|
focus::FocusState,
|
||||||
grab::resize_grab::ResizeSurfaceState,
|
grab::resize_grab::ResizeSurfaceState,
|
||||||
tag::TagId,
|
|
||||||
window::WindowElement,
|
window::WindowElement,
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
use calloop::{channel::Sender, futures::Scheduler, RegistrationToken};
|
||||||
use calloop::futures::Scheduler;
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::renderer::element::RenderElementStates,
|
backend::renderer::element::RenderElementStates,
|
||||||
desktop::{
|
desktop::{
|
||||||
|
@ -137,7 +133,6 @@ pub struct State {
|
||||||
pub window_rules: Vec<(WindowRuleCondition, WindowRule)>,
|
pub window_rules: Vec<(WindowRuleCondition, WindowRule)>,
|
||||||
|
|
||||||
pub async_scheduler: Scheduler<()>,
|
pub async_scheduler: Scheduler<()>,
|
||||||
pub config_process: async_process::Child,
|
|
||||||
|
|
||||||
// TODO: move into own struct
|
// TODO: move into own struct
|
||||||
// | basically just clean this mess up
|
// | basically just clean this mess up
|
||||||
|
@ -203,39 +198,14 @@ impl State {
|
||||||
|
|
||||||
let (tx_channel, rx_channel) = calloop::channel::channel::<Msg>();
|
let (tx_channel, rx_channel) = calloop::channel::channel::<Msg>();
|
||||||
|
|
||||||
let config_dir = get_config_dir();
|
|
||||||
tracing::debug!("config dir is {:?}", config_dir);
|
|
||||||
|
|
||||||
let metaconfig = crate::config::parse(&config_dir)?;
|
|
||||||
|
|
||||||
// If a socket is provided in the metaconfig, use it.
|
|
||||||
let socket_dir = if let Some(socket_dir) = &metaconfig.socket_dir {
|
|
||||||
// cd into the metaconfig dir and canonicalize to preserve relative paths
|
|
||||||
// like ./dir/here
|
|
||||||
let current_dir = std::env::current_dir()?;
|
|
||||||
|
|
||||||
std::env::set_current_dir(&config_dir)?;
|
|
||||||
let socket_dir = PathBuf::from(socket_dir).canonicalize()?;
|
|
||||||
std::env::set_current_dir(current_dir)?;
|
|
||||||
socket_dir
|
|
||||||
} else {
|
|
||||||
// Otherwise, use $XDG_RUNTIME_DIR. If that doesn't exist, use /tmp.
|
|
||||||
crate::XDG_BASE_DIRS
|
|
||||||
.get_runtime_directory()
|
|
||||||
.cloned()
|
|
||||||
.unwrap_or(PathBuf::from(crate::config::api::DEFAULT_SOCKET_DIR))
|
|
||||||
};
|
|
||||||
|
|
||||||
let socket_source = PinnacleSocketSource::new(tx_channel, &socket_dir)
|
|
||||||
.context("Failed to create socket source")?;
|
|
||||||
|
|
||||||
let ConfigReturn {
|
let ConfigReturn {
|
||||||
reload_keybind,
|
reload_keybind,
|
||||||
kill_keybind,
|
kill_keybind,
|
||||||
config_child_handle,
|
config_child_handle,
|
||||||
} = start_config(metaconfig, &config_dir)?;
|
socket_source,
|
||||||
|
} = crate::config::start_config(tx_channel.clone())?;
|
||||||
|
|
||||||
let insert_ret = loop_handle.insert_source(socket_source, |stream, _, data| {
|
let socket_token_ret = loop_handle.insert_source(socket_source, |stream, _, data| {
|
||||||
if let Some(old_stream) = data
|
if let Some(old_stream) = data
|
||||||
.state
|
.state
|
||||||
.api_state
|
.api_state
|
||||||
|
@ -250,9 +220,12 @@ impl State {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Err(err) = insert_ret {
|
let socket_token = match socket_token_ret {
|
||||||
anyhow::bail!("Failed to insert socket source into event loop: {err}");
|
Ok(token) => token,
|
||||||
}
|
Err(err) => {
|
||||||
|
anyhow::bail!("Failed to insert socket source into event loop: {err}");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let (executor, sched) =
|
let (executor, sched) =
|
||||||
calloop::futures::executor::<()>().expect("Couldn't create executor");
|
calloop::futures::executor::<()>().expect("Couldn't create executor");
|
||||||
|
@ -265,7 +238,7 @@ impl State {
|
||||||
|
|
||||||
let mut seat = seat_state.new_wl_seat(&display_handle, backend.seat_name());
|
let mut seat = seat_state.new_wl_seat(&display_handle, backend.seat_name());
|
||||||
seat.add_pointer();
|
seat.add_pointer();
|
||||||
seat.add_keyboard(XkbConfig::default(), 200, 25)?;
|
seat.add_keyboard(XkbConfig::default(), 500, 25)?;
|
||||||
|
|
||||||
loop_handle.insert_idle(|data| {
|
loop_handle.insert_idle(|data| {
|
||||||
data.state
|
data.state
|
||||||
|
@ -277,7 +250,6 @@ impl State {
|
||||||
.expect("failed to insert rx_channel into loop");
|
.expect("failed to insert rx_channel into loop");
|
||||||
});
|
});
|
||||||
|
|
||||||
tracing::debug!("before xwayland");
|
|
||||||
let xwayland = {
|
let xwayland = {
|
||||||
let (xwayland, channel) = XWayland::new(&display_handle);
|
let (xwayland, channel) = XWayland::new(&display_handle);
|
||||||
let clone = display_handle.clone();
|
let clone = display_handle.clone();
|
||||||
|
@ -289,7 +261,6 @@ impl State {
|
||||||
client_fd: _,
|
client_fd: _,
|
||||||
display,
|
display,
|
||||||
} => {
|
} => {
|
||||||
tracing::debug!("XWaylandEvent ready");
|
|
||||||
let mut wm = X11Wm::start_wm(
|
let mut wm = X11Wm::start_wm(
|
||||||
data.state.loop_handle.clone(),
|
data.state.loop_handle.clone(),
|
||||||
clone.clone(),
|
clone.clone(),
|
||||||
|
@ -297,6 +268,7 @@ impl State {
|
||||||
client,
|
client,
|
||||||
)
|
)
|
||||||
.expect("failed to attach x11wm");
|
.expect("failed to attach x11wm");
|
||||||
|
|
||||||
let cursor = Cursor::load();
|
let cursor = Cursor::load();
|
||||||
let image = cursor.get_image(1, Duration::ZERO);
|
let image = cursor.get_image(1, Duration::ZERO);
|
||||||
wm.set_cursor(
|
wm.set_cursor(
|
||||||
|
@ -305,7 +277,9 @@ impl State {
|
||||||
Point::from((image.xhot as u16, image.yhot as u16)),
|
Point::from((image.xhot as u16, image.yhot as u16)),
|
||||||
)
|
)
|
||||||
.expect("failed to set xwayland default cursor");
|
.expect("failed to set xwayland default cursor");
|
||||||
|
|
||||||
tracing::debug!("setting xwm and xdisplay");
|
tracing::debug!("setting xwm and xdisplay");
|
||||||
|
|
||||||
data.state.xwm = Some(wm);
|
data.state.xwm = Some(wm);
|
||||||
data.state.xdisplay = Some(display);
|
data.state.xdisplay = Some(display);
|
||||||
}
|
}
|
||||||
|
@ -318,7 +292,7 @@ impl State {
|
||||||
}
|
}
|
||||||
xwayland
|
xwayland
|
||||||
};
|
};
|
||||||
tracing::debug!("after xwayland");
|
tracing::debug!("xwayland set up");
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
backend,
|
backend,
|
||||||
|
@ -343,7 +317,12 @@ impl State {
|
||||||
layer_shell_state: WlrLayerShellState::new::<Self>(&display_handle),
|
layer_shell_state: WlrLayerShellState::new::<Self>(&display_handle),
|
||||||
|
|
||||||
input_state: InputState::new(reload_keybind, kill_keybind),
|
input_state: InputState::new(reload_keybind, kill_keybind),
|
||||||
api_state: ApiState::new(),
|
api_state: ApiState {
|
||||||
|
stream: None,
|
||||||
|
socket_token,
|
||||||
|
tx_channel,
|
||||||
|
config_process: config_child_handle,
|
||||||
|
},
|
||||||
focus_state: FocusState::new(),
|
focus_state: FocusState::new(),
|
||||||
|
|
||||||
seat,
|
seat,
|
||||||
|
@ -356,7 +335,6 @@ impl State {
|
||||||
popup_manager: PopupManager::default(),
|
popup_manager: PopupManager::default(),
|
||||||
|
|
||||||
async_scheduler: sched,
|
async_scheduler: sched,
|
||||||
config_process: config_child_handle,
|
|
||||||
|
|
||||||
windows: vec![],
|
windows: vec![],
|
||||||
window_rules: vec![],
|
window_rules: vec![],
|
||||||
|
@ -399,120 +377,6 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_config_dir() -> PathBuf {
|
|
||||||
let config_dir = std::env::var("PINNACLE_CONFIG_DIR")
|
|
||||||
.ok()
|
|
||||||
.and_then(|s| Some(PathBuf::from(shellexpand::full(&s).ok()?.to_string())));
|
|
||||||
|
|
||||||
config_dir.unwrap_or(crate::XDG_BASE_DIRS.get_config_home())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This should be called *after* you have created the [`PinnacleSocketSource`] to ensure
|
|
||||||
/// PINNACLE_SOCKET is set correctly for use in API implementations.
|
|
||||||
fn start_config(metaconfig: Metaconfig, config_dir: &Path) -> anyhow::Result<ConfigReturn> {
|
|
||||||
let reload_keybind = metaconfig.reload_keybind;
|
|
||||||
let kill_keybind = metaconfig.kill_keybind;
|
|
||||||
|
|
||||||
let mut command = metaconfig.command.split(' ');
|
|
||||||
|
|
||||||
let arg1 = command
|
|
||||||
.next()
|
|
||||||
.context("command in metaconfig.toml was empty")?;
|
|
||||||
|
|
||||||
std::env::set_var("PINNACLE_DIR", std::env::current_dir()?);
|
|
||||||
|
|
||||||
let envs = metaconfig
|
|
||||||
.envs
|
|
||||||
.unwrap_or(toml::map::Map::new())
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|(key, val)| {
|
|
||||||
if let toml::Value::String(string) = val {
|
|
||||||
Some((
|
|
||||||
key,
|
|
||||||
shellexpand::full_with_context(
|
|
||||||
&string,
|
|
||||||
|| std::env::var("HOME").ok(),
|
|
||||||
// Expand nonexistent vars to an empty string instead of crashing
|
|
||||||
|var| Ok::<_, ()>(Some(std::env::var(var).unwrap_or("".to_string()))),
|
|
||||||
)
|
|
||||||
.ok()?
|
|
||||||
.to_string(),
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
tracing::debug!("Config envs are {:?}", envs);
|
|
||||||
|
|
||||||
// Using async_process's Child instead of std::process because I don't have to spawn my own
|
|
||||||
// thread to wait for the child
|
|
||||||
let child = async_process::Command::new(arg1)
|
|
||||||
.args(command)
|
|
||||||
.envs(envs)
|
|
||||||
.current_dir(config_dir)
|
|
||||||
.stdout(async_process::Stdio::inherit())
|
|
||||||
.stderr(async_process::Stdio::inherit())
|
|
||||||
.spawn()
|
|
||||||
.expect("failed to spawn config");
|
|
||||||
|
|
||||||
tracing::info!("Started config with {}", metaconfig.command);
|
|
||||||
|
|
||||||
let reload_mask = ModifierMask::from(reload_keybind.modifiers);
|
|
||||||
let kill_mask = ModifierMask::from(kill_keybind.modifiers);
|
|
||||||
|
|
||||||
Ok(ConfigReturn {
|
|
||||||
reload_keybind: (reload_mask, reload_keybind.key as u32),
|
|
||||||
kill_keybind: (kill_mask, kill_keybind.key as u32),
|
|
||||||
config_child_handle: child,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ConfigReturn {
|
|
||||||
reload_keybind: (ModifierMask, u32),
|
|
||||||
kill_keybind: (ModifierMask, u32),
|
|
||||||
config_child_handle: async_process::Child,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl State {
|
|
||||||
pub fn restart_config(&mut self) -> anyhow::Result<()> {
|
|
||||||
tracing::info!("Restarting config");
|
|
||||||
tracing::debug!("Clearing tags");
|
|
||||||
for output in self.space.outputs() {
|
|
||||||
output.with_state(|state| state.tags.clear());
|
|
||||||
}
|
|
||||||
TagId::reset();
|
|
||||||
|
|
||||||
tracing::debug!("Clearing mouse- and keybinds");
|
|
||||||
self.input_state.keybinds.clear();
|
|
||||||
self.input_state.mousebinds.clear();
|
|
||||||
self.window_rules.clear();
|
|
||||||
|
|
||||||
tracing::debug!("Killing old config");
|
|
||||||
if let Err(err) = self.config_process.kill() {
|
|
||||||
tracing::warn!("Error when killing old config: {err}");
|
|
||||||
}
|
|
||||||
|
|
||||||
let config_dir = get_config_dir();
|
|
||||||
|
|
||||||
let metaconfig =
|
|
||||||
crate::config::parse(&config_dir).context("Failed to parse metaconfig.toml")?;
|
|
||||||
|
|
||||||
let ConfigReturn {
|
|
||||||
reload_keybind,
|
|
||||||
kill_keybind,
|
|
||||||
config_child_handle,
|
|
||||||
} = start_config(metaconfig, &config_dir)?;
|
|
||||||
|
|
||||||
self.input_state.reload_keybind = reload_keybind;
|
|
||||||
self.input_state.kill_keybind = kill_keybind;
|
|
||||||
self.config_process = config_child_handle;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CalloopData {
|
pub struct CalloopData {
|
||||||
pub display: Display<State>,
|
pub display: Display<State>,
|
||||||
pub state: State,
|
pub state: State,
|
||||||
|
@ -569,17 +433,15 @@ pub fn take_presentation_feedback(
|
||||||
output_presentation_feedback
|
output_presentation_feedback
|
||||||
}
|
}
|
||||||
|
|
||||||
/// State containing the config API's stream.
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct ApiState {
|
pub struct ApiState {
|
||||||
// TODO: this may not need to be in an arc mutex because of the move to async
|
// TODO: this may not need to be in an arc mutex because of the move to async
|
||||||
|
/// The stream API messages are being sent through
|
||||||
pub stream: Option<Arc<Mutex<UnixStream>>>,
|
pub stream: Option<Arc<Mutex<UnixStream>>>,
|
||||||
}
|
/// A token used to remove the socket source from the event loop on config restart
|
||||||
|
pub socket_token: RegistrationToken,
|
||||||
impl ApiState {
|
/// The sending channel used to send API messages from the socket source to a handler
|
||||||
pub fn new() -> Self {
|
pub tx_channel: Sender<Msg>,
|
||||||
Default::default()
|
pub config_process: async_process::Child,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait WithState {
|
pub trait WithState {
|
||||||
|
|
Loading…
Reference in a new issue