mod clients;
mod color;
mod color_management;
mod config;
mod control_center;
mod damage_tracking;
mod debugfs;
mod duration;
mod generate;
mod idle;
mod input;
mod json;
mod log;
mod pid;
mod quit;
mod randr;
mod reexec;
mod run_privileged;
mod run_tagged;
pub mod screenshot;
mod seat_test;
mod set_log_level;
mod trace;
mod tree;
mod unlock;
mod version;
mod xwayland;
use crate::cli::clients::ClientsArgs;
use crate::cli::color_management::ColorManagementArgs;
use crate::cli::config::ConfigArgs;
use crate::cli::damage_tracking::DamageTrackingArgs;
use crate::cli::debugfs::DebugfsArgs;
use crate::cli::idle::IdleCmd;
use crate::cli::input::InputArgs;
use crate::cli::json::VERBOSE_JSON;
use crate::cli::randr::RandrArgs;
use crate::cli::reexec::ReexecArgs;
use crate::cli::run_tagged::RunTaggedArgs;
use crate::cli::trace::TraceArgs;
use crate::cli::tree::TreeArgs;
use crate::cli::xwayland::XwaylandArgs;
use crate::compositor::LogLevel;
use crate::compositor::start_compositor;
use crate::env::CONFIG_DIR;
use crate::env::INITIAL_LOG_LEVEL;
use crate::format::Format;
use crate::format::ref_formats;
use crate::portal;
use crate::pr_caps::drop_all_pr_caps;
use crate::utils::errorfmt::ErrorFmt;
use clap::Args;
use clap::Parser;
use clap::Subcommand;
use clap::ValueEnum;
use clap::ValueHint;
use clap::builder::PossibleValue;
use clap_complete::Shell;
use std::io::Read;
use std::io::stdin;
use std::sync::atomic::Ordering::Relaxed;
#[derive(Parser, Debug)]
struct Jay {
#[clap(flatten)]
global: GlobalArgs,
#[clap(subcommand)]
command: Cmd,
}
#[derive(Args, Debug)]
pub struct GlobalArgs {
#[clap(value_enum, long)]
log_level: Option<LogLevel>,
#[clap(long)]
config_dir: Option<String>,
#[clap(long)]
json: bool,
#[clap(long)]
all_json_fields: bool,
}
#[derive(Subcommand, Debug)]
pub enum Cmd {
Run(RunArgs),
Config(ConfigArgs),
GenerateCompletion(GenerateArgs),
Log(LogArgs),
SetLogLevel(SetLogArgs),
Quit,
Unlock,
Screenshot(ScreenshotArgs),
Idle(IdleArgs),
RunPrivileged(RunPrivilegedArgs),
RunTagged(RunTaggedArgs),
SeatTest(SeatTestArgs),
Portal,
Randr(RandrArgs),
Input(InputArgs),
#[clap(hide = true)]
DamageTracking(DamageTrackingArgs),
Xwayland(XwaylandArgs),
ColorManagement(ColorManagementArgs),
#[clap(hide = true)]
Reexec(ReexecArgs),
Clients(ClientsArgs),
Tree(TreeArgs),
ControlCenter,
Version,
Pid,
Trace(TraceArgs),
Debugfs(DebugfsArgs),
#[cfg(feature = "it")]
RunTests,
}
#[derive(Args, Debug)]
pub struct IdleArgs {
#[clap(subcommand)]
command: Option<IdleCmd>,
}
#[derive(Args, Debug)]
pub struct RunPrivilegedArgs {
#[clap(required = true, trailing_var_arg = true, value_hint = ValueHint::CommandWithArguments)]
program: Vec<String>,
}
#[derive(ValueEnum, Debug, Copy, Clone, Hash, Default, PartialEq)]
pub enum ScreenshotFormat {
#[default]
Png,
Qoi,
}
#[derive(Args, Debug)]
pub struct ScreenshotArgs {
#[clap(value_enum, long, default_value_t)]
format: ScreenshotFormat,
#[clap(long)]
hdr10: bool,
#[clap(value_hint = ValueHint::FilePath)]
filename: Option<String>,
}
#[derive(Args, Debug, Default)]
pub struct RunArgs {
#[clap(value_enum, use_value_delimiter = true, long)]
pub backends: Vec<CliBackend>,
}
#[derive(Args, Debug)]
pub struct LogArgs {
#[clap(long)]
path: bool,
#[clap(long, short)]
follow: bool,
#[clap(long, short = 'e')]
pager_end: bool,
}
#[derive(Args, Debug)]
pub struct SetLogArgs {
#[clap(value_enum)]
level: LogLevel,
}
#[derive(Args, Debug)]
pub struct SeatTestArgs {
#[clap(long, short = 'a')]
all: bool,
seat: Option<String>,
}
#[derive(ValueEnum, Debug, Copy, Clone, Hash, Eq, PartialEq)]
pub enum CliBackend {
X11,
Metal,
Headless,
}
#[derive(Args, Debug)]
pub struct GenerateArgs {
#[clap(value_enum)]
shell: Shell,
}
impl ValueEnum for &'static Format {
fn value_variants<'a>() -> &'a [Self] {
ref_formats()
}
fn to_possible_value(&self) -> Option<PossibleValue> {
Some(PossibleValue::new(self.name))
}
}
#[derive(Args, Debug)]
#[group(required = true, multiple = false)]
struct MatchSource {
#[clap(short, long)]
expr: Option<String>,
#[clap(short, long, value_hint = ValueHint::FilePath)]
file: Option<String>,
}
impl MatchSource {
fn read(&self, source: &mut Vec<u8>) -> &str {
let path;
let res = if let Some(f) = &self.file {
if f == "-" {
path = "<stdin>";
stdin().read_to_end(source).map(drop)
} else {
path = f;
std::fs::read(f).map(|v| *source = v)
}
} else {
path = "-e value";
source.extend_from_slice(self.expr.as_ref().unwrap().as_bytes());
Ok(())
};
if let Err(e) = res {
fatal!("Could not read {path}: {}", ErrorFmt(e))
}
path
}
}
pub fn main() {
let mut cli = Jay::parse();
if let Some(dir) = cli.global.config_dir.take() {
let _ = CONFIG_DIR.set(Some(dir));
}
if let Some(level) = cli.global.log_level {
let _ = INITIAL_LOG_LEVEL.set(level);
}
if not_matches!(cli.command, Cmd::Run(_)) {
drop_all_pr_caps();
}
if cli.global.all_json_fields {
VERBOSE_JSON.store(true, Relaxed);
}
match cli.command {
Cmd::Run(a) => start_compositor(cli.global, a),
Cmd::GenerateCompletion(g) => generate::main(g),
Cmd::Log(a) => log::main(cli.global, a),
Cmd::Quit => quit::main(cli.global),
Cmd::SetLogLevel(a) => set_log_level::main(cli.global, a),
Cmd::Screenshot(a) => screenshot::main(cli.global, a),
Cmd::Idle(a) => idle::main(cli.global, a),
Cmd::Unlock => unlock::main(cli.global),
Cmd::RunPrivileged(a) => run_privileged::main(cli.global, a),
Cmd::RunTagged(a) => run_tagged::main(cli.global, a),
Cmd::SeatTest(a) => seat_test::main(cli.global, a),
Cmd::Portal => portal::run_freestanding(cli.global),
Cmd::Randr(a) => randr::main(cli.global, a),
Cmd::Input(a) => input::main(cli.global, a),
Cmd::DamageTracking(a) => damage_tracking::main(cli.global, a),
Cmd::Xwayland(a) => xwayland::main(cli.global, a),
Cmd::ColorManagement(a) => color_management::main(cli.global, a),
Cmd::Clients(a) => clients::main(cli.global, a),
Cmd::Tree(a) => tree::main(cli.global, a),
Cmd::Version => version::main(cli.global),
Cmd::Pid => pid::main(cli.global),
#[cfg(feature = "it")]
Cmd::RunTests => crate::it::run_tests(),
Cmd::Reexec(a) => reexec::main(cli.global, a),
Cmd::ControlCenter => control_center::main(cli.global),
Cmd::Config(a) => config::main(cli.global, a),
Cmd::Trace(a) => trace::main(cli.global, a),
Cmd::Debugfs(a) => debugfs::main(cli.global, a),
}
}