use core::ptr;
use libc::c_char;
use std::os::raw::c_void;
use weechat_sys::{t_gui_bar_item, t_gui_buffer, t_gui_window, t_hashtable, t_weechat_plugin};
use crate::{buffer::Buffer, LossyCString, Weechat};
pub trait BarItemCallback: 'static {
fn callback(&mut self, weechat: &Weechat, buffer: &Buffer) -> String;
}
impl<T: FnMut(&Weechat, &Buffer) -> String + 'static> BarItemCallback for T {
fn callback(&mut self, weechat: &Weechat, buffer: &Buffer) -> String {
self(weechat, buffer)
}
}
struct BarItemCbData {
callback: Box<dyn BarItemCallback>,
weechat_ptr: *mut t_weechat_plugin,
}
pub struct BarItem {
name: String,
ptr: *mut t_gui_bar_item,
weechat: *mut t_weechat_plugin,
_data: Box<BarItemCbData>,
}
impl Drop for BarItem {
fn drop(&mut self) {
let weechat = Weechat::from_ptr(self.weechat);
let bar_item_remove = weechat.get().bar_item_remove.unwrap();
unsafe { bar_item_remove(self.ptr) };
}
}
impl BarItem {
pub fn new(name: &str, callback: impl BarItemCallback) -> Result<BarItem, ()> {
unsafe extern "C" fn c_item_cb(
pointer: *const c_void,
_data: *mut c_void,
_bar_item: *mut t_gui_bar_item,
_window: *mut t_gui_window,
buffer: *mut t_gui_buffer,
_extra_info: *mut t_hashtable,
) -> *mut c_char {
let data: &mut BarItemCbData = { &mut *(pointer as *mut BarItemCbData) };
let weechat = Weechat::from_ptr(data.weechat_ptr);
let buffer = weechat.buffer_from_ptr(buffer);
let cb_trait = &mut data.callback;
let ret = cb_trait.callback(&weechat, &buffer);
libc::strdup(LossyCString::new(ret).as_ptr())
}
Weechat::check_thread();
let weechat = unsafe { Weechat::weechat() };
let data = Box::new(BarItemCbData {
callback: Box::new(callback),
weechat_ptr: weechat.ptr,
});
let data_ref = Box::leak(data);
let bar_item_new = weechat.get().bar_item_new.unwrap();
let bar_item_name = LossyCString::new(name);
let bar_item_ptr = unsafe {
bar_item_new(
weechat.ptr,
bar_item_name.as_ptr(),
Some(c_item_cb),
data_ref as *const _ as *const c_void,
ptr::null_mut(),
)
};
let cb_data = unsafe { Box::from_raw(data_ref) };
if bar_item_ptr.is_null() {
return Err(());
}
Ok(BarItem {
name: name.to_owned(),
ptr: bar_item_ptr,
weechat: weechat.ptr,
_data: cb_data,
})
}
pub fn update(&self) {
Weechat::bar_item_update(&self.name);
}
}