dynisland 0.1.3

A Dynamic Island bar
use dynisland_core::abi::{gdk, gtk, gtk_layer_shell, log};
use gdk::prelude::*;
use gtk::{prelude::*, Window};
use gtk_layer_shell::LayerShell;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(tag = "Alignment")]
pub enum Alignment {
    #[serde(alias = "start")]
    Start,
    #[serde(alias = "center")]
    Center,
    #[serde(alias = "end")]
    End,
}

impl Alignment {
    pub fn map_gtk(&self) -> gtk::Align {
        match self {
            Alignment::Start => gtk::Align::Start,
            Alignment::Center => gtk::Align::Center,
            Alignment::End => gtk::Align::End,
        }
    }
}

#[derive(Serialize, Deserialize, Default, Debug, Clone)]
#[serde(tag = "Layer")]
pub enum Layer {
    #[serde(alias = "background")]
    Background,
    #[serde(alias = "bottom")]
    Bottom,
    #[default]
    #[serde(alias = "top")]
    Top,
    #[serde(alias = "overlay")]
    Overlay,
}

impl Layer {
    pub fn map_gtk(&self) -> gtk_layer_shell::Layer {
        match self {
            Layer::Background => gtk_layer_shell::Layer::Background,
            Layer::Bottom => gtk_layer_shell::Layer::Bottom,
            Layer::Top => gtk_layer_shell::Layer::Top,
            Layer::Overlay => gtk_layer_shell::Layer::Overlay,
        }
    }
}

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(default)]
pub struct WindowPosition {
    pub(crate) layer: Layer,
    pub(crate) h_anchor: Alignment,
    pub(crate) v_anchor: Alignment,
    pub(crate) margin_x: i32,
    pub(crate) margin_y: i32,
    pub(crate) exclusive_zone: i32,
    pub(crate) monitor: String,
    pub(crate) layer_shell: bool,
}

impl Default for WindowPosition {
    fn default() -> Self {
        Self {
            layer: Layer::Top,
            h_anchor: Alignment::Center,
            v_anchor: Alignment::Start,
            margin_x: 0,
            margin_y: 0,
            exclusive_zone: -1,
            monitor: String::from(""),
            layer_shell: true,
        }
    }
}

#[derive(Debug, Deserialize, Clone, Default)]
#[serde(default)]
pub struct DeWindowPosition {
    pub(crate) layer: Option<Layer>,
    pub(crate) h_anchor: Option<Alignment>,
    pub(crate) v_anchor: Option<Alignment>,
    pub(crate) margin_x: Option<i32>,
    pub(crate) margin_y: Option<i32>,
    pub(crate) exclusive_zone: Option<i32>,
    pub(crate) monitor: Option<String>,
    pub(crate) layer_shell: Option<bool>,
}

impl WindowPosition {
    pub fn config_layer_shell_for(&self, window: &Window) {
        window.set_layer(self.layer.map_gtk());
        match self.v_anchor {
            Alignment::Start => {
                window.set_anchor(gtk_layer_shell::Edge::Top, true);
                window.set_anchor(gtk_layer_shell::Edge::Bottom, false);
                window.set_margin(gtk_layer_shell::Edge::Top, self.margin_y);
            }
            Alignment::Center => {
                window.set_anchor(gtk_layer_shell::Edge::Top, false);
                window.set_anchor(gtk_layer_shell::Edge::Bottom, false);
            }
            Alignment::End => {
                window.set_anchor(gtk_layer_shell::Edge::Top, false);
                window.set_anchor(gtk_layer_shell::Edge::Bottom, true);
                window.set_margin(gtk_layer_shell::Edge::Bottom, self.margin_y);
            }
        }
        match self.h_anchor {
            Alignment::Start => {
                window.set_anchor(gtk_layer_shell::Edge::Left, true);
                window.set_anchor(gtk_layer_shell::Edge::Right, false);
                window.set_margin(gtk_layer_shell::Edge::Left, self.margin_x);
            }
            Alignment::Center => {
                window.set_anchor(gtk_layer_shell::Edge::Left, false);
                window.set_anchor(gtk_layer_shell::Edge::Right, false);
            }
            Alignment::End => {
                window.set_anchor(gtk_layer_shell::Edge::Left, false);
                window.set_anchor(gtk_layer_shell::Edge::Right, true);
                window.set_margin(gtk_layer_shell::Edge::Right, self.margin_x);
            }
        }
        let mut monitor = None;
        for mon in gdk::Display::default()
            .unwrap()
            .monitors()
            .iter::<gdk::Monitor>()
        {
            let mon = match mon {
                Ok(monitor) => monitor,
                Err(_) => {
                    continue;
                }
            };
            if mon.connector().unwrap().eq_ignore_ascii_case(&self.monitor) {
                monitor = Some(mon);
                break;
            }
        }
        if let Some(monitor) = monitor {
            window.set_monitor(&monitor);
        }
        window.set_namespace("dynisland");
        window.set_exclusive_zone(self.exclusive_zone);
        window.set_resizable(false);
        window.queue_resize();
    }

    pub fn init_window(&self, window: &Window) {
        if self.layer_shell {
            window.init_layer_shell();
            self.config_layer_shell_for(window.upcast_ref());
            window.connect_destroy(|_| log::debug!("LayerShell window was destroyed"));
        } else {
            window.connect_destroy(|_| std::process::exit(0));
        }
    }
    pub fn reconfigure_window(&self, window: &Window) {
        if self.layer_shell {
            if !window.is_layer_window() {
                window.init_layer_shell();
            }
            self.config_layer_shell_for(window);
        }
    }
}