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