autocommit 2022-02-01 23:33:59 CET
This commit is contained in:
parent
41c5f8cf89
commit
2dbe3ba732
21 changed files with 814 additions and 86 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -268,6 +268,7 @@ dependencies = [
|
|||
"backtrace",
|
||||
"bitflags",
|
||||
"bstr",
|
||||
"byteorder",
|
||||
"env_logger",
|
||||
"futures",
|
||||
"isnt",
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ rand = "0.8.4"
|
|||
renderdoc = "0.10.1"
|
||||
smallvec = { version = "1.8.0", features = ["const_generics", "const_new", "union"] }
|
||||
backtrace = "0.3.64"
|
||||
byteorder = "1.4.3"
|
||||
|
||||
[build-dependencies]
|
||||
repc = "0.1.1"
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ impl XorgBackend {
|
|||
slf.query_devices(ffi::XCB_INPUT_DEVICE_ALL_MASTER as _)?;
|
||||
slf.handle_events()?;
|
||||
|
||||
state.render_ctx.set(Some(ctx.clone()));
|
||||
state.set_render_ctx(&ctx);
|
||||
|
||||
Ok(slf)
|
||||
}
|
||||
|
|
|
|||
489
src/cursor.rs
Normal file
489
src/cursor.rs
Normal file
|
|
@ -0,0 +1,489 @@
|
|||
use crate::rect::Rect;
|
||||
use crate::render::{RenderContext, Renderer, Texture};
|
||||
use crate::{ErrorFmt, NumCell, RenderError};
|
||||
use ahash::AHashSet;
|
||||
use bstr::{BStr, BString, ByteSlice, ByteVec};
|
||||
use byteorder::{LittleEndian, ReadBytesExt};
|
||||
use isnt::std_1::primitive::IsntSliceExt;
|
||||
use std::cell::Cell;
|
||||
use std::convert::TryInto;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader, Seek, SeekFrom};
|
||||
use std::rc::Rc;
|
||||
use std::{env, io, slice, str};
|
||||
use std::mem::MaybeUninit;
|
||||
use thiserror::Error;
|
||||
use uapi::c;
|
||||
use crate::format::ARGB8888;
|
||||
|
||||
const XCURSOR_MAGIC: u32 = 0x72756358;
|
||||
const XCURSOR_IMAGE_TYPE: u32 = 0xfffd0002;
|
||||
const XCURSOR_PATH_DEFAULT: &[u8] =
|
||||
b"~/.icons:/usr/share/icons:/usr/share/pixmaps:/usr/X11R6/lib/X11/icons";
|
||||
const XCURSOR_PATH: &str = "XCURSOR_PATH";
|
||||
const HOME: &str = "HOME";
|
||||
|
||||
const HEADER_SIZE: u32 = 16;
|
||||
|
||||
pub trait Cursor {
|
||||
fn set_position(&self, x: i32, y: i32);
|
||||
fn render(&self, renderer: &mut Renderer, x: i32, y: i32);
|
||||
fn extents(&self) -> Rect;
|
||||
fn handle_unset(&self) { }
|
||||
fn tick(&self) { }
|
||||
}
|
||||
|
||||
pub struct ServerCursors {
|
||||
pub default: ServerCursorTemplate,
|
||||
pub resize_right: ServerCursorTemplate,
|
||||
pub resize_left: ServerCursorTemplate,
|
||||
pub resize_top: ServerCursorTemplate,
|
||||
pub resize_bottom: ServerCursorTemplate,
|
||||
pub resize_top_bottom: ServerCursorTemplate,
|
||||
pub resize_left_right: ServerCursorTemplate,
|
||||
pub resize_top_left: ServerCursorTemplate,
|
||||
pub resize_top_right: ServerCursorTemplate,
|
||||
pub resize_bottom_left: ServerCursorTemplate,
|
||||
pub resize_bottom_right: ServerCursorTemplate,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum KnownCursor {
|
||||
Default,
|
||||
}
|
||||
|
||||
impl ServerCursors {
|
||||
pub fn load(ctx: &Rc<RenderContext>) -> Result<Self, CursorError> {
|
||||
let paths = find_cursor_paths();
|
||||
log::debug!("Trying to load cursors from paths {:?}", paths);
|
||||
let load = |name: &str| {
|
||||
ServerCursorTemplate::load(name, None, 16, &paths, ctx)
|
||||
};
|
||||
Ok(Self {
|
||||
// default: load("left_ptr")?,
|
||||
default: load("left_ptr_watch")?,
|
||||
resize_right: load("right_side")?,
|
||||
resize_left: load("left_side")?,
|
||||
resize_top: load("top_side")?,
|
||||
resize_bottom: load("bottom_side")?,
|
||||
resize_top_bottom: load("v_double_arrow")?,
|
||||
resize_left_right: load("h_double_arrow")?,
|
||||
resize_top_left: load("top_left_corner")?,
|
||||
resize_top_right: load("top_right_corner")?,
|
||||
resize_bottom_left: load("top_left_corner")?,
|
||||
resize_bottom_right: load("bottom_right_corner")?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ServerCursorTemplate {
|
||||
var: ServerCursorTemplateVariant,
|
||||
}
|
||||
|
||||
enum ServerCursorTemplateVariant {
|
||||
Static(Rc<CursorImage>),
|
||||
Animated(Rc<Vec<CursorImage>>),
|
||||
}
|
||||
|
||||
impl ServerCursorTemplate {
|
||||
fn load(
|
||||
name: &str,
|
||||
theme: Option<&BStr>,
|
||||
size: u32,
|
||||
paths: &[BString],
|
||||
ctx: &Rc<RenderContext>,
|
||||
) -> Result<Self, CursorError> {
|
||||
match open_cursor(name, theme, size, paths) {
|
||||
Ok(c) => {
|
||||
if c.len() == 1 {
|
||||
let c = &c[0];
|
||||
let cursor = CursorImage::from_bytes(ctx, &c.pixels, 0, c.width, c.height, c.xhot, c.yhot)?;
|
||||
Ok(ServerCursorTemplate {
|
||||
var: ServerCursorTemplateVariant::Static(Rc::new(cursor)),
|
||||
})
|
||||
} else {
|
||||
let mut images = vec!();
|
||||
for c in c {
|
||||
let img = CursorImage::from_bytes(ctx, &c.pixels, c.delay as _, c.width, c.height, c.xhot, c.yhot)?;
|
||||
images.push(img);
|
||||
}
|
||||
Ok(ServerCursorTemplate {
|
||||
var: ServerCursorTemplateVariant::Animated(Rc::new(images)),
|
||||
})
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("Could not load cursor {}: {}", name, ErrorFmt(e));
|
||||
let empty: [Cell<u8>; 4] = unsafe { MaybeUninit::zeroed().assume_init() };
|
||||
let cursor = CursorImage::from_bytes(ctx, &empty, 0, 1, 1, 0, 0)?;
|
||||
Ok(ServerCursorTemplate {
|
||||
var: ServerCursorTemplateVariant::Static(Rc::new(cursor)),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn instantiate(&self) -> Rc<dyn Cursor> {
|
||||
match &self.var {
|
||||
ServerCursorTemplateVariant::Static(s) => {
|
||||
Rc::new(StaticCursor {
|
||||
x: Cell::new(0),
|
||||
y: Cell::new(0),
|
||||
extents: Cell::new(s.extents),
|
||||
image: s.clone(),
|
||||
})
|
||||
},
|
||||
ServerCursorTemplateVariant::Animated(a) => {
|
||||
let mut start = c::timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: 0,
|
||||
};
|
||||
uapi::clock_gettime(c::CLOCK_MONOTONIC, &mut start).unwrap();
|
||||
Rc::new(AnimatedCursor {
|
||||
start,
|
||||
next: NumCell::new(a[0].delay_ns),
|
||||
idx: Cell::new(0),
|
||||
images: a.clone(),
|
||||
x: Cell::new(0),
|
||||
y: Cell::new(0),
|
||||
extents: Cell::new(a[0].extents),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CursorImage {
|
||||
extents: Rect,
|
||||
xhot: i32,
|
||||
yhot: i32,
|
||||
delay_ns: u64,
|
||||
tex: Rc<Texture>,
|
||||
}
|
||||
|
||||
impl CursorImage {
|
||||
fn from_bytes(ctx: &Rc<RenderContext>, data: &[Cell<u8>], delay_ms: u64, width: i32, height: i32, xhot: i32, yhot: i32) -> Result<Self, CursorError> {
|
||||
Ok(Self {
|
||||
extents: Rect::new_sized(-xhot, -yhot, width, height).unwrap(),
|
||||
xhot,
|
||||
yhot,
|
||||
delay_ns: delay_ms * 1_000_000,
|
||||
tex: ctx.shmem_texture(data, ARGB8888, width, height, width * 4)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct StaticCursor {
|
||||
x: Cell<i32>,
|
||||
y: Cell<i32>,
|
||||
extents: Cell<Rect>,
|
||||
image: Rc<CursorImage>,
|
||||
}
|
||||
|
||||
impl Cursor for StaticCursor {
|
||||
fn set_position(&self, x: i32, y: i32) {
|
||||
let dx = x - self.x.replace(x);
|
||||
let dy = y - self.y.replace(y);
|
||||
self.extents.set(self.extents.get().move_(dx, dy));
|
||||
}
|
||||
|
||||
fn render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
renderer.render_texture(&self.image.tex, x, y, ARGB8888);
|
||||
}
|
||||
|
||||
fn extents(&self) -> Rect {
|
||||
self.extents.get()
|
||||
}
|
||||
}
|
||||
|
||||
struct AnimatedCursor {
|
||||
start: c::timespec,
|
||||
next: NumCell<u64>,
|
||||
idx: Cell<usize>,
|
||||
images: Rc<Vec<CursorImage>>,
|
||||
x: Cell<i32>,
|
||||
y: Cell<i32>,
|
||||
extents: Cell<Rect>,
|
||||
}
|
||||
|
||||
impl Cursor for AnimatedCursor {
|
||||
fn set_position(&self, x: i32, y: i32) {
|
||||
let dx = x - self.x.replace(x);
|
||||
let dy = y - self.y.replace(y);
|
||||
self.extents.set(self.extents.get().move_(dx, dy));
|
||||
}
|
||||
|
||||
fn render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
let img = &self.images[self.idx.get()];
|
||||
renderer.render_texture(&img.tex, x, y, ARGB8888);
|
||||
}
|
||||
|
||||
fn extents(&self) -> Rect {
|
||||
self.extents.get()
|
||||
}
|
||||
|
||||
fn tick(&self) {
|
||||
let mut now = c::timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: 0,
|
||||
};
|
||||
uapi::clock_gettime(c::CLOCK_MONOTONIC, &mut now).unwrap();
|
||||
let dist = (now.tv_sec.wrapping_sub(self.start.tv_sec)) as i64 * 1_000_000_000
|
||||
+ now.tv_nsec.wrapping_sub(self.start.tv_nsec) as i64;
|
||||
if (dist as u64) < self.next.get() {
|
||||
return;
|
||||
}
|
||||
let idx = (self.idx.get() + 1) % self.images.len();
|
||||
self.idx.set(idx);
|
||||
let image = &self.images[idx];
|
||||
self.extents.set(
|
||||
Rect::new_sized(
|
||||
self.x.get() - image.xhot,
|
||||
self.y.get() - image.yhot,
|
||||
image.extents.width(),
|
||||
image.extents.height(),
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
self.next.fetch_add(image.delay_ns);
|
||||
}
|
||||
}
|
||||
|
||||
fn open_cursor(
|
||||
name: &str,
|
||||
theme: Option<&BStr>,
|
||||
size: u32,
|
||||
paths: &[BString],
|
||||
) -> Result<Vec<XCursorImage>, CursorError> {
|
||||
let name = name.as_bytes().as_bstr();
|
||||
let mut file = None;
|
||||
let mut themes_tested = AHashSet::new();
|
||||
if let Some(theme) = theme {
|
||||
file = open_cursor_file(&mut themes_tested, paths, theme, name);
|
||||
}
|
||||
if file.is_none() {
|
||||
file = open_cursor_file(&mut themes_tested, paths, b"default".as_bstr(), name);
|
||||
}
|
||||
let file = match file {
|
||||
Some(f) => f,
|
||||
_ => return Err(CursorError::NotFound),
|
||||
};
|
||||
let mut file = BufReader::new(file);
|
||||
let images = parser_cursor_file(&mut file, size)?;
|
||||
if images.is_empty() {
|
||||
return Err(CursorError::EmptyXcursorFile);
|
||||
}
|
||||
Ok(images)
|
||||
}
|
||||
|
||||
fn open_cursor_file(
|
||||
themes_tested: &mut AHashSet<BString>,
|
||||
paths: &[BString],
|
||||
theme: &BStr,
|
||||
name: &BStr,
|
||||
) -> Option<File> {
|
||||
if !themes_tested.insert(theme.to_owned()) {
|
||||
return None;
|
||||
}
|
||||
if paths.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let mut parents = None;
|
||||
for cursor_path in paths {
|
||||
let mut theme_dir = cursor_path.to_vec();
|
||||
theme_dir.push(b'/');
|
||||
theme_dir.extend_from_slice(theme.as_bytes());
|
||||
let mut cursor_file = theme_dir.clone();
|
||||
cursor_file.extend_from_slice(b"/cursors/");
|
||||
cursor_file.extend_from_slice(name.as_bytes());
|
||||
if let Ok(f) = File::open(cursor_file.to_os_str().unwrap()) {
|
||||
return Some(f);
|
||||
}
|
||||
if parents.is_none() {
|
||||
let mut index_file = theme_dir.clone();
|
||||
index_file.extend_from_slice(b"/index.theme");
|
||||
parents = find_parent_themes(&index_file);
|
||||
}
|
||||
}
|
||||
if let Some(parents) = parents {
|
||||
for parent in parents {
|
||||
if let Some(file) = open_cursor_file(themes_tested, paths, parent.as_bstr(), name) {
|
||||
return Some(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn find_cursor_paths() -> Vec<BString> {
|
||||
let home = env::var_os(HOME).map(|h| Vec::from_os_string(h).unwrap());
|
||||
let cursor_paths = env::var_os(XCURSOR_PATH);
|
||||
let cursor_paths = cursor_paths
|
||||
.as_ref()
|
||||
.map(|c| <[u8]>::from_os_str(c).unwrap())
|
||||
.unwrap_or(XCURSOR_PATH_DEFAULT);
|
||||
let mut paths = vec![];
|
||||
for path in <[u8]>::split(cursor_paths, |b| *b == b':') {
|
||||
if path.first() == Some(&b'~') {
|
||||
if let Some(home) = home.as_ref() {
|
||||
let mut full_path = home.clone();
|
||||
full_path.extend_from_slice(&path[1..]);
|
||||
paths.push(full_path.into());
|
||||
} else {
|
||||
log::warn!(
|
||||
"`HOME` is not set. Cannot expand {}. Ignoring.",
|
||||
path.as_bstr()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
paths.push(path.as_bstr().to_owned());
|
||||
}
|
||||
}
|
||||
paths
|
||||
}
|
||||
|
||||
fn find_parent_themes(path: &[u8]) -> Option<Vec<BString>> {
|
||||
// NOTE: The files we're reading here are really INI files with a hierarchy. This
|
||||
// algorithm treats it as a flat list and is inherited from libxcursor.
|
||||
let file = match File::open(path.to_os_str().unwrap()) {
|
||||
Ok(f) => f,
|
||||
_ => return None,
|
||||
};
|
||||
let mut buf_reader = BufReader::new(file);
|
||||
let mut buf = vec![];
|
||||
loop {
|
||||
buf.clear();
|
||||
match buf_reader.read_until(b'\n', &mut buf) {
|
||||
Ok(n) if n > 0 => {}
|
||||
_ => return None,
|
||||
}
|
||||
let mut suffix = match buf.strip_prefix(b"Inherits") {
|
||||
Some(s) => s,
|
||||
_ => continue,
|
||||
};
|
||||
while suffix.first() == Some(&b' ') {
|
||||
suffix = &suffix[1..];
|
||||
}
|
||||
if suffix.first() != Some(&b'=') {
|
||||
continue;
|
||||
}
|
||||
suffix = &suffix[1..];
|
||||
let parents = suffix
|
||||
.split(|b| matches!(*b, b' ' | b'\t' | b'\n' | b';' | b','))
|
||||
.filter(|v| v.is_not_empty())
|
||||
.map(|v| v.as_bstr().to_owned())
|
||||
.collect();
|
||||
return Some(parents);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum CursorError {
|
||||
#[error("An IO error occurred: {0}")]
|
||||
Io(#[from] io::Error),
|
||||
#[error("The file is not an Xcursor file")]
|
||||
NotAnXcursorFile,
|
||||
#[error("The Xcursor file contains more than 0x10000 images")]
|
||||
OversizedXcursorFile,
|
||||
#[error("The Xcursor file is empty")]
|
||||
EmptyXcursorFile,
|
||||
#[error("The Xcursor file is corrupt")]
|
||||
CorruptXcursorFile,
|
||||
#[error("The requested cursor could not be found")]
|
||||
NotFound,
|
||||
#[error("Could not import the cursor as a texture")]
|
||||
ImportError(#[from] RenderError),
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
struct XCursorImage {
|
||||
width: i32,
|
||||
height: i32,
|
||||
xhot: i32,
|
||||
yhot: i32,
|
||||
delay: u32,
|
||||
pixels: Vec<Cell<u8>>,
|
||||
}
|
||||
|
||||
impl Debug for XCursorImage {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("XcbCursorImage")
|
||||
.field("width", &self.width)
|
||||
.field("height", &self.height)
|
||||
.field("xhot", &self.xhot)
|
||||
.field("yhot", &self.yhot)
|
||||
.field("delay", &self.delay)
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
fn parser_cursor_file<R: BufRead + Seek>(
|
||||
r: &mut R,
|
||||
target: u32,
|
||||
) -> Result<Vec<XCursorImage>, CursorError> {
|
||||
let [magic, header] = read_u32_n(r)?;
|
||||
if magic != XCURSOR_MAGIC || header < HEADER_SIZE {
|
||||
return Err(CursorError::NotAnXcursorFile);
|
||||
}
|
||||
let [_version, ntoc] = read_u32_n(r)?;
|
||||
r.seek(SeekFrom::Current((HEADER_SIZE - header) as i64))?;
|
||||
if ntoc > 0x10000 {
|
||||
return Err(CursorError::OversizedXcursorFile);
|
||||
}
|
||||
let mut images_positions = vec![];
|
||||
let mut best_fit = i64::MAX;
|
||||
for _ in 0..ntoc {
|
||||
let [type_, size, position] = read_u32_n(r)?;
|
||||
if type_ != XCURSOR_IMAGE_TYPE {
|
||||
continue;
|
||||
}
|
||||
let fit = (size as i64 - target as i64).abs();
|
||||
if fit < best_fit {
|
||||
best_fit = fit;
|
||||
images_positions.clear();
|
||||
}
|
||||
if fit == best_fit {
|
||||
images_positions.push(position);
|
||||
}
|
||||
}
|
||||
let mut images = Vec::with_capacity(images_positions.len());
|
||||
for position in images_positions {
|
||||
r.seek(SeekFrom::Start(position as u64))?;
|
||||
let [_chunk_header, _type_, _size, _version, width, height, xhot, yhot, delay] =
|
||||
read_u32_n(r)?;
|
||||
let [width, height, xhot, yhot] = u32_to_i32([width, height, xhot, yhot])?;
|
||||
let mut image = XCursorImage {
|
||||
width,
|
||||
height,
|
||||
xhot,
|
||||
yhot,
|
||||
delay,
|
||||
pixels: vec![],
|
||||
};
|
||||
let num_bytes = width as usize * height as usize * 4;
|
||||
unsafe {
|
||||
image.pixels.reserve_exact(num_bytes as usize);
|
||||
image.pixels.set_len(num_bytes as usize);
|
||||
r.read_exact(slice::from_raw_parts_mut(image.pixels.as_mut_ptr() as _, num_bytes))?;
|
||||
}
|
||||
images.push(image);
|
||||
}
|
||||
Ok(images)
|
||||
}
|
||||
|
||||
fn read_u32_n<R: BufRead, const N: usize>(r: &mut R) -> Result<[u32; N], io::Error> {
|
||||
let mut res = [0; N];
|
||||
r.read_u32_into::<LittleEndian>(&mut res)?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn u32_to_i32<const N: usize>(n: [u32; N]) -> Result<[i32; N], CursorError> {
|
||||
let mut res = [0; N];
|
||||
for i in 0..N {
|
||||
res[i] = n[i]
|
||||
.try_into()
|
||||
.map_err(|_| CursorError::CorruptXcursorFile)?;
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
|
|
@ -350,6 +350,9 @@ impl WlSeatGlobal {
|
|||
.enter(self, x.apply_fract(new.x), y.apply_fract(new.y));
|
||||
stack.push(new.node);
|
||||
}
|
||||
if let Some(node) = stack.last() {
|
||||
node.pointer_target(self);
|
||||
}
|
||||
}
|
||||
found_tree.clear();
|
||||
}
|
||||
|
|
@ -397,7 +400,7 @@ impl WlSeatGlobal {
|
|||
self.focus_toplevel(n);
|
||||
}
|
||||
|
||||
pub fn enter_popup(self: &Rc<Self>, n: &Rc<XdgPopup>) {
|
||||
pub fn enter_popup(self: &Rc<Self>, _n: &Rc<XdgPopup>) {
|
||||
// self.focus_xdg_surface(&n.xdg);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ use crate::ifs::wl_data_device::{WlDataDevice, WlDataDeviceId};
|
|||
use crate::ifs::wl_seat::wl_keyboard::{WlKeyboard, WlKeyboardId, REPEAT_INFO_SINCE};
|
||||
use crate::ifs::wl_seat::wl_pointer::{WlPointer, WlPointerId};
|
||||
use crate::ifs::wl_seat::wl_touch::WlTouch;
|
||||
use crate::ifs::wl_surface::cursor::CursorSurface;
|
||||
use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel;
|
||||
use crate::object::{Interface, Object, ObjectId};
|
||||
use crate::tree::{FloatNode, FoundNode, Node};
|
||||
|
|
@ -31,6 +30,7 @@ use std::io::Write;
|
|||
use std::rc::Rc;
|
||||
pub use types::*;
|
||||
use uapi::{c, OwnedFd};
|
||||
use crate::cursor::{Cursor, KnownCursor};
|
||||
|
||||
id!(WlSeatId);
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ pub struct WlSeatGlobal {
|
|||
kb_state: RefCell<XkbState>,
|
||||
layout: Rc<OwnedFd>,
|
||||
layout_size: u32,
|
||||
cursor: CloneCell<Option<Rc<CursorSurface>>>,
|
||||
cursor: CloneCell<Option<Rc<dyn Cursor>>>,
|
||||
serial: NumCell<u32>,
|
||||
}
|
||||
|
||||
|
|
@ -121,7 +121,21 @@ impl WlSeatGlobal {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_cursor(&self, cursor: Option<Rc<CursorSurface>>) {
|
||||
pub fn set_known_cursor(&self, cursor: KnownCursor) {
|
||||
let cursors = match self.state.cursors.get() {
|
||||
Some(c) => c,
|
||||
None => {
|
||||
self.set_cursor(None);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let tpl = match cursor {
|
||||
KnownCursor::Default => &cursors.default,
|
||||
};
|
||||
self.set_cursor(Some(tpl.instantiate()));
|
||||
}
|
||||
|
||||
pub fn set_cursor(&self, cursor: Option<Rc<dyn Cursor>>) {
|
||||
if let Some(old) = self.cursor.get() {
|
||||
if let Some(new) = cursor.as_ref() {
|
||||
if Rc::ptr_eq(&old, new) {
|
||||
|
|
@ -130,10 +144,15 @@ impl WlSeatGlobal {
|
|||
}
|
||||
old.handle_unset();
|
||||
}
|
||||
if let Some(cursor) = cursor.as_ref() {
|
||||
log::info!("setting new cursor");
|
||||
let (x, y) = self.pos.get();
|
||||
cursor.set_position(x.round_down(), y.round_down());
|
||||
}
|
||||
self.cursor.set(cursor);
|
||||
}
|
||||
|
||||
pub fn get_cursor(&self) -> Option<Rc<CursorSurface>> {
|
||||
pub fn get_cursor(&self) -> Option<Rc<dyn Cursor>> {
|
||||
self.cursor.get()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use crate::object::{Interface, Object, ObjectId};
|
|||
use crate::utils::buffd::MsgParser;
|
||||
use std::rc::Rc;
|
||||
pub use types::*;
|
||||
use crate::cursor::Cursor;
|
||||
|
||||
const SET_CURSOR: u32 = 0;
|
||||
const RELEASE: u32 = 1;
|
||||
|
|
@ -153,7 +154,7 @@ impl WlPointer {
|
|||
let surface = self.seat.client.get_surface(req.surface)?;
|
||||
let cursor = surface.get_cursor(&self.seat.global)?;
|
||||
cursor.set_hotspot(req.hotspot_x, req.hotspot_y);
|
||||
cursor_opt = Some(cursor);
|
||||
cursor_opt = Some(cursor as Rc<dyn Cursor>);
|
||||
}
|
||||
let pointer_node = match self.seat.global.pointer_stack.borrow().last().cloned() {
|
||||
Some(n) => n,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
use crate::ifs::wl_seat::WlSeatGlobal;
|
||||
use crate::ifs::wl_surface::WlSurface;
|
||||
use crate::rect::Rect;
|
||||
use crate::render::Renderer;
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
use crate::cursor::Cursor;
|
||||
|
||||
pub struct CursorSurface {
|
||||
seat: Rc<WlSeatGlobal>,
|
||||
|
|
@ -38,15 +40,6 @@ impl CursorSurface {
|
|||
);
|
||||
}
|
||||
|
||||
pub fn set_position(&self, x: i32, y: i32) {
|
||||
self.pos.set((x, y));
|
||||
self.update_extents();
|
||||
}
|
||||
|
||||
pub fn handle_unset(&self) {
|
||||
self.surface.cursors.remove(&self.seat.id());
|
||||
}
|
||||
|
||||
pub fn handle_surface_destroy(&self) {
|
||||
self.seat.set_cursor(None);
|
||||
}
|
||||
|
|
@ -71,12 +64,23 @@ impl CursorSurface {
|
|||
self.hotspot.set((hot_x - hotspot_dx, hot_y - hotspot_dy));
|
||||
self.update_extents();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn surface(&self) -> &Rc<WlSurface> {
|
||||
&self.surface
|
||||
impl Cursor for CursorSurface {
|
||||
fn set_position(&self, x: i32, y: i32) {
|
||||
self.pos.set((x, y));
|
||||
self.update_extents();
|
||||
}
|
||||
|
||||
pub fn extents(&self) -> Rect {
|
||||
fn render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
renderer.render_surface(&self.surface, x, y);
|
||||
}
|
||||
|
||||
fn extents(&self) -> Rect {
|
||||
self.extents.get()
|
||||
}
|
||||
|
||||
fn handle_unset(&self) {
|
||||
self.surface.cursors.remove(&self.seat.id());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -206,6 +206,7 @@ impl WlSurface {
|
|||
}
|
||||
self.set_role(SurfaceRole::Cursor)?;
|
||||
let cursor = Rc::new(CursorSurface::new(seat, self));
|
||||
cursor.handle_buffer_change();
|
||||
self.cursors.insert(seat.id(), cursor.clone());
|
||||
Ok(cursor)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use crate::client::{ClientId, DynEventFormatter};
|
|||
use crate::fixed::Fixed;
|
||||
use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal};
|
||||
use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceError, XdgSurfaceExt};
|
||||
use crate::ifs::xdg_positioner::{XdgPositioned, XdgPositioner};
|
||||
use crate::ifs::xdg_positioner::{XdgPositioned, XdgPositioner, CA};
|
||||
use crate::object::{Interface, Object, ObjectId};
|
||||
use crate::rect::Rect;
|
||||
use crate::render::Renderer;
|
||||
|
|
@ -15,6 +15,7 @@ use crate::utils::linkedlist::LinkedNode;
|
|||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
pub use types::*;
|
||||
use crate::cursor::KnownCursor;
|
||||
|
||||
const DESTROY: u32 = 0;
|
||||
const GRAB: u32 = 1;
|
||||
|
|
@ -85,13 +86,94 @@ impl XdgPopup {
|
|||
Box::new(PopupDone { obj: self.clone() })
|
||||
}
|
||||
|
||||
fn update_relative_position(&self, parent: &XdgSurface) -> Result<(), XdgPopupError> {
|
||||
let parent = parent.extents.get();
|
||||
let positioner = self.pos.borrow();
|
||||
if !parent.contains_rect(&positioner.ar) {
|
||||
// return Err(XdgPopupError::AnchorRectOutside);
|
||||
fn update_position(&self, parent: &XdgSurface) -> Result<(), XdgPopupError> {
|
||||
// let parent = parent.extents.get();
|
||||
let positioner = self.pos.borrow_mut();
|
||||
// if !parent.contains_rect(&positioner.ar) {
|
||||
// return Err(XdgPopupError::AnchorRectOutside);
|
||||
// }
|
||||
let parent_abs = parent.absolute_desired_extents.get();
|
||||
let mut rel_pos = positioner.get_position(false, false);
|
||||
let mut abs_pos = rel_pos.move_(parent_abs.x1(), parent_abs.y1());
|
||||
if let Some(ws) = parent.workspace.get() {
|
||||
let output_pos = ws.output.get().position.get();
|
||||
let mut overflow = output_pos.get_overflow(&abs_pos);
|
||||
if !overflow.is_contained() {
|
||||
let mut flip_x = positioner.ca.contains(CA::FLIP_X) && overflow.x_overflow();
|
||||
let mut flip_y = positioner.ca.contains(CA::FLIP_Y) && overflow.y_overflow();
|
||||
if flip_x || flip_y {
|
||||
let mut adj_rel = positioner.get_position(flip_x, flip_y);
|
||||
let mut adj_abs = adj_rel.move_(parent_abs.x1(), parent_abs.y1());
|
||||
let mut adj_overflow = output_pos.get_overflow(&adj_abs);
|
||||
let mut recalculate = false;
|
||||
if flip_x && adj_overflow.x_overflow() {
|
||||
flip_x = false;
|
||||
recalculate = true;
|
||||
}
|
||||
if flip_y && adj_overflow.y_overflow() {
|
||||
flip_y = false;
|
||||
recalculate = true;
|
||||
}
|
||||
if flip_x || flip_y {
|
||||
if recalculate {
|
||||
adj_rel = positioner.get_position(flip_x, flip_y);
|
||||
adj_abs = adj_rel.move_(parent_abs.x1(), parent_abs.y1());
|
||||
adj_overflow = output_pos.get_overflow(&adj_abs);
|
||||
}
|
||||
rel_pos = adj_rel;
|
||||
abs_pos = adj_abs;
|
||||
overflow = adj_overflow;
|
||||
}
|
||||
}
|
||||
let (mut dx, mut dy) = (0, 0);
|
||||
if positioner.ca.contains(CA::SLIDE_X) && overflow.x_overflow() {
|
||||
dx = if overflow.left > 0 || overflow.left + overflow.right > 0 {
|
||||
parent_abs.x1() - abs_pos.x1()
|
||||
} else {
|
||||
parent_abs.x2() - abs_pos.x2()
|
||||
};
|
||||
}
|
||||
if positioner.ca.contains(CA::SLIDE_Y) && overflow.y_overflow() {
|
||||
dy = if overflow.top > 0 || overflow.top + overflow.bottom > 0 {
|
||||
parent_abs.y1() - abs_pos.y1()
|
||||
} else {
|
||||
parent_abs.y2() - abs_pos.y2()
|
||||
};
|
||||
}
|
||||
if dx != 0 || dy != 0 {
|
||||
rel_pos = rel_pos.move_(dx, dy);
|
||||
abs_pos = rel_pos.move_(parent_abs.x1(), parent_abs.y1());
|
||||
overflow = output_pos.get_overflow(&abs_pos);
|
||||
}
|
||||
let (mut dx1, mut dx2, mut dy1, mut dy2) = (0, 0, 0, 0);
|
||||
if positioner.ca.contains(CA::RESIZE_X) {
|
||||
dx1 = overflow.left.max(0);
|
||||
dx2 = -overflow.right.max(0);
|
||||
}
|
||||
if positioner.ca.contains(CA::RESIZE_Y) {
|
||||
dy1 = overflow.top.max(0);
|
||||
dy2 = -overflow.bottom.max(0);
|
||||
}
|
||||
if dx1 > 0 || dx2 < 0 || dy1 > 0 || dy2 < 0 {
|
||||
abs_pos = Rect::new(
|
||||
abs_pos.x1() + dx1,
|
||||
abs_pos.y1() + dy1,
|
||||
abs_pos.x2() + dx2,
|
||||
abs_pos.y2() + dy2,
|
||||
)
|
||||
.unwrap();
|
||||
rel_pos = Rect::new_sized(
|
||||
abs_pos.x1() - parent_abs.x1(),
|
||||
abs_pos.y1() - parent_abs.y1(),
|
||||
abs_pos.width(),
|
||||
abs_pos.height(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
self.relative_position.set(positioner.get_position());
|
||||
self.relative_position.set(rel_pos);
|
||||
self.xdg.absolute_desired_extents.set(abs_pos);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -134,7 +216,7 @@ impl XdgPopup {
|
|||
.get_xdg_positioner(req.positioner)?
|
||||
.value();
|
||||
if let Some(parent) = self.parent.get() {
|
||||
self.update_relative_position(&parent)?;
|
||||
self.update_position(&parent)?;
|
||||
let rel = self.relative_position.get();
|
||||
self.xdg.surface.client.event(self.repositioned(req.token));
|
||||
self.xdg.surface.client.event(self.configure(
|
||||
|
|
@ -144,24 +226,6 @@ impl XdgPopup {
|
|||
rel.height(),
|
||||
));
|
||||
self.xdg.send_configure();
|
||||
let parent = parent.absolute_desired_extents.get();
|
||||
self.xdg
|
||||
.absolute_desired_extents
|
||||
.set(rel.move_(parent.x1(), parent.y1()));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_request_(
|
||||
self: &Rc<Self>,
|
||||
request: u32,
|
||||
parser: MsgParser<'_, '_>,
|
||||
) -> Result<(), XdgPopupError> {
|
||||
match request {
|
||||
DESTROY => self.destroy(parser)?,
|
||||
GRAB => self.grab(parser)?,
|
||||
REPOSITION => self.reposition(parser)?,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -171,7 +235,13 @@ impl XdgPopup {
|
|||
}
|
||||
}
|
||||
|
||||
handle_request!(XdgPopup);
|
||||
handle_request! {
|
||||
XdgPopup, XdgPopupError;
|
||||
|
||||
DESTROY => destroy,
|
||||
GRAB => grab,
|
||||
REPOSITION => reposition,
|
||||
}
|
||||
|
||||
impl Object for XdgPopup {
|
||||
fn id(&self) -> ObjectId {
|
||||
|
|
@ -183,7 +253,11 @@ impl Object for XdgPopup {
|
|||
}
|
||||
|
||||
fn num_requests(&self) -> u32 {
|
||||
REPOSITION + 1
|
||||
let last_req = match self.xdg.base.version {
|
||||
0..=2 => GRAB,
|
||||
_ => REPOSITION,
|
||||
};
|
||||
last_req + 1
|
||||
}
|
||||
|
||||
fn break_loops(&self) {
|
||||
|
|
@ -228,6 +302,10 @@ impl Node for XdgPopup {
|
|||
seat.enter_popup(&self);
|
||||
}
|
||||
|
||||
fn pointer_target(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
seat.set_known_cursor(KnownCursor::Default);
|
||||
}
|
||||
|
||||
fn render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
renderer.render_xdg_surface(&self.xdg, x, y)
|
||||
}
|
||||
|
|
@ -244,7 +322,7 @@ impl Node for XdgPopup {
|
|||
impl XdgSurfaceExt for XdgPopup {
|
||||
fn initial_configure(self: Rc<Self>) -> Result<(), XdgSurfaceError> {
|
||||
if let Some(parent) = self.parent.get() {
|
||||
self.update_relative_position(&parent)?;
|
||||
self.update_position(&parent)?;
|
||||
let rel = self.relative_position.get();
|
||||
self.xdg.surface.client.event(self.configure(
|
||||
rel.x1(),
|
||||
|
|
@ -252,10 +330,6 @@ impl XdgSurfaceExt for XdgPopup {
|
|||
rel.width(),
|
||||
rel.height(),
|
||||
));
|
||||
let parent = parent.absolute_desired_extents.get();
|
||||
self.xdg
|
||||
.absolute_desired_extents
|
||||
.set(rel.move_(parent.x1(), parent.y1()));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ use std::cell::{Cell, RefCell};
|
|||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
pub use types::*;
|
||||
use crate::cursor::KnownCursor;
|
||||
|
||||
const DESTROY: u32 = 0;
|
||||
const SET_PARENT: u32 = 1;
|
||||
|
|
@ -395,6 +396,10 @@ impl Node for XdgToplevel {
|
|||
seat.enter_toplevel(&self);
|
||||
}
|
||||
|
||||
fn pointer_target(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
seat.set_known_cursor(KnownCursor::Default);
|
||||
}
|
||||
|
||||
fn render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
renderer.render_xdg_surface(&self.xdg, x, y)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ const BOTTOM_RIGHT: u32 = 8;
|
|||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Default)]
|
||||
pub struct Square: u32 {
|
||||
pub struct Edge: u32 {
|
||||
const TOP = 1 << 0;
|
||||
const BOTTOM = 1 << 1;
|
||||
const LEFT = 1 << 2;
|
||||
|
|
@ -43,18 +43,18 @@ bitflags::bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
impl Square {
|
||||
impl Edge {
|
||||
fn from_enum(e: u32) -> Option<Self> {
|
||||
let s = match e {
|
||||
NONE => Square::empty(),
|
||||
TOP => Square::TOP,
|
||||
BOTTOM => Square::BOTTOM,
|
||||
LEFT => Square::LEFT,
|
||||
RIGHT => Square::RIGHT,
|
||||
TOP_LEFT => Square::TOP | Square::LEFT,
|
||||
BOTTOM_LEFT => Square::BOTTOM | Square::LEFT,
|
||||
TOP_RIGHT => Square::TOP | Square::RIGHT,
|
||||
BOTTOM_RIGHT => Square::BOTTOM | Square::RIGHT,
|
||||
NONE => Edge::empty(),
|
||||
TOP => Edge::TOP,
|
||||
BOTTOM => Edge::BOTTOM,
|
||||
LEFT => Edge::LEFT,
|
||||
RIGHT => Edge::RIGHT,
|
||||
TOP_LEFT => Edge::TOP | Edge::LEFT,
|
||||
BOTTOM_LEFT => Edge::BOTTOM | Edge::LEFT,
|
||||
TOP_RIGHT => Edge::TOP | Edge::RIGHT,
|
||||
BOTTOM_RIGHT => Edge::BOTTOM | Edge::RIGHT,
|
||||
_ => return None,
|
||||
};
|
||||
Some(s)
|
||||
|
|
@ -88,8 +88,8 @@ pub struct XdgPositioned {
|
|||
pub size_width: i32,
|
||||
pub size_height: i32,
|
||||
pub ar: Rect,
|
||||
pub anchor: Square,
|
||||
pub gravity: Square,
|
||||
pub anchor: Edge,
|
||||
pub gravity: Edge,
|
||||
pub ca: CA,
|
||||
pub off_x: i32,
|
||||
pub off_y: i32,
|
||||
|
|
@ -104,35 +104,46 @@ impl XdgPositioned {
|
|||
self.size_height != 0 && self.size_width != 0
|
||||
}
|
||||
|
||||
pub fn get_position(&self) -> Rect {
|
||||
pub fn get_position(&self, flip_x: bool, flip_y: bool) -> Rect {
|
||||
let mut anchor = self.anchor;
|
||||
let mut gravity = self.gravity;
|
||||
if flip_x {
|
||||
anchor ^= Edge::LEFT | Edge::RIGHT;
|
||||
gravity ^= Edge::LEFT | Edge::RIGHT;
|
||||
}
|
||||
if flip_y {
|
||||
anchor ^= Edge::TOP | Edge::BOTTOM;
|
||||
gravity ^= Edge::TOP | Edge::BOTTOM;
|
||||
}
|
||||
|
||||
let mut x1 = self.off_x;
|
||||
let mut y1 = self.off_x;
|
||||
|
||||
if self.anchor.contains(Square::LEFT) {
|
||||
if anchor.contains(Edge::LEFT) {
|
||||
x1 += self.ar.x1();
|
||||
} else if self.anchor.contains(Square::RIGHT) {
|
||||
} else if anchor.contains(Edge::RIGHT) {
|
||||
x1 += self.ar.x2();
|
||||
} else {
|
||||
x1 += self.ar.x1() + self.ar.width() / 2;
|
||||
}
|
||||
|
||||
if self.anchor.contains(Square::TOP) {
|
||||
if anchor.contains(Edge::TOP) {
|
||||
y1 += self.ar.y1();
|
||||
} else if self.anchor.contains(Square::BOTTOM) {
|
||||
} else if anchor.contains(Edge::BOTTOM) {
|
||||
y1 += self.ar.y2();
|
||||
} else {
|
||||
y1 += self.ar.y1() + self.ar.height() / 2;
|
||||
}
|
||||
|
||||
if self.gravity.contains(Square::LEFT) {
|
||||
if gravity.contains(Edge::LEFT) {
|
||||
x1 -= self.size_width;
|
||||
} else if !self.gravity.contains(Square::RIGHT) {
|
||||
} else if !gravity.contains(Edge::RIGHT) {
|
||||
x1 -= self.size_width / 2;
|
||||
}
|
||||
|
||||
if self.gravity.contains(Square::TOP) {
|
||||
if gravity.contains(Edge::TOP) {
|
||||
y1 -= self.size_height;
|
||||
} else if !self.gravity.contains(Square::BOTTOM) {
|
||||
} else if !gravity.contains(Edge::BOTTOM) {
|
||||
y1 -= self.size_height / 2;
|
||||
}
|
||||
|
||||
|
|
@ -193,7 +204,7 @@ impl XdgPositioner {
|
|||
|
||||
fn set_anchor(&self, parser: MsgParser<'_, '_>) -> Result<(), SetAnchorError> {
|
||||
let req: SetAnchor = self.client.parse(self, parser)?;
|
||||
let anchor = match Square::from_enum(req.anchor) {
|
||||
let anchor = match Edge::from_enum(req.anchor) {
|
||||
Some(a) => a,
|
||||
_ => return Err(SetAnchorError::UnknownAnchor(req.anchor)),
|
||||
};
|
||||
|
|
@ -203,7 +214,7 @@ impl XdgPositioner {
|
|||
|
||||
fn set_gravity(&self, parser: MsgParser<'_, '_>) -> Result<(), SetGravityError> {
|
||||
let req: SetGravity = self.client.parse(self, parser)?;
|
||||
let gravity = match Square::from_enum(req.gravity) {
|
||||
let gravity = match Edge::from_enum(req.gravity) {
|
||||
Some(a) => a,
|
||||
_ => return Err(SetGravityError::UnknownGravity(req.gravity)),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,6 +24,31 @@ macro_rules! handle_request {
|
|||
}
|
||||
}
|
||||
};
|
||||
($oname:ty, $ename:ty; $($code:ident => $f:ident,)*) => {
|
||||
impl crate::object::ObjectHandleRequest for $oname {
|
||||
fn handle_request(
|
||||
self: std::rc::Rc<Self>,
|
||||
request: u32,
|
||||
parser: crate::utils::buffd::MsgParser<'_, '_>,
|
||||
) -> Result<(), crate::client::ClientError> {
|
||||
fn handle_request(
|
||||
slf: std::rc::Rc<$oname>,
|
||||
request: u32,
|
||||
parser: crate::utils::buffd::MsgParser<'_, '_>,
|
||||
) -> Result<(), $ename> {
|
||||
match request {
|
||||
$(
|
||||
$code => slf.$f(parser)?,
|
||||
)*
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
handle_request(self, request, parser)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! bind {
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ mod backend;
|
|||
mod backends;
|
||||
mod client;
|
||||
mod clientmem;
|
||||
mod cursor;
|
||||
mod drm;
|
||||
mod event_loop;
|
||||
mod fixed;
|
||||
|
|
@ -116,6 +117,7 @@ fn main_() -> Result<(), MainError> {
|
|||
eng: engine.clone(),
|
||||
el: el.clone(),
|
||||
render_ctx: Default::default(),
|
||||
cursors: Default::default(),
|
||||
wheel,
|
||||
clients: Clients::new(),
|
||||
next_name: NumCell::new(1),
|
||||
|
|
|
|||
48
src/rect.rs
48
src/rect.rs
|
|
@ -1,4 +1,6 @@
|
|||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
|
||||
use std::fmt::{Debug, Formatter};
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Default)]
|
||||
pub struct Rect {
|
||||
x1: i32,
|
||||
y1: i32,
|
||||
|
|
@ -6,6 +8,41 @@ pub struct Rect {
|
|||
y2: i32,
|
||||
}
|
||||
|
||||
impl Debug for Rect {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Rect")
|
||||
.field("x1", &self.x1)
|
||||
.field("y1", &self.y1)
|
||||
.field("x2", &self.x2)
|
||||
.field("y2", &self.y2)
|
||||
.field("width", &(self.x2 - self.x1))
|
||||
.field("height", &(self.y2 - self.y1))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
|
||||
pub struct RectOverflow {
|
||||
pub left: i32,
|
||||
pub right: i32,
|
||||
pub top: i32,
|
||||
pub bottom: i32,
|
||||
}
|
||||
|
||||
impl RectOverflow {
|
||||
pub fn is_contained(&self) -> bool {
|
||||
self.left <= 0 && self.right <= 0 && self.top <= 0 && self.bottom <= 0
|
||||
}
|
||||
|
||||
pub fn x_overflow(&self) -> bool {
|
||||
self.left > 0 || self.right > 0
|
||||
}
|
||||
|
||||
pub fn y_overflow(&self) -> bool {
|
||||
self.top > 0 || self.bottom > 0
|
||||
}
|
||||
}
|
||||
|
||||
impl Rect {
|
||||
pub fn new_empty(x: i32, y: i32) -> Self {
|
||||
Self {
|
||||
|
|
@ -64,6 +101,15 @@ impl Rect {
|
|||
self.x1 <= rect.x1 && self.y1 <= rect.x1 && rect.x2 <= self.x2 && rect.y2 <= self.y2
|
||||
}
|
||||
|
||||
pub fn get_overflow(&self, child: &Self) -> RectOverflow {
|
||||
RectOverflow {
|
||||
left: self.x1 - child.x1,
|
||||
right: child.x2 - self.x2,
|
||||
top: self.y1 - child.y1,
|
||||
bottom: child.y2 - self.y2,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.x1 == self.x2 || self.y1 == self.y2
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,10 +39,11 @@ impl Framebuffer {
|
|||
let seats = state.globals.lock_seats();
|
||||
for seat in seats.values() {
|
||||
if let Some(cursor) = seat.get_cursor() {
|
||||
cursor.tick();
|
||||
let extents = cursor.extents();
|
||||
if extents.intersects(&rect) {
|
||||
let (x, y) = rect.translate(extents.x1(), extents.y1());
|
||||
renderer.render_surface(cursor.surface(), x, y);
|
||||
cursor.render(&mut renderer, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ use crate::tree::{
|
|||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use std::slice;
|
||||
use crate::format::Format;
|
||||
use crate::render::Texture;
|
||||
|
||||
const NON_COLOR: (f32, f32, f32) = (0.2, 0.2, 0.2);
|
||||
const CHILD_COLOR: (f32, f32, f32) = (0.8, 0.8, 0.8);
|
||||
|
|
@ -218,10 +220,12 @@ impl Renderer<'_> {
|
|||
}
|
||||
|
||||
pub fn render_buffer(&mut self, buffer: &WlBuffer, x: i32, y: i32) {
|
||||
let texture = match buffer.texture.get() {
|
||||
Some(t) => t,
|
||||
_ => return,
|
||||
};
|
||||
if let Some(tex) = buffer.texture.get() {
|
||||
self.render_texture(&tex, x, y, buffer.format);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_texture(&mut self, texture: &Texture, x: i32, y: i32, format: &Format) {
|
||||
assert!(Rc::ptr_eq(&self.ctx.ctx, &texture.ctx.ctx));
|
||||
unsafe {
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
|
@ -229,7 +233,7 @@ impl Renderer<'_> {
|
|||
glBindTexture(GL_TEXTURE_2D, texture.gl.tex);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
let prog = match buffer.format.has_alpha {
|
||||
let prog = match format.has_alpha {
|
||||
true => {
|
||||
glEnable(GL_BLEND);
|
||||
&self.ctx.tex_alpha_prog
|
||||
|
|
|
|||
16
src/state.rs
16
src/state.rs
|
|
@ -14,15 +14,17 @@ use crate::utils::copyhashmap::CopyHashMap;
|
|||
use crate::utils::linkedlist::LinkedList;
|
||||
use crate::utils::numcell::NumCell;
|
||||
use crate::utils::queue::AsyncQueue;
|
||||
use crate::Wheel;
|
||||
use crate::{ErrorFmt, Wheel};
|
||||
use ahash::AHashMap;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
use crate::cursor::ServerCursors;
|
||||
|
||||
pub struct State {
|
||||
pub eng: Rc<AsyncEngine>,
|
||||
pub el: Rc<EventLoop>,
|
||||
pub render_ctx: CloneCell<Option<Rc<RenderContext>>>,
|
||||
pub cursors: CloneCell<Option<Rc<ServerCursors>>>,
|
||||
pub wheel: Rc<Wheel>,
|
||||
pub clients: Clients,
|
||||
pub next_name: NumCell<u32>,
|
||||
|
|
@ -47,6 +49,18 @@ pub struct SeatData {
|
|||
}
|
||||
|
||||
impl State {
|
||||
pub fn set_render_ctx(&self, ctx: &Rc<RenderContext>) {
|
||||
let cursors = match ServerCursors::load(ctx) {
|
||||
Ok(c) => Some(Rc::new(c)),
|
||||
Err(e) => {
|
||||
log::error!("Could not load the cursors: {}", ErrorFmt(e));
|
||||
None
|
||||
}
|
||||
};
|
||||
self.cursors.set(cursors);
|
||||
self.render_ctx.set(Some(ctx.clone()));
|
||||
}
|
||||
|
||||
pub fn add_global<T>(&self, global: &Rc<T>)
|
||||
where
|
||||
Globals: AddGlobal<T>,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::ifs::wl_seat::NodeSeatState;
|
||||
use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal};
|
||||
use crate::rect::Rect;
|
||||
use crate::render::Renderer;
|
||||
use crate::tree::{FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode};
|
||||
|
|
@ -8,6 +8,7 @@ use crate::{NumCell, State};
|
|||
use ahash::AHashMap;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
use crate::cursor::KnownCursor;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
|
|
@ -354,6 +355,10 @@ impl Node for ContainerNode {
|
|||
}
|
||||
}
|
||||
|
||||
fn pointer_target(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
seat.set_known_cursor(KnownCursor::Default);
|
||||
}
|
||||
|
||||
fn render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
renderer.render_container(self, x, y);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use std::fmt::Display;
|
|||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
pub use workspace::*;
|
||||
use crate::cursor::KnownCursor;
|
||||
|
||||
mod container;
|
||||
mod workspace;
|
||||
|
|
@ -126,6 +127,10 @@ pub trait Node {
|
|||
let _ = y;
|
||||
}
|
||||
|
||||
fn pointer_target(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
let _ = seat;
|
||||
}
|
||||
|
||||
fn motion(&self, seat: &WlSeatGlobal, x: Fixed, y: Fixed) {
|
||||
let _ = seat;
|
||||
let _ = x;
|
||||
|
|
@ -249,6 +254,10 @@ impl Node for DisplayNode {
|
|||
}
|
||||
FindTreeResult::AcceptsInput
|
||||
}
|
||||
|
||||
fn pointer_target(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
seat.set_known_cursor(KnownCursor::Default);
|
||||
}
|
||||
}
|
||||
|
||||
tree_id!(OutputNodeId);
|
||||
|
|
@ -298,6 +307,10 @@ impl Node for OutputNode {
|
|||
self.workspace.set(None);
|
||||
}
|
||||
|
||||
fn pointer_target(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
seat.set_known_cursor(KnownCursor::Default);
|
||||
}
|
||||
|
||||
fn render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
renderer.render_output(self, x, y);
|
||||
}
|
||||
|
|
@ -376,6 +389,10 @@ impl Node for FloatNode {
|
|||
.set(Rect::new_sized(pos.x1(), pos.x2(), width, height).unwrap());
|
||||
}
|
||||
|
||||
fn pointer_target(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
seat.set_known_cursor(KnownCursor::Default);
|
||||
}
|
||||
|
||||
fn render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
renderer.render_floating(self, x, y)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::ifs::wl_seat::NodeSeatState;
|
||||
use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal};
|
||||
use crate::rect::Rect;
|
||||
use crate::render::Renderer;
|
||||
use crate::tree::container::ContainerNode;
|
||||
|
|
@ -6,6 +6,7 @@ use crate::tree::{AbsoluteNode, FindTreeResult, FoundNode, Node, NodeId, OutputN
|
|||
use crate::utils::clonecell::CloneCell;
|
||||
use crate::utils::linkedlist::LinkedList;
|
||||
use std::rc::Rc;
|
||||
use crate::cursor::KnownCursor;
|
||||
|
||||
tree_id!(WorkspaceNodeId);
|
||||
|
||||
|
|
@ -61,6 +62,10 @@ impl Node for WorkspaceNode {
|
|||
self.container.set(None);
|
||||
}
|
||||
|
||||
fn pointer_target(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
seat.set_known_cursor(KnownCursor::Default);
|
||||
}
|
||||
|
||||
fn render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
||||
renderer.render_workspace(self, x, y);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue