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
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// MIT/Apache2 License

//! Provides functionality and structures used to interface with the colormap.

use crate::{
    auto::xproto::{AllocColorReply, AllocColorRequest, Colormap},
    display::prelude::*,
    Display, RequestCookie,
};

#[cfg(feature = "async")]
use crate::{
    display::{
        futures::{ExchangeRequestFuture, MapFuture, SendRequestFuture},
        AsyncDisplay,
    },
    util::BoxedFnOnce,
};
#[cfg(feature = "async")]
use alloc::boxed::Box;

/// Convenience function for producing an RGB pixel value for supported monitors.
#[inline]
#[must_use]
pub const fn rgb(r: u8, g: u8, b: u8) -> u32 {
    let r = r as u32;
    let g = g as u32;
    let b = b as u32;
    b + (g << 8) + (r << 16)
}

/// The result of a color allocation call.
#[derive(Debug, Clone, Copy)]
pub enum ColorAllocation {
    /// The desired color was allocated without issue.
    NoChange(u32),
    /// The color was allocated, but it had to be changed to another color.
    Changed {
        pixel: u32,
        red: u16,
        green: u16,
        blue: u16,
    },
}

impl ColorAllocation {
    /// Get the pixel for this result.
    #[inline]
    #[must_use]
    pub fn pixel(&self) -> u32 {
        match self {
            Self::NoChange(pixel) | Self::Changed { pixel, .. } => *pixel,
        }
    }

    /// Convert an alloc color reply to the result.
    #[inline]
    #[must_use]
    pub fn from_alloc_color_reply(acr: AllocColorReply, r: u16, g: u16, b: u16) -> Self {
        if acr.red == r && acr.green == g && acr.blue == b {
            Self::NoChange(acr.pixel)
        } else {
            Self::Changed {
                red: acr.red,
                green: acr.green,
                blue: acr.blue,
                pixel: acr.pixel,
            }
        }
    }
}

impl From<ColorAllocation> for u32 {
    #[inline]
    fn from(ca: ColorAllocation) -> u32 {
        ca.pixel()
    }
}

impl Colormap {
    /// Alloc color request.
    #[inline]
    fn alloc_color_request(self, r: u16, g: u16, b: u16) -> AllocColorRequest {
        AllocColorRequest {
            cmap: self,
            red: r,
            green: g,
            blue: b,
            ..Default::default()
        }
    }

    /// Allocate a new color in the colormap.
    #[inline]
    pub fn alloc_color<Dpy: Display + ?Sized>(
        self,
        dpy: &mut Dpy,
        r: u16,
        g: u16,
        b: u16,
    ) -> crate::Result<RequestCookie<AllocColorRequest>> {
        dpy.send_request(self.alloc_color_request(r, g, b))
    }

    /// Allocate a new color in the colormap, async redox.
    #[cfg(feature = "async")]
    #[inline]
    pub async fn alloc_color_async<Dpy: AsyncDisplay + ?Sized>(
        self,
        dpy: &mut Dpy,
        r: u16,
        g: u16,
        b: u16,
    ) -> SendRequestFuture<'_, Dpy, AllocColorRequest> {
        dpy.send_request_async(self.alloc_color_request(r, g, b))
    }

    /// Immediately allocate a new color in the colormap.
    #[inline]
    pub fn alloc_color_immediate<Dpy: Display + ?Sized>(
        self,
        dpy: &mut Dpy,
        r: u16,
        g: u16,
        b: u16,
    ) -> crate::Result<ColorAllocation> {
        let tok = self.alloc_color(dpy, r, g, b)?;
        Ok(ColorAllocation::from_alloc_color_reply(
            dpy.resolve_request(tok)?,
            r,
            g,
            b,
        ))
    }

    /// Immediately allocate a new color in the colormap, async redox.
    #[cfg(feature = "async")]
    #[inline]
    pub async fn alloc_color_immediate_async<Dpy: AsyncDisplay + ?Sized>(
        self,
        dpy: &mut Dpy,
        r: u16,
        g: u16,
        b: u16,
    ) -> MapFuture<
        ExchangeRequestFuture<'_, Dpy, AllocColorRequest>,
        BoxedFnOnce<AllocColorReply, ColorAllocation>,
    > {
        MapFuture::run(
            dpy.exchange_request_async(self.alloc_color_request(r, g, b)),
            Box::new(move |acr| ColorAllocation::from_alloc_color_reply(acr, r, g, b)),
        )
    }
}