winisland-plugin-api 0.1.0

C ABI types for WinIsland plugin development, with optional build-time packaging and signing tools
Documentation
use std::ffi::c_char;

pub type PluginHandle = *mut std::ffi::c_void;

#[cfg(feature = "packager")]
pub mod packager;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PluginType {
    Content = 1,
    Theme = 2,
    Shortcut = 3,
}

impl PluginType {
    pub fn from_u32(v: u32) -> Option<Self> {
        match v {
            1 => Some(Self::Content),
            2 => Some(Self::Theme),
            3 => Some(Self::Shortcut),
            _ => None,
        }
    }
}

#[repr(C)]
pub struct PluginResultC {
    pub ok: bool,
    pub error: [u8; 256],
}

impl PluginResultC {
    pub fn ok() -> Self {
        Self {
            ok: true,
            error: [0u8; 256],
        }
    }

    pub fn err(msg: &str) -> Self {
        let mut error = [0u8; 256];
        let bytes = msg.as_bytes();
        let len = bytes.len().min(255);
        error[..len].copy_from_slice(&bytes[..len]);
        Self { ok: false, error }
    }

    pub fn into_result(self) -> Result<(), String> {
        if self.ok {
            Ok(())
        } else {
            let end = self.error.iter().position(|&b| b == 0).unwrap_or(256);
            Err(String::from_utf8_lossy(&self.error[..end]).into_owned())
        }
    }
}

#[repr(C)]
pub struct PluginMetadataC {
    pub id: [u8; 64],
    pub name: [u8; 128],
    pub version: [u8; 32],
    pub author: [u8; 128],
    pub description: [u8; 256],
}

#[repr(C)]
pub struct IslandContentC {
    pub tag: u32,
    pub title: [u8; 256],
    pub artist: [u8; 256],
    pub cover_url: [u8; 512],
    pub is_playing: bool,
    pub message: [u8; 256],
    pub label: [u8; 128],
    pub value: [u8; 128],
}

pub const ISLAND_CONTENT_TAG_MUSIC: u32 = 1;
pub const ISLAND_CONTENT_TAG_NOTIFICATION: u32 = 2;
pub const ISLAND_CONTENT_TAG_STATUS: u32 = 3;

#[repr(C)]
pub struct ThemeColorsC {
    pub primary: [u8; 4],
    pub secondary: [u8; 4],
    pub background: [u8; 4],
    pub text: [u8; 4],
    pub border: [u8; 4],
}

#[repr(C)]
pub struct AnimationConfigC {
    pub expand_duration_ms: u32,
    pub collapse_duration_ms: u32,
    pub bounce_intensity: f32,
}

#[repr(C)]
pub struct ShortcutC {
    pub id: [u8; 64],
    pub name: [u8; 128],
    pub description: [u8; 256],
    pub icon: [u8; 256],
    pub hotkey: [u8; 32],
}

#[repr(C)]
pub struct PluginVTable {
    pub on_load: unsafe extern "C" fn(PluginHandle) -> PluginResultC,
    pub on_unload: unsafe extern "C" fn(PluginHandle) -> PluginResultC,
    pub destroy: unsafe extern "C" fn(PluginHandle),
    pub get_content: Option<unsafe extern "C" fn(PluginHandle) -> IslandContentC>,
    pub on_click: Option<unsafe extern "C" fn(PluginHandle)>,
    pub on_expanded: Option<unsafe extern "C" fn(PluginHandle, bool)>,
    pub supports_expand: Option<unsafe extern "C" fn(PluginHandle) -> bool>,
    pub get_colors: Option<unsafe extern "C" fn(PluginHandle) -> ThemeColorsC>,
    pub get_animations: Option<unsafe extern "C" fn(PluginHandle) -> AnimationConfigC>,
    pub get_shortcuts_count: Option<unsafe extern "C" fn(PluginHandle) -> u32>,
    pub get_shortcut_at: Option<unsafe extern "C" fn(PluginHandle, i: u32, out: *mut ShortcutC)>,
    pub execute_shortcut:
        Option<unsafe extern "C" fn(PluginHandle, id: *const c_char) -> PluginResultC>,
}

#[repr(C)]
pub struct PluginInstanceC {
    pub handle: PluginHandle,
    pub metadata: PluginMetadataC,
    pub vtable: *const PluginVTable,
    pub plugin_type: u32,
}

pub type PluginGetInstanceFn = unsafe extern "C" fn() -> PluginInstanceC;