aboutsummaryrefslogtreecommitdiff
path: root/src/utils.rs
blob: b7dee6e2d91340c49dcfd4c7e31909c110acb3fd (plain)
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
use std::fs::File;
use std::io::Read;
use std::time::Duration;

use anyhow::{anyhow, Context};
use smithay::backend::allocator::Fourcc;
use smithay::backend::renderer::element::texture::TextureBuffer;
use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture};
use smithay::reexports::nix::time::{clock_gettime, ClockId};
use smithay::utils::{Logical, Physical, Point, Rectangle, Transform};
use xcursor::parser::parse_xcursor;
use xcursor::CursorTheme;

const CURSOR_SIZE: u32 = 24;
static FALLBACK_CURSOR_DATA: &[u8] = include_bytes!("../resources/cursor.rgba");

pub fn get_monotonic_time() -> Duration {
    Duration::from(clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap())
}

pub fn center(rect: Rectangle<i32, Logical>) -> Point<i32, Logical> {
    rect.loc + rect.size.downscale(2).to_point()
}

fn load_xcursor() -> anyhow::Result<xcursor::parser::Image> {
    let theme = CursorTheme::load("default");
    let path = theme
        .load_icon("default")
        .ok_or_else(|| anyhow!("no default icon"))?;
    let mut file = File::open(path).context("error opening cursor icon file")?;
    let mut buf = vec![];
    file.read_to_end(&mut buf)
        .context("error reading cursor icon file")?;
    let images = parse_xcursor(&buf).context("error parsing cursor icon file")?;

    let nearest_image = images
        .iter()
        .min_by_key(|image| (CURSOR_SIZE as i32 - image.size as i32).abs())
        .unwrap();
    let frame = images
        .iter()
        .find(move |image| {
            image.width == nearest_image.width && image.height == nearest_image.height
        })
        .unwrap();
    Ok(frame.clone())
}

pub fn load_default_cursor(
    renderer: &mut GlesRenderer,
) -> (TextureBuffer<GlesTexture>, Point<i32, Physical>) {
    let frame = match load_xcursor() {
        Ok(frame) => frame,
        Err(err) => {
            warn!("error loading xcursor default cursor: {err:?}");

            xcursor::parser::Image {
                size: 32,
                width: 64,
                height: 64,
                xhot: 1,
                yhot: 1,
                delay: 1,
                pixels_rgba: Vec::from(FALLBACK_CURSOR_DATA),
                pixels_argb: vec![],
            }
        }
    };

    let texture = TextureBuffer::from_memory(
        renderer,
        &frame.pixels_rgba,
        Fourcc::Abgr8888,
        (frame.width as i32, frame.height as i32),
        false,
        1,
        Transform::Normal,
        None,
    )
    .unwrap();
    (texture, (frame.xhot as i32, frame.yhot as i32).into())
}