From dd5992ed98d444c099e115f0c1b3feb340aeef75 Mon Sep 17 00:00:00 2001 From: Ottatop Date: Sun, 10 Sep 2023 22:53:24 -0500 Subject: [PATCH 1/7] Remove itertools --- Cargo.toml | 2 +- src/layout.rs | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a5d7e1b..c14514c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,13 +25,13 @@ rmp-serde = { version = "1.1.2" } calloop = { version = "0.10.1", features = ["executor", "futures-io"] } futures-lite = { version = "1.13.0" } async-process = { version = "1.7.0" } -itertools = { version = "0.11.0" } x11rb = { version = "0.12.0", default-features = false, features = ["composite"], optional = true } shellexpand = "3.1.0" toml = "0.7.7" anyhow = { version = "1.0.75", features = ["backtrace"] } clap = { version = "4.4.2", features = ["derive"] } xkbcommon = "0.6.0" +xdg = "2.5.2" [features] default = ["egl", "winit", "udev", "xwayland"] diff --git a/src/layout.rs b/src/layout.rs index 154939b..6d969a0 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-or-later -use itertools::{Either, Itertools}; use smithay::{ desktop::layer_map_for_output, output::Output, @@ -401,14 +400,17 @@ fn corner(layout: &Layout, windows: Vec, rect: Rectangle { let mut windows = windows.into_iter(); let Some(corner) = windows.next() else { unreachable!() }; - let (horiz_stack, vert_stack): (Vec, Vec) = - windows.enumerate().partition_map(|(i, win)| { - if i % 2 == 0 { - Either::Left(win) - } else { - Either::Right(win) - } - }); + + let mut horiz_stack = Vec::::new(); + let mut vert_stack = Vec::::new(); + + for (i, win) in windows.enumerate() { + if i % 2 == 0 { + horiz_stack.push(win); + } else { + vert_stack.push(win); + } + } let div_factor = 2; From b2b23a88c962477c5ca95270c0cf260163a7fbeb Mon Sep 17 00:00:00 2001 From: Ottatop Date: Sun, 10 Sep 2023 23:40:22 -0500 Subject: [PATCH 2/7] Use BaseDirectories for config dir --- Cargo.toml | 5 ++--- src/state.rs | 25 ++++++++++++++----------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c14514c..5150c0b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,11 +6,9 @@ edition = "2021" license = "GPL-3.0+" description = "A WIP Smithay-based Wayland compositor, inspired by AwesomeWM" readme = "README.md" -repository = "https://github.com/Ottatop/pinnacle/" +repository = "https://github.com/pinnacle-comp/pinnacle/" keywords = ["wayland", "compositor", "smithay", "lua"] -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] tracing = "0.1.37" tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } @@ -32,6 +30,7 @@ anyhow = { version = "1.0.75", features = ["backtrace"] } clap = { version = "4.4.2", features = ["derive"] } xkbcommon = "0.6.0" xdg = "2.5.2" +lazy_static = "1.4.0" [features] default = ["egl", "winit", "udev", "xwayland"] diff --git a/src/state.rs b/src/state.rs index 69d5b36..645366e 100644 --- a/src/state.rs +++ b/src/state.rs @@ -65,9 +65,15 @@ use smithay::{ }, xwayland::{X11Surface, X11Wm, XWayland, XWaylandEvent}, }; +use xdg::BaseDirectories; use crate::input::InputState; +lazy_static::lazy_static! { + static ref XDG_BASE_DIRS: BaseDirectories = + BaseDirectories::with_prefix("pinnacle").expect("couldn't create xdg BaseDirectories"); +} + pub enum Backend { Winit(Winit), Udev(Udev), @@ -204,6 +210,7 @@ impl State { let (tx_channel, rx_channel) = calloop::channel::channel::(); let config_dir = get_config_dir(); + tracing::debug!("config dir is {:?}", config_dir); let metaconfig = crate::metaconfig::parse(&config_dir)?; @@ -401,17 +408,11 @@ impl State { } fn get_config_dir() -> PathBuf { - let config_dir = std::env::var("PINNACLE_CONFIG_DIR").unwrap_or_else(|_| { - let default_config_dir = - std::env::var("XDG_CONFIG_HOME").unwrap_or("~/.config".to_string()); + let config_dir = std::env::var("PINNACLE_CONFIG_DIR") + .ok() + .and_then(|s| Some(PathBuf::from(shellexpand::full(&s).ok()?.to_string()))); - PathBuf::from(default_config_dir) - .join("pinnacle") - .to_string_lossy() - .to_string() - }); - - PathBuf::from(shellexpand::tilde(&config_dir).to_string()) + config_dir.unwrap_or(XDG_BASE_DIRS.get_config_home()) } /// This should be called *after* you have created the [`PinnacleSocketSource`] to ensure @@ -422,7 +423,9 @@ fn start_config(metaconfig: Metaconfig, config_dir: &Path) -> anyhow::Result Date: Mon, 11 Sep 2023 02:48:33 -0500 Subject: [PATCH 3/7] Add file logging --- Cargo.toml | 2 ++ src/main.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++-------- src/state.rs | 10 +++---- 3 files changed, 67 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5150c0b..69db617 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,8 @@ clap = { version = "4.4.2", features = ["derive"] } xkbcommon = "0.6.0" xdg = "2.5.2" lazy_static = "1.4.0" +tracing-appender = "0.2.2" +walkdir = "2.4.0" [features] default = ["egl", "winit", "udev", "xwayland"] diff --git a/src/main.rs b/src/main.rs index f306c13..a80581f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,12 @@ // #![deny(unused_imports)] // gonna force myself to keep stuff clean #![warn(clippy::unwrap_used)] +use std::path::Path; + use clap::Parser; +use tracing_subscriber::{fmt::writer::MakeWriterExt, EnvFilter}; +use walkdir::WalkDir; +use xdg::BaseDirectories; mod api; mod backend; @@ -29,6 +34,11 @@ mod state; mod tag; mod window; +lazy_static::lazy_static! { + pub static ref XDG_BASE_DIRS: BaseDirectories = + BaseDirectories::with_prefix("pinnacle").expect("couldn't create xdg BaseDirectories"); +} + #[derive(clap::Args, Debug)] #[group(id = "backend", required = false, multiple = false)] struct Backends { @@ -53,18 +63,24 @@ struct Args { force: bool, } +const PINNACLE_LOG_PREFIX: &str = "pinnacle.log"; + fn main() -> anyhow::Result<()> { - match tracing_subscriber::EnvFilter::try_from_default_env() { - Ok(env_filter) => { - tracing_subscriber::fmt() - .compact() - .with_env_filter(env_filter) - .init(); - } - Err(_) => { - tracing_subscriber::fmt().compact().init(); - } - } + let xdg_state_dir = XDG_BASE_DIRS.get_state_home(); + + trim_logs(&xdg_state_dir); + + let appender = tracing_appender::rolling::hourly(xdg_state_dir, PINNACLE_LOG_PREFIX); + let (appender, _guard) = tracing_appender::non_blocking(appender); + let writer = appender.and(std::io::stdout); + + let env_filter = EnvFilter::try_from_default_env().unwrap_or(EnvFilter::new("debug")); + + tracing_subscriber::fmt() + .compact() + .with_env_filter(env_filter) + .with_writer(writer) + .init(); let args = Args::parse(); @@ -124,3 +140,38 @@ fn main() -> anyhow::Result<()> { Ok(()) } + +fn trim_logs(log_path: impl AsRef) { + let logs = WalkDir::new(log_path) + .sort_by(|a, b| { + let a_creation_time = a + .metadata() + .expect("failed to get log metadata") + .created() + .expect("failed to get log creation time"); + let b_creation_time = b + .metadata() + .expect("failed to get log metadata") + .created() + .expect("failed to get log creation time"); + + a_creation_time.cmp(&b_creation_time) + }) + .into_iter() + .filter_entry(|entry| { + entry.file_type().is_file() + && entry + .file_name() + .to_string_lossy() + .starts_with(PINNACLE_LOG_PREFIX) + }) + .filter_map(|dir| dir.ok()) + .collect::>(); + + // If there are more than 3 logs, delete the oldest ones + let num_to_delete = logs.len().saturating_sub(3); + + for entry in logs.into_iter().take(num_to_delete) { + std::fs::remove_file(entry.path()).expect("failed to remove oldest log file"); + } +} diff --git a/src/state.rs b/src/state.rs index 645366e..a219b35 100644 --- a/src/state.rs +++ b/src/state.rs @@ -65,15 +65,9 @@ use smithay::{ }, xwayland::{X11Surface, X11Wm, XWayland, XWaylandEvent}, }; -use xdg::BaseDirectories; use crate::input::InputState; -lazy_static::lazy_static! { - static ref XDG_BASE_DIRS: BaseDirectories = - BaseDirectories::with_prefix("pinnacle").expect("couldn't create xdg BaseDirectories"); -} - pub enum Backend { Winit(Winit), Udev(Udev), @@ -412,7 +406,7 @@ fn get_config_dir() -> PathBuf { .ok() .and_then(|s| Some(PathBuf::from(shellexpand::full(&s).ok()?.to_string()))); - config_dir.unwrap_or(XDG_BASE_DIRS.get_config_home()) + config_dir.unwrap_or(crate::XDG_BASE_DIRS.get_config_home()) } /// This should be called *after* you have created the [`PinnacleSocketSource`] to ensure @@ -460,6 +454,8 @@ fn start_config(metaconfig: Metaconfig, config_dir: &Path) -> anyhow::Result Date: Mon, 11 Sep 2023 03:05:45 -0500 Subject: [PATCH 4/7] Change max log count --- src/main.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index a80581f..d12fa85 100644 --- a/src/main.rs +++ b/src/main.rs @@ -70,7 +70,7 @@ fn main() -> anyhow::Result<()> { trim_logs(&xdg_state_dir); - let appender = tracing_appender::rolling::hourly(xdg_state_dir, PINNACLE_LOG_PREFIX); + let appender = tracing_appender::rolling::hourly(&xdg_state_dir, PINNACLE_LOG_PREFIX); let (appender, _guard) = tracing_appender::non_blocking(appender); let writer = appender.and(std::io::stdout); @@ -157,6 +157,7 @@ fn trim_logs(log_path: impl AsRef) { a_creation_time.cmp(&b_creation_time) }) + .contents_first(true) .into_iter() .filter_entry(|entry| { entry.file_type().is_file() @@ -168,10 +169,12 @@ fn trim_logs(log_path: impl AsRef) { .filter_map(|dir| dir.ok()) .collect::>(); - // If there are more than 3 logs, delete the oldest ones - let num_to_delete = logs.len().saturating_sub(3); - - for entry in logs.into_iter().take(num_to_delete) { - std::fs::remove_file(entry.path()).expect("failed to remove oldest log file"); + // If there are more than 4 logs, delete all but 3 + if logs.len() > 4 { + let num_to_delete = logs.len().saturating_sub(3); + for entry in logs.into_iter().take(num_to_delete) { + tracing::info!("Deleting {:?}", entry.path()); + std::fs::remove_file(entry.path()).expect("failed to remove oldest log file"); + } } } From 50716a9168db10afa3138c0fb5ce62dc8f056dd8 Mon Sep 17 00:00:00 2001 From: Ottatop Date: Mon, 11 Sep 2023 03:22:51 -0500 Subject: [PATCH 5/7] Use `$XDG_RUNTIME_DIR` for socket --- src/api.rs | 3 ++- src/state.rs | 22 ++++++++++------------ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/api.rs b/src/api.rs index e1d8dd6..0c81da1 100644 --- a/src/api.rs +++ b/src/api.rs @@ -50,6 +50,7 @@ use smithay::reexports::calloop::{ use self::msg::{Msg, OutgoingMsg}; pub const DEFAULT_SOCKET_DIR: &str = "/tmp"; +pub const SOCKET_NAME: &str = "pinnacle_socket"; fn handle_client( mut stream: UnixStream, @@ -90,7 +91,7 @@ impl PinnacleSocketSource { /// Create a loop source that listens for connections to the provided socket_dir. /// This will also set PINNACLE_SOCKET for use in API implementations. pub fn new(sender: Sender, socket_dir: &Path) -> anyhow::Result { - let socket_path = socket_dir.join("pinnacle_socket"); + let socket_path = socket_dir.join(SOCKET_NAME); if let Ok(exists) = socket_path.try_exists() { if exists { diff --git a/src/state.rs b/src/state.rs index a219b35..ae1daf7 100644 --- a/src/state.rs +++ b/src/state.rs @@ -208,24 +208,22 @@ impl State { let metaconfig = crate::metaconfig::parse(&config_dir)?; - let socket_dir = { - let dir_string = shellexpand::full( - metaconfig - .socket_dir - .as_deref() - .unwrap_or(DEFAULT_SOCKET_DIR), - )? - .to_string(); - + // 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 pathbuf = PathBuf::from(&dir_string).canonicalize()?; + let socket_dir = PathBuf::from(socket_dir).canonicalize()?; std::env::set_current_dir(current_dir)?; - - pathbuf + 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::api::DEFAULT_SOCKET_DIR)) }; let socket_source = PinnacleSocketSource::new(tx_channel, &socket_dir) From 4b66c6bd62cb647f6d6b6f9bdf5e79ba6a09defe Mon Sep 17 00:00:00 2001 From: Ottatop Date: Mon, 11 Sep 2023 03:58:43 -0500 Subject: [PATCH 6/7] Give each Pinnacle instance its own socket --- Cargo.toml | 2 ++ src/api.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 69db617..55b376e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,8 @@ xdg = "2.5.2" lazy_static = "1.4.0" tracing-appender = "0.2.2" walkdir = "2.4.0" +sysinfo = "0.29.10" + [features] default = ["egl", "winit", "udev", "xwayland"] diff --git a/src/api.rs b/src/api.rs index 0c81da1..7eab360 100644 --- a/src/api.rs +++ b/src/api.rs @@ -46,6 +46,8 @@ use anyhow::Context; use smithay::reexports::calloop::{ self, channel::Sender, generic::Generic, EventSource, Interest, Mode, PostAction, }; +use sysinfo::{ProcessRefreshKind, RefreshKind, SystemExt}; +use walkdir::WalkDir; use self::msg::{Msg, OutgoingMsg}; @@ -91,11 +93,51 @@ impl PinnacleSocketSource { /// Create a loop source that listens for connections to the provided socket_dir. /// This will also set PINNACLE_SOCKET for use in API implementations. pub fn new(sender: Sender, socket_dir: &Path) -> anyhow::Result { - let socket_path = socket_dir.join(SOCKET_NAME); + let system = sysinfo::System::new_with_specifics( + RefreshKind::new().with_processes(ProcessRefreshKind::new()), + ); - if let Ok(exists) = socket_path.try_exists() { - if exists { - std::fs::remove_file(&socket_path).context("Failed to remove old socket")?; + // Test if you are running multiple instances of Pinnacle + let multiple_instances = system.processes_by_exact_name("pinnacle").count() > 1; + + // If you are, append a suffix to the socket name + let socket_name = if multiple_instances { + let mut suffix: u8 = 1; + while let Ok(true) = socket_dir + .join(format!("{SOCKET_NAME}_{suffix}")) + .try_exists() + { + suffix += 1; + } + format!("{SOCKET_NAME}_{suffix}") + } else { + SOCKET_NAME.to_string() + }; + + let socket_path = socket_dir.join(socket_name); + + // If there are multiple instances, don't touch other sockets + if multiple_instances { + if let Ok(exists) = socket_path.try_exists() { + if exists { + std::fs::remove_file(&socket_path).context(format!( + "Failed to remove old socket at {}", + socket_path.to_string_lossy() + ))?; + } + } + } else { + // If there are, remove them all + for entry in WalkDir::new(socket_dir) + .contents_first(true) + .into_iter() + .filter_entry(|entry| entry.file_name().to_string_lossy().starts_with(SOCKET_NAME)) + .filter_map(|e| e.ok()) + { + std::fs::remove_file(entry.path()).context(format!( + "Failed to remove old socket at {}", + entry.path().to_string_lossy() + ))?; } } From 98796dde69864e21b5a211b545bb12b2a448f67a Mon Sep 17 00:00:00 2001 From: Ottatop Date: Mon, 11 Sep 2023 04:02:36 -0500 Subject: [PATCH 7/7] Remove unused import --- src/state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/state.rs b/src/state.rs index ae1daf7..8a1db97 100644 --- a/src/state.rs +++ b/src/state.rs @@ -16,7 +16,7 @@ use crate::{ window_rules::{WindowRule, WindowRuleCondition}, CallbackId, ModifierMask, Msg, }, - PinnacleSocketSource, DEFAULT_SOCKET_DIR, + PinnacleSocketSource, }, backend::{udev::Udev, winit::Winit, BackendData}, cursor::Cursor,