hexchat_api/
plugin.rs

1use std::ffi::{CString, c_void};
2use crate::{str2cstring, PHEXCHAT};
3use std::ptr;
4use std::cell::RefCell;
5use std::rc::Rc;
6
7// TODO - Currently there's no use for retaining all the data except for the
8//        handle. Consider removing the CString fields.
9#[allow(dead_code)]
10struct PluginData {
11    file_name   : CString,
12    plugin_name : CString,
13    description : CString,
14    version     : CString,
15    handle      : *const c_void,
16    removed     : bool,
17}
18
19/// Represents a created plugin entry. Plugins that embed other language
20/// interpreters and load plugins written in those languages can have Hexchat
21/// look as if the loaded scripts are actual plugins. By creating a `Plugin`
22/// object for such a script, an entry is made in Hexchat's list of loaded
23/// plugins. When one of these scripts is unloaded, the fictitious plugin entry
24/// can be removed from Hexchat by dropping the associated `Plugin` object.
25///
26#[derive(Clone)]
27pub struct Plugin {
28    data: Rc<RefCell<PluginData>>,
29}
30
31impl Plugin {
32    /// Creates a new plugin entry in Hexchat.
33    /// # Arguments
34    /// `file_name`     - The name of the script representing a "plugin".
35    /// `plugin_name`   - The name of the plugin script.
36    /// `description`   - The plugin script's description.
37    /// `version`       - A version string for the plugin script.
38    ///
39    pub fn new(file_name    : &str,
40               plugin_name  : &str,
41               description  : &str,
42               version      : &str)
43        -> Plugin
44    {
45        unsafe {
46            let hc   = &*PHEXCHAT;
47            let null = ptr::null::<c_void>();
48            let file_name   = str2cstring(file_name);
49            let plugin_name = str2cstring(plugin_name);
50            let description = str2cstring(description);
51            let version     = str2cstring(version);
52
53            let handle = (hc.c_plugingui_add)(hc,
54                                              file_name.as_ptr(),
55                                              plugin_name.as_ptr(),
56                                              description.as_ptr(),
57                                              version.as_ptr(),
58                                              null.cast());
59            let pd = PluginData {
60                file_name,
61                plugin_name,
62                description,
63                version,
64                handle      : handle.cast(),
65                removed     : false,
66            };
67            Plugin { data: Rc::new(RefCell::new(pd)) }
68        }
69    }
70    /// Removes the plugin entry for the plugin script. This can be used to
71    /// remove a plugin entry, or simply dropping the `Plugin` object will
72    /// cause removal to happen automatically.
73    ///
74    pub fn remove(&self) {
75        let cell = &*self.data;
76        let data = &mut *cell.borrow_mut();
77        if !data.removed {
78            unsafe {
79                let hc = &*PHEXCHAT;
80                (hc.c_plugingui_remove)(hc, data.handle.cast());
81            }
82            data.removed = true;
83        }
84    }
85}
86
87impl Drop for PluginData {
88    /// Removes the entry in Hexchat's plugins list for the `Plugin`.
89    fn drop(&mut self) {
90        if !self.removed {
91            unsafe {
92                let hc = &*PHEXCHAT;
93                (hc.c_plugingui_remove)(hc, self.handle.cast());
94            }
95        }
96    }
97}