🔒 Repository is read-only – file editing is disabled.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
use smithay::{
backend::renderer::{
element::{
solid::{SolidColorBuffer, SolidColorRenderElement},
AsRenderElements, Kind,
},
Renderer,
},
desktop::WindowSurface,
input::Seat,
utils::{Logical, Point, Serial},
wayland::shell::xdg::XdgShellHandler,
};
use std::cell::{RefCell, RefMut};
use crate::{state::Backend, AnvilState};
use super::WindowElement;
pub struct WindowState {
pub is_ssd: bool,
pub header_bar: HeaderBar,
}
#[derive(Debug, Clone)]
pub struct HeaderBar {
pub pointer_loc: Option<Point<f64, Logical>>,
pub width: u32,
pub close_button_hover: bool,
pub maximize_button_hover: bool,
pub background: SolidColorBuffer,
pub close_button: SolidColorBuffer,
pub maximize_button: SolidColorBuffer,
}
const BG_COLOR: [f32; 4] = [0.75f32, 0.9f32, 0.78f32, 1f32];
const MAX_COLOR: [f32; 4] = [1f32, 0.965f32, 0.71f32, 1f32];
const CLOSE_COLOR: [f32; 4] = [1f32, 0.66f32, 0.612f32, 1f32];
const MAX_COLOR_HOVER: [f32; 4] = [0.71f32, 0.624f32, 0f32, 1f32];
const CLOSE_COLOR_HOVER: [f32; 4] = [0.75f32, 0.11f32, 0.016f32, 1f32];
pub const HEADER_BAR_HEIGHT: i32 = 32;
const BUTTON_HEIGHT: u32 = HEADER_BAR_HEIGHT as u32;
const BUTTON_WIDTH: u32 = 32;
impl HeaderBar {
pub fn pointer_enter(&mut self, loc: Point<f64, Logical>) {
self.pointer_loc = Some(loc);
}
pub fn pointer_leave(&mut self) {
self.pointer_loc = None;
}
pub fn clicked<BackendData: Backend>(
&mut self,
seat: &Seat<AnvilState<BackendData>>,
state: &mut AnvilState<BackendData>,
window: &WindowElement,
serial: Serial,
) {
match self.pointer_loc.as_ref() {
Some(loc) if loc.x >= (self.width - BUTTON_WIDTH) as f64 => {
match window.0.underlying_surface() {
WindowSurface::Wayland(w) => w.send_close(),
#[cfg(feature = "xwayland")]
WindowSurface::X11(w) => {
let _ = w.close();
}
};
}
Some(loc) if loc.x >= (self.width - (BUTTON_WIDTH * 2)) as f64 => {
match window.0.underlying_surface() {
WindowSurface::Wayland(w) => state.maximize_request(w.clone()),
#[cfg(feature = "xwayland")]
WindowSurface::X11(w) => {
let surface = w.clone();
state
.handle
.insert_idle(move |data| data.maximize_request_x11(&surface));
}
};
}
Some(_) => {
match window.0.underlying_surface() {
WindowSurface::Wayland(w) => {
let seat = seat.clone();
let toplevel = w.clone();
state
.handle
.insert_idle(move |data| data.move_request_xdg(&toplevel, &seat, serial));
}
#[cfg(feature = "xwayland")]
WindowSurface::X11(w) => {
let window = w.clone();
state
.handle
.insert_idle(move |data| data.move_request_x11(&window));
}
};
}
_ => {}
};
}
pub fn touch_down<BackendData: Backend>(
&mut self,
seat: &Seat<AnvilState<BackendData>>,
state: &mut AnvilState<BackendData>,
window: &WindowElement,
serial: Serial,
) {
match self.pointer_loc.as_ref() {
Some(loc) if loc.x >= (self.width - BUTTON_WIDTH) as f64 => {}
Some(loc) if loc.x >= (self.width - (BUTTON_WIDTH * 2)) as f64 => {}
Some(_) => {
match window.0.underlying_surface() {
WindowSurface::Wayland(w) => {
let seat = seat.clone();
let toplevel = w.clone();
state
.handle
.insert_idle(move |data| data.move_request_xdg(&toplevel, &seat, serial));
}
#[cfg(feature = "xwayland")]
WindowSurface::X11(w) => {
let window = w.clone();
state
.handle
.insert_idle(move |data| data.move_request_x11(&window));
}
};
}
_ => {}
};
}
pub fn touch_up<BackendData: Backend>(
&mut self,
_seat: &Seat<AnvilState<BackendData>>,
state: &mut AnvilState<BackendData>,
window: &WindowElement,
_serial: Serial,
) {
match self.pointer_loc.as_ref() {
Some(loc) if loc.x >= (self.width - BUTTON_WIDTH) as f64 => {
match window.0.underlying_surface() {
WindowSurface::Wayland(w) => w.send_close(),
#[cfg(feature = "xwayland")]
WindowSurface::X11(w) => {
let _ = w.close();
}
};
}
Some(loc) if loc.x >= (self.width - (BUTTON_WIDTH * 2)) as f64 => {
match window.0.underlying_surface() {
WindowSurface::Wayland(w) => state.maximize_request(w.clone()),
#[cfg(feature = "xwayland")]
WindowSurface::X11(w) => {
let surface = w.clone();
state
.handle
.insert_idle(move |data| data.maximize_request_x11(&surface));
}
};
}
_ => {}
};
}
pub fn redraw(&mut self, width: u32) {
if width == 0 {
self.width = 0;
return;
}
self.background
.update((width as i32, HEADER_BAR_HEIGHT), BG_COLOR);
let mut needs_redraw_buttons = false;
if width != self.width {
needs_redraw_buttons = true;
self.width = width;
}
if self
.pointer_loc
.as_ref()
.map(|l| l.x >= (width - BUTTON_WIDTH) as f64)
.unwrap_or(false)
&& (needs_redraw_buttons || !self.close_button_hover)
{
self.close_button
.update((BUTTON_WIDTH as i32, BUTTON_HEIGHT as i32), CLOSE_COLOR_HOVER);
self.close_button_hover = true;
} else if !self
.pointer_loc
.as_ref()
.map(|l| l.x >= (width - BUTTON_WIDTH) as f64)
.unwrap_or(false)
&& (needs_redraw_buttons || self.close_button_hover)
{
self.close_button
.update((BUTTON_WIDTH as i32, BUTTON_HEIGHT as i32), CLOSE_COLOR);
self.close_button_hover = false;
}
if self
.pointer_loc
.as_ref()
.map(|l| l.x >= (width - BUTTON_WIDTH * 2) as f64 && l.x <= (width - BUTTON_WIDTH) as f64)
.unwrap_or(false)
&& (needs_redraw_buttons || !self.maximize_button_hover)
{
self.maximize_button
.update((BUTTON_WIDTH as i32, BUTTON_HEIGHT as i32), MAX_COLOR_HOVER);
self.maximize_button_hover = true;
} else if !self
.pointer_loc
.as_ref()
.map(|l| l.x >= (width - BUTTON_WIDTH * 2) as f64 && l.x <= (width - BUTTON_WIDTH) as f64)
.unwrap_or(false)
&& (needs_redraw_buttons || self.maximize_button_hover)
{
self.maximize_button
.update((BUTTON_WIDTH as i32, BUTTON_HEIGHT as i32), MAX_COLOR);
self.maximize_button_hover = false;
}
}
}
impl<R: Renderer> AsRenderElements<R> for HeaderBar {
type RenderElement = SolidColorRenderElement;
fn render_elements<C: From<Self::RenderElement>>(
&self,
_renderer: &mut R,
location: Point<i32, smithay::utils::Physical>,
scale: smithay::utils::Scale<f64>,
alpha: f32,
) -> Vec<C> {
let header_end_offset: Point<i32, Logical> = Point::from((self.width as i32, 0));
let button_offset: Point<i32, Logical> = Point::from((BUTTON_WIDTH as i32, 0));
vec![
SolidColorRenderElement::from_buffer(
&self.close_button,
location + (header_end_offset - button_offset).to_physical_precise_round(scale),
scale,
alpha,
Kind::Unspecified,
)
.into(),
SolidColorRenderElement::from_buffer(
&self.maximize_button,
location + (header_end_offset - button_offset.upscale(2)).to_physical_precise_round(scale),
scale,
alpha,
Kind::Unspecified,
)
.into(),
SolidColorRenderElement::from_buffer(&self.background, location, scale, alpha, Kind::Unspecified)
.into(),
]
}
}
impl WindowElement {
pub fn decoration_state(&self) -> RefMut<'_, WindowState> {
self.user_data().insert_if_missing(|| {
RefCell::new(WindowState {
is_ssd: false,
header_bar: HeaderBar {
pointer_loc: None,
width: 0,
close_button_hover: false,
maximize_button_hover: false,
background: SolidColorBuffer::default(),
close_button: SolidColorBuffer::default(),
maximize_button: SolidColorBuffer::default(),
},
})
});
self.user_data()
.get::<RefCell<WindowState>>()
.unwrap()
.borrow_mut()
}
pub fn set_ssd(&self, ssd: bool) {
self.decoration_state().is_ssd = ssd;
}
}