Merge pull request #122 from pinnacle-comp/spawn_once

Move spawn_once logic into compositor
This commit is contained in:
Ottatop 2023-12-25 21:07:27 -06:00 committed by GitHub
commit ddb4b21720
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 233 additions and 121 deletions

79
Cargo.lock generated
View file

@ -183,7 +183,7 @@ dependencies = [
"polling", "polling",
"rustix 0.38.28", "rustix 0.38.28",
"slab", "slab",
"tracing 0.1.37", "tracing",
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
@ -1458,7 +1458,7 @@ dependencies = [
"sysinfo", "sysinfo",
"thiserror", "thiserror",
"toml", "toml",
"tracing 0.2.0", "tracing",
"tracing-appender", "tracing-appender",
"tracing-subscriber", "tracing-subscriber",
"x11rb 0.13.0", "x11rb 0.13.0",
@ -1483,7 +1483,7 @@ dependencies = [
"concurrent-queue", "concurrent-queue",
"pin-project-lite", "pin-project-lite",
"rustix 0.38.28", "rustix 0.38.28",
"tracing 0.1.37", "tracing",
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
@ -1855,7 +1855,7 @@ dependencies = [
"smallvec", "smallvec",
"tempfile", "tempfile",
"thiserror", "thiserror",
"tracing 0.1.37", "tracing",
"udev 0.8.0", "udev 0.8.0",
"wayland-backend", "wayland-backend",
"wayland-egl", "wayland-egl",
@ -2079,30 +2079,20 @@ dependencies = [
[[package]] [[package]]
name = "tracing" name = "tracing"
version = "0.1.37" version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
dependencies = [
"cfg-if",
"pin-project-lite",
"tracing-attributes 0.1.24",
"tracing-core 0.1.31",
]
[[package]]
name = "tracing"
version = "0.2.0"
source = "git+https://github.com/tokio-rs/tracing?rev=84f0a60#84f0a608123a651f268ff76347f81182f487d3b1"
dependencies = [ dependencies = [
"pin-project-lite", "pin-project-lite",
"tracing-attributes 0.2.0", "tracing-attributes",
"tracing-core 0.2.0", "tracing-core",
] ]
[[package]] [[package]]
name = "tracing-appender" name = "tracing-appender"
version = "0.2.0" version = "0.2.3"
source = "git+https://github.com/tokio-rs/tracing?rev=84f0a60#84f0a608123a651f268ff76347f81182f487d3b1" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf"
dependencies = [ dependencies = [
"crossbeam-channel", "crossbeam-channel",
"thiserror", "thiserror",
@ -2112,19 +2102,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-attributes" name = "tracing-attributes"
version = "0.1.24" version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.31",
]
[[package]]
name = "tracing-attributes"
version = "0.2.0"
source = "git+https://github.com/tokio-rs/tracing?rev=84f0a60#84f0a608123a651f268ff76347f81182f487d3b1"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2133,35 +2113,30 @@ dependencies = [
[[package]] [[package]]
name = "tracing-core" name = "tracing-core"
version = "0.1.31" version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
dependencies = [
"once_cell",
]
[[package]]
name = "tracing-core"
version = "0.2.0"
source = "git+https://github.com/tokio-rs/tracing?rev=84f0a60#84f0a608123a651f268ff76347f81182f487d3b1"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"valuable",
] ]
[[package]] [[package]]
name = "tracing-log" name = "tracing-log"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/tokio-rs/tracing?rev=84f0a60#84f0a608123a651f268ff76347f81182f487d3b1" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
dependencies = [ dependencies = [
"log", "log",
"once_cell", "once_cell",
"tracing-core 0.2.0", "tracing-core",
] ]
[[package]] [[package]]
name = "tracing-subscriber" name = "tracing-subscriber"
version = "0.3.0" version = "0.3.18"
source = "git+https://github.com/tokio-rs/tracing?rev=84f0a60#84f0a608123a651f268ff76347f81182f487d3b1" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
dependencies = [ dependencies = [
"matchers", "matchers",
"nu-ansi-term", "nu-ansi-term",
@ -2170,8 +2145,8 @@ dependencies = [
"sharded-slab", "sharded-slab",
"smallvec", "smallvec",
"thread_local", "thread_local",
"tracing 0.2.0", "tracing",
"tracing-core 0.2.0", "tracing-core",
"tracing-log", "tracing-log",
] ]
@ -2216,6 +2191,12 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "valuable"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.4" version = "0.9.4"

View file

@ -10,9 +10,9 @@ repository = "https://github.com/pinnacle-comp/pinnacle/"
keywords = ["wayland", "compositor", "smithay", "lua"] keywords = ["wayland", "compositor", "smithay", "lua"]
[dependencies] [dependencies]
tracing = { git = "https://github.com/tokio-rs/tracing", rev = "84f0a60" } tracing = "0.1.40"
tracing-subscriber = { git = "https://github.com/tokio-rs/tracing", rev = "84f0a60", features = ["env-filter"] } tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
tracing-appender = { git = "https://github.com/tokio-rs/tracing", rev = "84f0a60" } tracing-appender = "0.2.3"
smithay = { git = "https://github.com/Smithay/smithay", rev = "56b6441a14600593d13229b9584058ec19e3e18b", default-features = false, features = ["desktop", "wayland_frontend"] } smithay = { git = "https://github.com/Smithay/smithay", rev = "56b6441a14600593d13229b9584058ec19e3e18b", default-features = false, features = ["desktop", "wayland_frontend"] }
smithay-drm-extras = { git = "https://github.com/Smithay/smithay", rev = "56b6441a14600593d13229b9584058ec19e3e18b", optional = true } smithay-drm-extras = { git = "https://github.com/Smithay/smithay", rev = "56b6441a14600593d13229b9584058ec19e3e18b", optional = true }
thiserror = "1" thiserror = "1"

View file

@ -29,8 +29,8 @@ require("pinnacle").setup(function(pinnacle)
-- Outputs ----------------------------------------------------------------------- -- Outputs -----------------------------------------------------------------------
-- You can set your own monitor layout as I have done below for my monitors. -- You can set your own monitor layout as I have done below for my monitors.
-- --
-- local lg = output.get_by_name("DP-2") --[[@as Output]] -- local lg = output.get_by_name("DP-2") --[[@as OutputHandle]]
-- local dell = output.get_by_name("DP-3") --[[@as Output]] -- local dell = output.get_by_name("DP-3") --[[@as OutputHandle]]
-- --
-- dell:set_loc_left_of(lg, "bottom") -- dell:set_loc_left_of(lg, "bottom")
@ -42,49 +42,55 @@ require("pinnacle").setup(function(pinnacle)
-- Mousebinds -------------------------------------------------------------------- -- Mousebinds --------------------------------------------------------------------
input.mousebind({"Ctrl"}, buttons.left, "Press", input.mousebind({ "Ctrl" }, buttons.left, "Press", function()
function() window.begin_move(buttons.left) end) window.begin_move(buttons.left)
input.mousebind({"Ctrl"}, buttons.right, "Press", end)
function() window.begin_resize(buttons.right) end) input.mousebind({ "Ctrl" }, buttons.right, "Press", function()
window.begin_resize(buttons.right)
end)
-- Keybinds ---------------------------------------------------------------------- -- Keybinds ----------------------------------------------------------------------
-- mod_key + Alt + q quits the compositor -- mod_key + Alt + q quits the compositor
input.keybind({mod_key, "Alt"}, keys.q, pinnacle.quit) input.keybind({ mod_key, "Alt" }, keys.q, pinnacle.quit)
-- mod_key + Alt + c closes the focused window -- mod_key + Alt + c closes the focused window
input.keybind({mod_key, "Alt"}, keys.c, input.keybind({ mod_key, "Alt" }, keys.c, function()
function() window.get_focused():close() end) window.get_focused():close()
end)
-- mod_key + return spawns a terminal -- mod_key + return spawns a terminal
input.keybind({mod_key}, keys.Return, function() input.keybind({ mod_key }, keys.Return, function()
process.spawn(terminal, function(stdout, stderr, exit_code, exit_msg) process.spawn(terminal, function(stdout, stderr, exit_code, exit_msg)
-- do something with the output here -- do something with the output here
end) end)
end) end)
-- mod_key + Alt + Space toggle floating on the focused window -- mod_key + Alt + Space toggle floating on the focused window
input.keybind({mod_key, "Alt"}, keys.space, input.keybind({ mod_key, "Alt" }, keys.space, function()
function() window.get_focused():toggle_floating() end) window.get_focused():toggle_floating()
end)
-- mod_key + f toggles fullscreen on the focused window -- mod_key + f toggles fullscreen on the focused window
input.keybind({mod_key}, keys.f, input.keybind({ mod_key }, keys.f, function()
function() window.get_focused():toggle_fullscreen() end) window.get_focused():toggle_fullscreen()
end)
-- mod_key + m toggles maximized on the focused window -- mod_key + m toggles maximized on the focused window
input.keybind({mod_key}, keys.m, input.keybind({ mod_key }, keys.m, function()
function() window.get_focused():toggle_maximized() end) window.get_focused():toggle_maximized()
end)
-- Tags --------------------------------------------------------------------------- -- Tags ---------------------------------------------------------------------------
local tags = {"1", "2", "3", "4", "5"} local tags = { "1", "2", "3", "4", "5" }
output.connect_for_all(function(op) output.connect_for_all(function(op)
-- Add tags 1, 2, 3, 4 and 5 on all monitors, and toggle tag 1 active by default -- Add tags 1, 2, 3, 4 and 5 on all monitors, and toggle tag 1 active by default
op:add_tags(tags) op:add_tags(tags)
-- Same as tag.add(op, "1", "2", "3", "4", "5") -- Same as tag.add(op, "1", "2", "3", "4", "5")
tag.toggle({name = "1", output = op}) tag.toggle({ name = "1", output = op })
-- Window rules -- Window rules
-- Add your own window rules here. Below is an example. -- Add your own window rules here. Below is an example.
@ -111,30 +117,35 @@ require("pinnacle").setup(function(pinnacle)
-- Create a layout cycler to cycle your tag layouts. This will store which layout each tag has -- Create a layout cycler to cycle your tag layouts. This will store which layout each tag has
-- and change to the next or previous one in the array when the respective function is called. -- and change to the next or previous one in the array when the respective function is called.
local layout_cycler = tag.layout_cycler({ local layout_cycler = tag.layout_cycler({
"MasterStack", "Dwindle", "Spiral", "CornerTopLeft", "CornerTopRight", "MasterStack",
"CornerBottomLeft", "CornerBottomRight" "Dwindle",
"Spiral",
"CornerTopLeft",
"CornerTopRight",
"CornerBottomLeft",
"CornerBottomRight",
}) })
input.keybind({mod_key}, keys.space, layout_cycler.next) input.keybind({ mod_key }, keys.space, layout_cycler.next)
input.keybind({mod_key, "Shift"}, keys.space, layout_cycler.prev) input.keybind({ mod_key, "Shift" }, keys.space, layout_cycler.prev)
-- Tag manipulation -- Tag manipulation
for _, tag_name in pairs(tags) do for _, tag_name in pairs(tags) do
-- mod_key + 1-5 switches tags -- mod_key + 1-5 switches tags
input.keybind({mod_key}, tag_name, input.keybind({ mod_key }, tag_name, function()
function() tag.switch_to(tag_name) end) tag.switch_to(tag_name)
end)
-- mod_key + Shift + 1-5 toggles tags -- mod_key + Shift + 1-5 toggles tags
input.keybind({mod_key, "Shift"}, tag_name, input.keybind({ mod_key, "Shift" }, tag_name, function()
function() tag.toggle(tag_name) end) tag.toggle(tag_name)
end)
-- mod_key + Alt + 1-5 moves windows to tags -- mod_key + Alt + 1-5 moves windows to tags
input.keybind({mod_key, "Alt"}, tag_name, input.keybind({ mod_key, "Alt" }, tag_name, function()
function()
window:get_focused():move_to_tag(tag_name) window:get_focused():move_to_tag(tag_name)
end) end)
-- mod_key + Shift + Alt + 1-5 toggles tags on windows -- mod_key + Shift + Alt + 1-5 toggles tags on windows
input.keybind({mod_key, "Shift", "Alt"}, tag_name, input.keybind({ mod_key, "Shift", "Alt" }, tag_name, function()
function()
window.get_focused():toggle_tag(tag_name) window.get_focused():toggle_tag(tag_name)
end) end)
end end

View file

@ -18,6 +18,7 @@
---@field WindowResizeGrab { button: integer }? ---@field WindowResizeGrab { button: integer }?
-- --
---@field Spawn { command: string[], callback_id: integer? }? ---@field Spawn { command: string[], callback_id: integer? }?
---@field SpawnOnce { command: string[], callback_id: integer? }?
---@field SetEnv { key: string, value: string }? ---@field SetEnv { key: string, value: string }?
--Tags --Tags
---@field ToggleTag { tag_id: TagId }? ---@field ToggleTag { tag_id: TagId }?

View file

@ -8,17 +8,10 @@
---@class ProcessModule ---@class ProcessModule
local process_module = {} local process_module = {}
---Spawn a process with an optional callback for its stdout, stderr, and exit information. ---@param command string|string[]
---
---`callback` has the following parameters:
---
--- - `stdout` - The process's stdout printed this line.
--- - `stderr` - The process's stderr printed this line.
--- - `exit_code` - The process exited with this code.
--- - `exit_msg` - The process exited with this message.
---@param command string|string[] The command as one whole string or a table of each of its arguments
---@param callback fun(stdout: string|nil, stderr: string|nil, exit_code: integer|nil, exit_msg: string|nil)? A callback to do something whenever the process's stdout or stderr print a line, or when the process exits. ---@param callback fun(stdout: string|nil, stderr: string|nil, exit_code: integer|nil, exit_msg: string|nil)? A callback to do something whenever the process's stdout or stderr print a line, or when the process exits.
function process_module.spawn(command, callback) ---@param spawn_once boolean
local function spawn_inner(command, callback, spawn_once)
---@type integer|nil ---@type integer|nil
local callback_id = nil local callback_id = nil
@ -40,14 +33,38 @@ function process_module.spawn(command, callback)
command_arr = command command_arr = command
end end
SendMsg({ if spawn_once then
Spawn = { SendMsg({
command = command_arr, SpawnOnce = {
callback_id = callback_id, command = command_arr,
}, callback_id = callback_id,
}) },
})
else
SendMsg({
Spawn = {
command = command_arr,
callback_id = callback_id,
},
})
end
end end
---Spawn a process with an optional callback for its stdout, stderr, and exit information.
---
---`callback` has the following parameters:
---
--- - `stdout` - The process's stdout printed this line.
--- - `stderr` - The process's stderr printed this line.
--- - `exit_code` - The process exited with this code.
--- - `exit_msg` - The process exited with this message.
---@param command string|string[] The command as one whole string or a table of each of its arguments
---@param callback fun(stdout: string|nil, stderr: string|nil, exit_code: integer|nil, exit_msg: string|nil)? A callback to do something whenever the process's stdout or stderr print a line, or when the process exits.
function process_module.spawn(command, callback)
spawn_inner(command, callback, false)
end
-- PERF: callback is stored regardless if cmd was actually spawned
---Spawn a process only if it isn't already running, with an optional callback for its stdout, stderr, and exit information. ---Spawn a process only if it isn't already running, with an optional callback for its stdout, stderr, and exit information.
--- ---
---`callback` has the following parameters: ---`callback` has the following parameters:
@ -61,19 +78,7 @@ end
---@param command string|string[] The command as one whole string or a table of each of its arguments ---@param command string|string[] The command as one whole string or a table of each of its arguments
---@param callback fun(stdout: string|nil, stderr: string|nil, exit_code: integer|nil, exit_msg: string|nil)? A callback to do something whenever the process's stdout or stderr print a line, or when the process exits. ---@param callback fun(stdout: string|nil, stderr: string|nil, exit_code: integer|nil, exit_msg: string|nil)? A callback to do something whenever the process's stdout or stderr print a line, or when the process exits.
function process_module.spawn_once(command, callback) function process_module.spawn_once(command, callback)
local proc = "" spawn_inner(command, callback, true)
if type(command) == "string" then
proc = command:match("%S+")
else
proc = command[1]
end
---@type string
local procs = io.popen("pgrep -f " .. proc):read("*a")
if procs:len() ~= 0 then -- if process exists, return
return
end
process_module.spawn(command, callback)
end end
---Set an environment variable for Pinnacle. All future processes spawned will have this env set. ---Set an environment variable for Pinnacle. All future processes spawned will have this env set.

View file

@ -150,6 +150,12 @@ pub(crate) enum Msg {
#[serde(default)] #[serde(default)]
callback_id: Option<CallbackId>, callback_id: Option<CallbackId>,
}, },
/// Spawn a program with an optional callback only if it isn't running.
SpawnOnce {
command: Vec<String>,
#[serde(default)]
callback_id: Option<CallbackId>,
},
SetEnv { SetEnv {
key: String, key: String,
value: String, value: String,

View file

@ -19,6 +19,20 @@ pub fn spawn(command: Vec<&str>) -> anyhow::Result<()> {
send_msg(msg) send_msg(msg)
} }
/// Spawn a process only if it isn't already running.
///
/// This will use Rust's (more specifically `async_process`'s) `Command` to spawn the provided
/// arguments. If you are using any shell syntax like `~`, you may need to spawn a shell
/// instead. If so, you may *also* need to correctly escape the input.
pub fn spawn_once(command: Vec<&str>) -> anyhow::Result<()> {
let msg = Msg::SpawnOnce {
command: command.into_iter().map(|s| s.to_string()).collect(),
callback_id: None,
};
send_msg(msg)
}
/// Spawn a process with an optional callback for its stdout, stderr, and exit information. /// Spawn a process with an optional callback for its stdout, stderr, and exit information.
/// ///
/// `callback` has the following parameters: /// `callback` has the following parameters:
@ -60,6 +74,49 @@ where
send_msg(msg) send_msg(msg)
} }
// TODO: literally copy pasted from above, but will be rewritten so meh
/// Spawn a process with an optional callback for its stdout, stderr, and exit information,
/// only if it isn't already running.
///
/// `callback` has the following parameters:
/// - `0`: The process's stdout printed this line.
/// - `1`: The process's stderr printed this line.
/// - `2`: The process exited with this code.
/// - `3`: The process exited with this message.
/// - `4`: A `&mut `[`CallbackVec`] for use inside the closure.
///
/// You must also pass in a mutable reference to a [`CallbackVec`] in order to store your callback.
pub fn spawn_once_with_callback<'a, F>(
command: Vec<&str>,
mut callback: F,
callback_vec: &mut CallbackVec<'a>,
) -> anyhow::Result<()>
where
F: FnMut(Option<String>, Option<String>, Option<i32>, Option<String>, &mut CallbackVec) + 'a,
{
let args_callback = move |args: Option<Args>, callback_vec: &mut CallbackVec<'_>| {
if let Some(Args::Spawn {
stdout,
stderr,
exit_code,
exit_msg,
}) = args
{
callback(stdout, stderr, exit_code, exit_msg, callback_vec);
}
};
let len = callback_vec.callbacks.len();
callback_vec.callbacks.push(Box::new(args_callback));
let msg = Msg::SpawnOnce {
command: command.into_iter().map(|s| s.to_string()).collect(),
callback_id: Some(CallbackId(len as u32)),
};
send_msg(msg)
}
/// Set an environment variable for Pinnacle. All future processes spawned will have this env set. /// Set an environment variable for Pinnacle. All future processes spawned will have this env set.
/// ///
/// Note that this will only set the variable for the compositor, not the running config process. /// Note that this will only set the variable for the compositor, not the running config process.

View file

@ -44,14 +44,12 @@ use std::{
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
use self::msg::{Msg, OutgoingMsg};
use anyhow::Context; use anyhow::Context;
use calloop::RegistrationToken; use calloop::RegistrationToken;
use smithay::reexports::calloop::{ use smithay::reexports::calloop::{
self, channel::Sender, generic::Generic, EventSource, Interest, Mode, PostAction, self, channel::Sender, generic::Generic, EventSource, Interest, Mode, PostAction,
}; };
use sysinfo::{ProcessRefreshKind, RefreshKind, SystemExt};
use self::msg::{Msg, OutgoingMsg};
pub const SOCKET_NAME: &str = "pinnacle_socket"; pub const SOCKET_NAME: &str = "pinnacle_socket";
@ -100,15 +98,15 @@ pub struct PinnacleSocketSource {
impl PinnacleSocketSource { impl PinnacleSocketSource {
/// Create a loop source that listens for connections to the provided `socket_dir`. /// Create a loop source that listens for connections to the provided `socket_dir`.
/// This will also set PINNACLE_SOCKET for use in API implementations. /// This will also set PINNACLE_SOCKET for use in API implementations.
pub fn new(sender: Sender<Msg>, socket_dir: &Path) -> anyhow::Result<Self> { pub fn new(
sender: Sender<Msg>,
socket_dir: &Path,
multiple_instances: bool,
) -> anyhow::Result<Self> {
tracing::debug!("Creating socket source for dir {socket_dir:?}"); tracing::debug!("Creating socket source for dir {socket_dir:?}");
let system = sysinfo::System::new_with_specifics(
RefreshKind::new().with_processes(ProcessRefreshKind::new()),
);
// Test if you are running multiple instances of Pinnacle // Test if you are running multiple instances of Pinnacle
let multiple_instances = system.processes_by_exact_name("pinnacle").count() > 1; // let multiple_instances = system.processes_by_exact_name("pinnacle").count() > 1;
// If you are, append a suffix to the socket name // If you are, append a suffix to the socket name
let socket_name = if multiple_instances { let socket_name = if multiple_instances {

View file

@ -9,6 +9,7 @@ use smithay::{
utils::{Point, Rectangle, SERIAL_COUNTER}, utils::{Point, Rectangle, SERIAL_COUNTER},
wayland::{compositor, shell::xdg::XdgToplevelSurfaceData}, wayland::{compositor, shell::xdg::XdgToplevelSurfaceData},
}; };
use sysinfo::{PidExt, ProcessExt, ProcessRefreshKind, SystemExt};
use crate::{ use crate::{
api::msg::{ api::msg::{
@ -90,6 +91,31 @@ impl State {
} => { } => {
self.handle_spawn(command, callback_id); self.handle_spawn(command, callback_id);
} }
Msg::SpawnOnce {
command,
callback_id,
} => {
self.system_processes
.refresh_processes_specifics(ProcessRefreshKind::new());
let Some(arg0) = command.first() else {
tracing::warn!("No command specified for `SpawnOnce`");
return;
};
let compositor_pid = std::process::id();
let already_running =
self.system_processes
.processes_by_exact_name(arg0)
.any(|proc| {
proc.parent()
.is_some_and(|parent_pid| parent_pid.as_u32() == compositor_pid)
});
if !already_running {
self.handle_spawn(command, callback_id);
}
}
Msg::SetEnv { key, value } => std::env::set_var(key, value), Msg::SetEnv { key, value } => std::env::set_var(key, value),
Msg::SetWindowSize { Msg::SetWindowSize {

View file

@ -125,6 +125,11 @@ pub enum Msg {
#[serde(default)] #[serde(default)]
callback_id: Option<CallbackId>, callback_id: Option<CallbackId>,
}, },
SpawnOnce {
command: Vec<String>,
#[serde(default)]
callback_id: Option<CallbackId>,
},
SetEnv { SetEnv {
key: String, key: String,
value: String, value: String,

View file

@ -15,6 +15,7 @@ use smithay::{
input::keyboard::keysyms, input::keyboard::keysyms,
utils::{Logical, Point}, utils::{Logical, Point},
}; };
use sysinfo::{ProcessRefreshKind, SystemExt};
use toml::Table; use toml::Table;
use crate::api::msg::{CallbackId, Modifier}; use crate::api::msg::{CallbackId, Modifier};
@ -236,7 +237,16 @@ impl State {
.unwrap_or(PathBuf::from(DEFAULT_SOCKET_DIR)) .unwrap_or(PathBuf::from(DEFAULT_SOCKET_DIR))
}; };
let socket_source = PinnacleSocketSource::new(tx_channel, &socket_dir) self.system_processes
.refresh_processes_specifics(ProcessRefreshKind::new());
let multiple_instances = self
.system_processes
.processes_by_exact_name("pinnacle")
.count()
> 1;
let socket_source = PinnacleSocketSource::new(tx_channel, &socket_dir, multiple_instances)
.context("Failed to create socket source")?; .context("Failed to create socket source")?;
let reload_keybind = metaconfig.reload_keybind; let reload_keybind = metaconfig.reload_keybind;

View file

@ -13,6 +13,7 @@
use clap::Parser; use clap::Parser;
use nix::unistd::Uid; use nix::unistd::Uid;
use sysinfo::{ProcessRefreshKind, RefreshKind, SystemExt};
use tracing_appender::rolling::Rotation; use tracing_appender::rolling::Rotation;
use tracing_subscriber::{fmt::writer::MakeWriterExt, EnvFilter}; use tracing_subscriber::{fmt::writer::MakeWriterExt, EnvFilter};
use xdg::BaseDirectories; use xdg::BaseDirectories;
@ -35,6 +36,10 @@ mod window;
lazy_static::lazy_static! { lazy_static::lazy_static! {
pub static ref XDG_BASE_DIRS: BaseDirectories = pub static ref XDG_BASE_DIRS: BaseDirectories =
BaseDirectories::with_prefix("pinnacle").expect("couldn't create xdg BaseDirectories"); BaseDirectories::with_prefix("pinnacle").expect("couldn't create xdg BaseDirectories");
pub static ref SYSTEM_PROCESSES: sysinfo::System =
sysinfo::System::new_with_specifics(
RefreshKind::new().with_processes(ProcessRefreshKind::new()),
);
} }
#[derive(clap::Args, Debug)] #[derive(clap::Args, Debug)]

View file

@ -41,6 +41,7 @@ use smithay::{
}, },
xwayland::{X11Wm, XWayland, XWaylandEvent}, xwayland::{X11Wm, XWayland, XWaylandEvent},
}; };
use sysinfo::{ProcessRefreshKind, RefreshKind, SystemExt};
use crate::input::InputState; use crate::input::InputState;
@ -98,6 +99,8 @@ pub struct State {
pub xwayland: XWayland, pub xwayland: XWayland,
pub xwm: Option<X11Wm>, pub xwm: Option<X11Wm>,
pub xdisplay: Option<u32>, pub xdisplay: Option<u32>,
pub system_processes: sysinfo::System,
} }
impl State { impl State {
@ -281,6 +284,10 @@ impl State {
xwayland, xwayland,
xwm: None, xwm: None,
xdisplay: None, xdisplay: None,
system_processes: sysinfo::System::new_with_specifics(
RefreshKind::new().with_processes(ProcessRefreshKind::new()),
),
}) })
} }