use std::io::prelude::*;
use std::process::Command;
use linicon::{lookup_icon, IconType};
use tauri::Manager;
use crate::config;
pub(crate) use crate::html::apply_runtime_style;
fn read_dconf(path: &str) -> Option<String> {
let out = Command::new("dconf").args(["read", path]).output().ok()?;
Some(
String::from_utf8_lossy(&out.stdout)
.replace(['\'', '"', '\n'], ""),
)
}
fn find_svg_icon(name: String) -> Option<String> {
lookup_icon(name).into_iter().find_map(|icon| match icon {
Ok(icon) if icon.icon_type == IconType::SVG => {
let mut data = String::new();
std::fs::File::open(icon.path)
.ok()?
.read_to_string(&mut data)
.ok()?;
Some(data)
}
_ => None,
})
}
fn apply_style_replacements(src: &str) -> String {
let height_px = format!("\"{}px\"", config::titlebar_height());
let width_px = format!("\"{}px\"", config::button_width());
src.replace("\"32px\"", &height_px)
.replace("\"46px\"", &width_px)
.replace(config::DEFAULT_CLOSE_HOVER_BG, &config::close_hover_bg())
.replace(config::DEFAULT_BUTTON_HOVER_BG, &config::button_hover_bg())
}
fn enabled_controls<R: tauri::Runtime>(webview: &tauri::Webview<R>) -> Vec<String> {
let win = webview.app_handle().get_webview_window(webview.label());
let mut out = Vec::with_capacity(3);
if win.as_ref().and_then(|w| w.is_minimizable().ok()).unwrap_or(true) {
out.push("minimize".into());
}
if win.as_ref().and_then(|w| w.is_maximizable().ok()).unwrap_or(true)
&& win.as_ref().and_then(|w| w.is_resizable().ok()).unwrap_or(true)
{
out.push("maximize".into());
}
if win.as_ref().and_then(|w| w.is_closable().ok()).unwrap_or(true) {
out.push("close".into());
}
out
}
fn dconf_button_layout() -> Option<Vec<String>> {
read_dconf("/org/gnome/desktop/wm/preferences/button-layout").map(|raw| {
raw.trim_start_matches("appmenu:")
.split(',')
.map(str::to_string)
.collect()
})
}
pub(crate) fn handle_page_load<R: tauri::Runtime>(webview: &tauri::Webview<R>) {
if !crate::overlay::contains(webview.label()) && !config::auto_titlebar() {
return;
}
let titlebar = apply_style_replacements(include_str!("js/titlebar.js"));
if let Err(e) = webview.eval(&titlebar) {
eprintln!("decor error: {e:?}");
return;
}
let mut platform = apply_style_replacements(include_str!("js/linux.js"));
let mut controls = enabled_controls(webview);
for control in controls.iter().chain(std::iter::once(&"restore".to_string())) {
let icon = find_svg_icon(format!("window-{control}-symbolic"))
.or_else(|| find_svg_icon(format!("window-{control}")));
if let Some(data) = icon {
platform = platform.replace(&format!("@win-{control}"), &data);
}
}
if let Some(layout) = dconf_button_layout() {
controls = layout;
}
let controls_base = apply_style_replacements(include_str!("js/controls.js"));
let platform = platform.replacen(
"[\"minimize\", \"maximize\", \"close\"]",
&format!("{controls:?}"),
1,
);
let _ = webview.eval(&format!(";(() => {{\n{controls_base}\n{platform}\n}})();"));
}