2023-08-01 18:06:35 +02:00
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
2023-06-22 01:58:49 +02:00
|
|
|
|
|
|
|
//! A very, VERY WIP Smithay-based Wayland compositor.
|
|
|
|
//!
|
|
|
|
//! Pinnacle is heavily inspired by the [Awesome Window Manager](https://awesomewm.org),
|
|
|
|
//! and this is an attempt to make something akin to it for Wayland.
|
|
|
|
//!
|
2023-06-22 02:08:29 +02:00
|
|
|
//! While Pinnacle is not a library, this documentation serves to guide those who want to
|
2023-06-22 01:58:49 +02:00
|
|
|
//! contribute or learn how building something like this works.
|
|
|
|
|
2024-01-22 06:42:48 +01:00
|
|
|
// #![deny(unused_imports)] // this has remained commented out for months lol
|
2023-06-30 00:41:08 +02:00
|
|
|
#![warn(clippy::unwrap_used)]
|
2023-06-29 19:29:00 +02:00
|
|
|
|
2024-02-19 07:17:26 +01:00
|
|
|
use anyhow::Context;
|
2024-03-02 08:23:31 +01:00
|
|
|
use cli::Cli;
|
2023-12-19 12:09:36 +01:00
|
|
|
use nix::unistd::Uid;
|
2024-02-19 07:17:26 +01:00
|
|
|
use tracing::{info, level_filters::LevelFilter, warn};
|
2023-09-14 08:34:20 +02:00
|
|
|
use tracing_appender::rolling::Rotation;
|
2024-02-19 07:17:26 +01:00
|
|
|
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Layer};
|
2023-09-11 09:48:33 +02:00
|
|
|
use xdg::BaseDirectories;
|
2023-09-08 07:21:09 +02:00
|
|
|
|
2023-12-15 05:00:04 +01:00
|
|
|
mod api;
|
2023-06-12 00:56:34 +02:00
|
|
|
mod backend;
|
2024-03-02 08:23:31 +01:00
|
|
|
mod cli;
|
2023-09-20 22:27:51 +02:00
|
|
|
mod config;
|
2023-06-12 00:56:34 +02:00
|
|
|
mod cursor;
|
2023-06-18 04:02:58 +02:00
|
|
|
mod focus;
|
2023-06-12 00:56:34 +02:00
|
|
|
mod grab;
|
|
|
|
mod handlers;
|
|
|
|
mod input;
|
|
|
|
mod layout;
|
2023-06-26 03:26:52 +02:00
|
|
|
mod output;
|
2023-06-12 00:56:34 +02:00
|
|
|
mod render;
|
|
|
|
mod state;
|
2023-07-01 04:34:07 +02:00
|
|
|
mod tag;
|
2023-06-12 00:56:34 +02:00
|
|
|
mod window;
|
|
|
|
|
2024-01-08 20:43:38 +01:00
|
|
|
#[tokio::main]
|
2024-01-08 19:51:04 +01:00
|
|
|
async fn main() -> anyhow::Result<()> {
|
2024-02-17 07:00:25 +01:00
|
|
|
let xdg_state_dir = BaseDirectories::with_prefix("pinnacle")?.get_state_home();
|
2023-09-11 09:48:33 +02:00
|
|
|
|
2023-09-14 08:34:20 +02:00
|
|
|
let appender = tracing_appender::rolling::Builder::new()
|
|
|
|
.rotation(Rotation::HOURLY)
|
|
|
|
.filename_suffix("pinnacle.log")
|
|
|
|
.max_log_files(8)
|
|
|
|
.build(xdg_state_dir)
|
2024-02-19 07:17:26 +01:00
|
|
|
.context("failed to build file logger")?;
|
2023-09-11 09:48:33 +02:00
|
|
|
|
|
|
|
let (appender, _guard) = tracing_appender::non_blocking(appender);
|
|
|
|
|
2024-02-19 07:17:26 +01:00
|
|
|
let env_filter = EnvFilter::try_from_default_env();
|
2023-09-11 09:48:33 +02:00
|
|
|
|
2024-02-19 07:17:26 +01:00
|
|
|
let file_log_env_filter = match env_filter.as_ref() {
|
|
|
|
Ok(filter) if filter.max_level_hint() == Some(LevelFilter::TRACE) => {
|
|
|
|
EnvFilter::new("trace")
|
|
|
|
}
|
|
|
|
_ => EnvFilter::new("debug"),
|
|
|
|
};
|
|
|
|
|
|
|
|
let file_log_layer = tracing_subscriber::fmt::layer()
|
|
|
|
.compact()
|
|
|
|
.with_writer(appender)
|
|
|
|
.with_filter(file_log_env_filter);
|
|
|
|
|
|
|
|
let stdout_env_filter = env_filter.unwrap_or_else(|_| EnvFilter::new("info"));
|
|
|
|
let stdout_layer = tracing_subscriber::fmt::layer()
|
2023-09-11 09:48:33 +02:00
|
|
|
.compact()
|
2024-02-19 07:17:26 +01:00
|
|
|
.with_writer(std::io::stdout)
|
|
|
|
.with_filter(stdout_env_filter);
|
|
|
|
|
|
|
|
tracing_subscriber::registry()
|
|
|
|
.with(file_log_layer)
|
|
|
|
.with(stdout_layer)
|
2023-09-11 09:48:33 +02:00
|
|
|
.init();
|
2023-06-15 19:42:34 +02:00
|
|
|
|
2024-03-03 09:25:19 +01:00
|
|
|
let Some(cli) = Cli::parse_and_prompt() else {
|
|
|
|
return Ok(());
|
|
|
|
};
|
2023-09-08 07:21:09 +02:00
|
|
|
|
2024-02-19 07:17:26 +01:00
|
|
|
if Uid::effective().is_root() {
|
2024-03-03 09:25:19 +01:00
|
|
|
if !cli.allow_root {
|
2024-02-19 07:17:26 +01:00
|
|
|
warn!("You are trying to run Pinnacle as root.");
|
|
|
|
warn!("This is NOT recommended.");
|
2024-03-03 09:25:19 +01:00
|
|
|
warn!("To run Pinnacle as root, pass in the `--allow-root` flag.");
|
2024-02-19 07:17:26 +01:00
|
|
|
warn!("Again, this is NOT recommended.");
|
|
|
|
return Ok(());
|
|
|
|
} else {
|
|
|
|
warn!("Running Pinnacle as root. I hope you know what you're doing 🫡");
|
|
|
|
}
|
2023-09-08 07:21:09 +02:00
|
|
|
}
|
|
|
|
|
2023-08-08 20:25:47 +02:00
|
|
|
let in_graphical_env =
|
|
|
|
std::env::var("WAYLAND_DISPLAY").is_ok() || std::env::var("DISPLAY").is_ok();
|
|
|
|
|
2024-01-30 03:46:18 +01:00
|
|
|
if !sysinfo::set_open_files_limit(0) {
|
2024-02-19 07:17:26 +01:00
|
|
|
warn!("Unable to set `sysinfo`'s open files limit to 0.");
|
|
|
|
warn!("You may see LOTS of file descriptors open under Pinnacle.");
|
2024-01-30 03:46:18 +01:00
|
|
|
}
|
|
|
|
|
2024-03-04 22:54:30 +01:00
|
|
|
let (mut state, mut event_loop) = match (cli.backend, cli.force) {
|
2024-03-02 08:23:31 +01:00
|
|
|
(None, _) => {
|
2023-09-08 07:21:09 +02:00
|
|
|
if in_graphical_env {
|
2024-02-19 07:17:26 +01:00
|
|
|
info!("Starting winit backend");
|
2024-03-04 22:54:30 +01:00
|
|
|
crate::backend::winit::setup_winit(cli.no_config, cli.config_dir)?
|
2023-09-08 07:21:09 +02:00
|
|
|
} else {
|
2024-02-19 07:17:26 +01:00
|
|
|
info!("Starting udev backend");
|
2024-03-04 22:54:30 +01:00
|
|
|
crate::backend::udev::setup_udev(cli.no_config, cli.config_dir)?
|
2023-09-08 07:21:09 +02:00
|
|
|
}
|
|
|
|
}
|
2024-03-02 08:23:31 +01:00
|
|
|
(Some(cli::Backend::Winit), force) => {
|
2023-08-08 20:25:47 +02:00
|
|
|
if !in_graphical_env {
|
2023-09-08 07:21:09 +02:00
|
|
|
if force {
|
2024-02-19 07:17:26 +01:00
|
|
|
warn!("Starting winit backend with no detected graphical environment");
|
2024-03-04 22:54:30 +01:00
|
|
|
crate::backend::winit::setup_winit(cli.no_config, cli.config_dir)?
|
2023-08-08 20:25:47 +02:00
|
|
|
} else {
|
2024-02-19 07:17:26 +01:00
|
|
|
warn!("Both WAYLAND_DISPLAY and DISPLAY are not set.");
|
|
|
|
warn!("If you are trying to run the winit backend in a tty, it won't work.");
|
2024-03-03 09:25:19 +01:00
|
|
|
warn!("If you really want to, additionally pass in the `--force` flag.");
|
2024-03-04 22:54:30 +01:00
|
|
|
return Ok(());
|
2023-08-08 20:25:47 +02:00
|
|
|
}
|
|
|
|
} else {
|
2024-02-19 07:17:26 +01:00
|
|
|
info!("Starting winit backend");
|
2024-03-04 22:54:30 +01:00
|
|
|
crate::backend::winit::setup_winit(cli.no_config, cli.config_dir)?
|
2023-08-08 20:25:47 +02:00
|
|
|
}
|
2023-06-19 20:27:54 +02:00
|
|
|
}
|
2024-03-02 08:23:31 +01:00
|
|
|
(Some(cli::Backend::Udev), force) => {
|
2023-08-08 20:25:47 +02:00
|
|
|
if in_graphical_env {
|
2023-09-08 07:21:09 +02:00
|
|
|
if force {
|
2024-02-19 07:17:26 +01:00
|
|
|
warn!("Starting udev backend with a detected graphical environment");
|
2024-03-04 22:54:30 +01:00
|
|
|
crate::backend::udev::setup_udev(cli.no_config, cli.config_dir)?
|
2023-08-08 20:25:47 +02:00
|
|
|
} else {
|
2024-02-19 07:17:26 +01:00
|
|
|
warn!("WAYLAND_DISPLAY and/or DISPLAY are set.");
|
|
|
|
warn!("If you are trying to run the udev backend in a graphical environment,");
|
|
|
|
warn!("it won't work and may mess some things up.");
|
2024-03-03 09:25:19 +01:00
|
|
|
warn!("If you really want to, additionally pass in the `--force` flag.");
|
2024-03-04 22:54:30 +01:00
|
|
|
return Ok(());
|
2023-08-08 20:25:47 +02:00
|
|
|
}
|
|
|
|
} else {
|
2024-02-19 07:17:26 +01:00
|
|
|
info!("Starting udev backend");
|
2024-03-04 22:54:30 +01:00
|
|
|
crate::backend::udev::setup_udev(cli.no_config, cli.config_dir)?
|
2023-08-08 20:25:47 +02:00
|
|
|
}
|
2023-06-19 20:27:54 +02:00
|
|
|
}
|
2024-03-04 22:54:30 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
event_loop.run(None, &mut state, |state| {
|
|
|
|
state.fixup_focus();
|
|
|
|
state.space.refresh();
|
|
|
|
state.popup_manager.cleanup();
|
|
|
|
state
|
|
|
|
.display_handle
|
|
|
|
.flush_clients()
|
|
|
|
.expect("failed to flush client buffers");
|
|
|
|
})?;
|
2023-06-19 19:42:49 +02:00
|
|
|
|
2023-06-12 00:56:34 +02:00
|
|
|
Ok(())
|
|
|
|
}
|