Skip to main content

winisland_plugin_api/
lib.rs

1use std::ffi::c_char;
2
3pub type PluginHandle = *mut std::ffi::c_void;
4
5#[cfg(feature = "packager")]
6pub mod packager;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum PluginType {
10    Content = 1,
11    Theme = 2,
12    Shortcut = 3,
13}
14
15impl PluginType {
16    pub fn from_u32(v: u32) -> Option<Self> {
17        match v {
18            1 => Some(Self::Content),
19            2 => Some(Self::Theme),
20            3 => Some(Self::Shortcut),
21            _ => None,
22        }
23    }
24}
25
26#[repr(C)]
27pub struct PluginResultC {
28    pub ok: bool,
29    pub error: [u8; 256],
30}
31
32impl PluginResultC {
33    pub fn ok() -> Self {
34        Self {
35            ok: true,
36            error: [0u8; 256],
37        }
38    }
39
40    pub fn err(msg: &str) -> Self {
41        let mut error = [0u8; 256];
42        let bytes = msg.as_bytes();
43        let len = bytes.len().min(255);
44        error[..len].copy_from_slice(&bytes[..len]);
45        Self { ok: false, error }
46    }
47
48    pub fn into_result(self) -> Result<(), String> {
49        if self.ok {
50            Ok(())
51        } else {
52            let end = self.error.iter().position(|&b| b == 0).unwrap_or(256);
53            Err(String::from_utf8_lossy(&self.error[..end]).into_owned())
54        }
55    }
56}
57
58#[repr(C)]
59pub struct PluginMetadataC {
60    pub id: [u8; 64],
61    pub name: [u8; 128],
62    pub version: [u8; 32],
63    pub author: [u8; 128],
64    pub description: [u8; 256],
65}
66
67#[repr(C)]
68pub struct IslandContentC {
69    pub tag: u32,
70    pub title: [u8; 256],
71    pub artist: [u8; 256],
72    pub cover_url: [u8; 512],
73    pub is_playing: bool,
74    pub message: [u8; 256],
75    pub label: [u8; 128],
76    pub value: [u8; 128],
77}
78
79pub const ISLAND_CONTENT_TAG_MUSIC: u32 = 1;
80pub const ISLAND_CONTENT_TAG_NOTIFICATION: u32 = 2;
81pub const ISLAND_CONTENT_TAG_STATUS: u32 = 3;
82
83#[repr(C)]
84pub struct ThemeColorsC {
85    pub primary: [u8; 4],
86    pub secondary: [u8; 4],
87    pub background: [u8; 4],
88    pub text: [u8; 4],
89    pub border: [u8; 4],
90}
91
92#[repr(C)]
93pub struct AnimationConfigC {
94    pub expand_duration_ms: u32,
95    pub collapse_duration_ms: u32,
96    pub bounce_intensity: f32,
97}
98
99#[repr(C)]
100pub struct ShortcutC {
101    pub id: [u8; 64],
102    pub name: [u8; 128],
103    pub description: [u8; 256],
104    pub icon: [u8; 256],
105    pub hotkey: [u8; 32],
106}
107
108#[repr(C)]
109pub struct PluginVTable {
110    pub on_load: unsafe extern "C" fn(PluginHandle) -> PluginResultC,
111    pub on_unload: unsafe extern "C" fn(PluginHandle) -> PluginResultC,
112    pub destroy: unsafe extern "C" fn(PluginHandle),
113    pub get_content: Option<unsafe extern "C" fn(PluginHandle) -> IslandContentC>,
114    pub on_click: Option<unsafe extern "C" fn(PluginHandle)>,
115    pub on_expanded: Option<unsafe extern "C" fn(PluginHandle, bool)>,
116    pub supports_expand: Option<unsafe extern "C" fn(PluginHandle) -> bool>,
117    pub get_colors: Option<unsafe extern "C" fn(PluginHandle) -> ThemeColorsC>,
118    pub get_animations: Option<unsafe extern "C" fn(PluginHandle) -> AnimationConfigC>,
119    pub get_shortcuts_count: Option<unsafe extern "C" fn(PluginHandle) -> u32>,
120    pub get_shortcut_at: Option<unsafe extern "C" fn(PluginHandle, i: u32, out: *mut ShortcutC)>,
121    pub execute_shortcut:
122        Option<unsafe extern "C" fn(PluginHandle, id: *const c_char) -> PluginResultC>,
123}
124
125#[repr(C)]
126pub struct PluginInstanceC {
127    pub handle: PluginHandle,
128    pub metadata: PluginMetadataC,
129    pub vtable: *const PluginVTable,
130    pub plugin_type: u32,
131}
132
133pub type PluginGetInstanceFn = unsafe extern "C" fn() -> PluginInstanceC;