waydock v0.1: panel, pins, fönstergrupper, menyer, settings-GUI, live-config
Some checks failed
check / check (push) Failing after 52s
Some checks failed
check / check (push) Failing after 52s
M0–M5 ur doc/plan.md: layer-shell-dock per skärm med transparent #222222-ö, pins + körande appar (gruppering, badges, indikatorer), klick/skroll/mittklick, konfigurerbar högerklicksmeny, tomyta-meny, settings-GUI som redigerar JSON-configen live, filewatcher, Wayfire-IPC-stubbar (scale, flytta-till-skärm), CI + release-flöde. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
232
src/main.rs
Normal file
232
src/main.rs
Normal file
@@ -0,0 +1,232 @@
|
||||
// waydock — modern, resurssnål dock för Wayfire.
|
||||
// Se doc/architecture.md för helheten.
|
||||
|
||||
mod config;
|
||||
mod dock;
|
||||
mod icons;
|
||||
mod menu;
|
||||
mod settings;
|
||||
mod style;
|
||||
mod toplevel;
|
||||
mod wayfire_ipc;
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use std::time::Duration;
|
||||
|
||||
use gtk4 as gtk;
|
||||
use gtk4::gdk;
|
||||
use gtk4::glib;
|
||||
use gtk4::prelude::*;
|
||||
use log::{error, info, warn, LevelFilter};
|
||||
|
||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
struct Cli {
|
||||
config: Option<PathBuf>,
|
||||
log: Option<String>,
|
||||
log_file: Option<String>,
|
||||
}
|
||||
|
||||
fn parse_cli() -> Cli {
|
||||
let mut cli = Cli { config: None, log: None, log_file: None };
|
||||
let mut args = std::env::args().skip(1);
|
||||
while let Some(arg) = args.next() {
|
||||
match arg.as_str() {
|
||||
"--config" => cli.config = args.next().map(PathBuf::from),
|
||||
"--log" => cli.log = args.next(),
|
||||
"--log-file" => cli.log_file = args.next(),
|
||||
"--version" | "-V" => {
|
||||
println!("waydock {VERSION}");
|
||||
std::process::exit(0);
|
||||
}
|
||||
"--help" | "-h" => {
|
||||
println!(
|
||||
"waydock {VERSION} — dock för Wayfire\n\n\
|
||||
FLAGGOR:\n \
|
||||
--config <fil> annan configfil (default ~/.config/waydock/config.json)\n \
|
||||
--log <nivå> error|warn|info|debug|trace (även env WAYDOCK_LOG)\n \
|
||||
--log-file <fil> skriv logg till fil\n \
|
||||
--version visa version"
|
||||
);
|
||||
std::process::exit(0);
|
||||
}
|
||||
other => {
|
||||
eprintln!("okänd flagga: {other} (se --help)");
|
||||
std::process::exit(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
cli
|
||||
}
|
||||
|
||||
fn init_logging(cli: &Cli, cfg: &config::Config) {
|
||||
let level_str = cli
|
||||
.log
|
||||
.clone()
|
||||
.or_else(|| std::env::var("WAYDOCK_LOG").ok())
|
||||
.unwrap_or_else(|| cfg.log.level.clone());
|
||||
let level = match level_str.to_lowercase().as_str() {
|
||||
"error" => LevelFilter::Error,
|
||||
"warn" => LevelFilter::Warn,
|
||||
"debug" => LevelFilter::Debug,
|
||||
"trace" => LevelFilter::Trace,
|
||||
_ => LevelFilter::Info,
|
||||
};
|
||||
let log_cfg = simplelog::ConfigBuilder::new()
|
||||
.set_time_format_rfc3339()
|
||||
.build();
|
||||
let mut loggers: Vec<Box<dyn simplelog::SharedLogger>> = vec![simplelog::TermLogger::new(
|
||||
level,
|
||||
log_cfg.clone(),
|
||||
simplelog::TerminalMode::Stderr,
|
||||
simplelog::ColorChoice::Auto,
|
||||
)];
|
||||
let file_path = cli.log_file.clone().or_else(|| cfg.log.file.clone());
|
||||
if let Some(path) = file_path {
|
||||
let expanded = if let Some(rest) = path.strip_prefix("~/") {
|
||||
glib::home_dir().join(rest)
|
||||
} else {
|
||||
PathBuf::from(&path)
|
||||
};
|
||||
match std::fs::File::create(&expanded) {
|
||||
Ok(f) => loggers.push(simplelog::WriteLogger::new(level, log_cfg, f)),
|
||||
Err(e) => eprintln!("kunde inte öppna loggfil {path}: {e}"),
|
||||
}
|
||||
}
|
||||
let _ = simplelog::CombinedLogger::init(loggers);
|
||||
}
|
||||
|
||||
/// Delar av configen som kräver att fönstren byggs om (inte bara CSS).
|
||||
fn layout_signature(cfg: &config::Config) -> String {
|
||||
format!(
|
||||
"{:?}|{}|{}|{:?}|{}|{}|{}|{:?}",
|
||||
cfg.position,
|
||||
cfg.centered,
|
||||
cfg.margin,
|
||||
cfg.layer,
|
||||
cfg.avoid_windows,
|
||||
cfg.appearance.shadow.enabled,
|
||||
cfg.appearance.shadow.blur,
|
||||
cfg.outputs.keys().collect::<Vec<_>>(),
|
||||
)
|
||||
}
|
||||
|
||||
fn main() -> glib::ExitCode {
|
||||
let cli = parse_cli();
|
||||
let cfg_path = cli.config.clone().unwrap_or_else(config::default_path);
|
||||
let initial_cfg = config::load_or_create(&cfg_path);
|
||||
init_logging(&cli, &initial_cfg);
|
||||
info!("waydock {VERSION} — config: {}", cfg_path.display());
|
||||
|
||||
let app = gtk::Application::new(Some("eu.brassepc.waydock"), Default::default());
|
||||
let started = Rc::new(Cell::new(false));
|
||||
|
||||
let cfg_path2 = cfg_path.clone();
|
||||
app.connect_activate(move |app| {
|
||||
if started.get() {
|
||||
info!("waydock kör redan — ignorerar andra instansen");
|
||||
return;
|
||||
}
|
||||
started.set(true);
|
||||
activate(app, cfg_path2.clone());
|
||||
});
|
||||
|
||||
// ge inte GTK våra egna flaggor
|
||||
app.run_with_args::<&str>(&[])
|
||||
}
|
||||
|
||||
fn activate(app: >k::Application, cfg_path: PathBuf) {
|
||||
let cfg: config::SharedConfig = Rc::new(RefCell::new(config::load_or_create(&cfg_path)));
|
||||
|
||||
let ctx = Rc::new(dock::Ctx {
|
||||
cfg: cfg.clone(),
|
||||
cfg_path: cfg_path.clone(),
|
||||
service: RefCell::new(None),
|
||||
docks: RefCell::new(Vec::new()),
|
||||
menu_target: RefCell::new(None),
|
||||
app: app.clone(),
|
||||
on_config_changed: RefCell::new(None),
|
||||
save_generation: Cell::new(0),
|
||||
});
|
||||
|
||||
// CSS + rebuild/refresh-logik
|
||||
let css_provider: Rc<RefCell<Option<gtk::CssProvider>>> = Rc::new(RefCell::new(None));
|
||||
let last_signature = Rc::new(RefCell::new(String::new()));
|
||||
{
|
||||
let ctx2 = ctx.clone();
|
||||
let css_provider = css_provider.clone();
|
||||
let last_signature = last_signature.clone();
|
||||
let apply: Rc<dyn Fn()> = Rc::new(move || {
|
||||
let cfg = ctx2.cfg.borrow();
|
||||
let provider = style::apply(&cfg, css_provider.borrow().as_ref());
|
||||
*css_provider.borrow_mut() = Some(provider);
|
||||
let sig = layout_signature(&cfg);
|
||||
drop(cfg);
|
||||
if *last_signature.borrow() != sig {
|
||||
*last_signature.borrow_mut() = sig;
|
||||
dock::rebuild_all(&ctx2);
|
||||
} else {
|
||||
dock::refresh_items(&ctx2);
|
||||
}
|
||||
});
|
||||
*ctx.on_config_changed.borrow_mut() = Some(apply);
|
||||
}
|
||||
|
||||
// fönsterspårningen
|
||||
{
|
||||
let ctx2 = ctx.clone();
|
||||
let on_update: Rc<dyn Fn()> = Rc::new(move || dock::refresh_items(&ctx2));
|
||||
match toplevel::start(on_update) {
|
||||
Ok(service) => *ctx.service.borrow_mut() = Some(service),
|
||||
Err(e) => {
|
||||
error!("{e} — docken visar bara pins");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !wayfire_ipc::available() {
|
||||
warn!("WAYFIRE_SOCKET saknas — översikt/flytta-till-skärm/dodge avstängda (aktivera ipc-pluginen i wayfire.ini)");
|
||||
}
|
||||
|
||||
// första uppritningen
|
||||
if let Some(cb) = ctx.on_config_changed.borrow().as_ref() {
|
||||
cb();
|
||||
}
|
||||
|
||||
// live-omladdning när configfilen ändras
|
||||
{
|
||||
let ctx2 = ctx.clone();
|
||||
config::watch(
|
||||
&cfg_path,
|
||||
Rc::new(move || {
|
||||
info!("configfilen ändrad — laddar om");
|
||||
let fresh = config::load_or_create(&ctx2.cfg_path);
|
||||
*ctx2.cfg.borrow_mut() = fresh;
|
||||
if let Some(cb) = ctx2.on_config_changed.borrow().as_ref() {
|
||||
cb();
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// skärmar in/ut → bygg om (debouncat, skärmar kommer i klungor)
|
||||
{
|
||||
let ctx2 = ctx.clone();
|
||||
let pending = Rc::new(Cell::new(0u64));
|
||||
let display = gdk::Display::default().expect("ingen display");
|
||||
display.monitors().connect_items_changed(move |_, _, _, _| {
|
||||
let generation = pending.get() + 1;
|
||||
pending.set(generation);
|
||||
let ctx3 = ctx2.clone();
|
||||
let pending2 = pending.clone();
|
||||
glib::timeout_add_local_once(Duration::from_millis(500), move || {
|
||||
if pending2.get() == generation {
|
||||
info!("skärmuppsättningen ändrad — bygger om dockorna");
|
||||
dock::rebuild_all(&ctx3);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user