#![allow(clippy::unused_self)]
#[derive(Debug)]
pub struct Api<'rofi> {
display_name: ptr::NonNull<*mut u8>,
display_name_len: usize,
display_name_capacity: usize,
lifetime: PhantomData<&'rofi ()>,
}
unsafe impl Send for Api<'_> {}
unsafe impl Sync for Api<'_> {}
impl Api<'_> {
pub(crate) unsafe fn new(display_name: ptr::NonNull<*mut u8>) -> Self {
Self {
display_name,
display_name_len: 0,
display_name_capacity: 0,
lifetime: PhantomData,
}
}
#[must_use]
pub fn display_name(&self) -> Option<&str> {
let ptr = *unsafe { self.display_name.as_ref() };
if ptr.is_null() {
return None;
}
let slice = unsafe { slice::from_raw_parts(ptr, self.display_name_len) };
Some(unsafe { str::from_utf8_unchecked(slice) })
}
fn change_display_name(&mut self, display_name: Option<String>) -> Option<String> {
let ptr = unsafe { self.display_name.as_mut() };
let old_len = self.display_name_len;
let old_capacity = self.display_name_capacity;
let old_ptr = *ptr;
if let Some(display_name) = &display_name {
self.display_name_len = display_name.len();
self.display_name_capacity = display_name.capacity();
}
*ptr = display_name.map_or_else(ptr::null_mut, String::into_raw);
if old_ptr.is_null() {
None
} else {
Some(unsafe { String::from_raw_parts(old_ptr, old_len, old_capacity) })
}
}
pub fn take_display_name(&mut self) -> Option<String> {
self.change_display_name(None)
}
pub fn replace_display_name(&mut self, display_name: String) -> Option<String> {
self.change_display_name(Some(display_name))
}
pub fn set_display_name<T: Display>(&mut self, display_name: T) {
let mut buf = self.take_display_name().unwrap_or_default();
buf.clear();
write!(buf, "{display_name}").unwrap();
self.replace_display_name(buf);
}
#[must_use]
pub fn supports_image<P: AsRef<Path>>(&self, path: P) -> bool {
let mut path = path.as_ref().as_os_str().as_bytes().to_owned();
path.push(b'\0');
let res = unsafe { ffi::icon_fetcher::file_is_image(path.as_ptr().cast()) };
res != 0
}
#[must_use]
pub fn query_icon(&mut self, name: &str, size: u32) -> IconRequest {
let name = CString::new(name).expect("name contained nul bytes");
self.query_icon_cstr(&name, size)
}
#[must_use]
pub fn query_icon_cstr(&mut self, name: &CStr, size: u32) -> IconRequest {
let uid = unsafe {
ffi::icon_fetcher::query(name.as_ptr(), size.try_into().unwrap_or(c_int::MAX))
};
IconRequest { uid }
}
#[must_use]
pub fn query_icon_wh(&mut self, name: &str, width: u32, height: u32) -> IconRequest {
let name = CString::new(name).expect("name contained nul bytes");
self.query_icon_wh_cstr(&name, width, height)
}
#[must_use]
pub fn query_icon_wh_cstr(&mut self, name: &CStr, width: u32, height: u32) -> IconRequest {
let uid = unsafe {
ffi::icon_fetcher::query_advanced(
name.as_ptr(),
width.try_into().unwrap_or(c_int::MAX),
height.try_into().unwrap_or(c_int::MAX),
)
};
IconRequest { uid }
}
#[allow(clippy::needless_pass_by_value)]
pub fn retrieve_icon(&mut self, request: IconRequest) -> Result<cairo::Surface, IconError> {
let ptr = unsafe { ffi::icon_fetcher::get(request.uid) };
if ptr.is_null() {
return Err(IconError::NotFound);
}
unsafe { cairo::Surface::from_raw_full(ptr) }.map_err(IconError::Surface)
}
}
#[derive(Debug)]
pub struct IconRequest {
uid: u32,
}
impl IconRequest {
#[allow(clippy::missing_errors_doc)]
pub fn wait(self, api: &mut Api<'_>) -> Result<cairo::Surface, IconError> {
api.retrieve_icon(self)
}
}
#[derive(Debug)]
pub enum IconError {
#[non_exhaustive]
NotFound,
#[non_exhaustive]
Surface(cairo::Error),
}
impl Display for IconError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str("failed to retrieve icon")
}
}
impl Error for IconError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::NotFound => Some(&IconNotFound),
Self::Surface(e) => Some(e),
}
}
}
#[derive(Debug)]
struct IconNotFound;
impl Display for IconNotFound {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str("icon not found")
}
}
impl Error for IconNotFound {}
use crate::ffi;
use crate::String;
use std::error::Error;
use std::ffi::CStr;
use std::ffi::CString;
use std::fmt;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Write as _;
use std::marker::PhantomData;
use std::os::raw::c_int;
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use std::ptr;
use std::slice;
use std::str;