autocommit 2022-03-26 22:58:30 CET
This commit is contained in:
parent
3b1b843821
commit
707ff6066c
28 changed files with 2307 additions and 707 deletions
|
|
@ -141,7 +141,12 @@ impl<'a> Parser<'a> {
|
||||||
let (_, body) = self.expect_tree(TreeDelim::Brace)?;
|
let (_, body) = self.expect_tree(TreeDelim::Brace)?;
|
||||||
let mut parser = Parser::new(body);
|
let mut parser = Parser::new(body);
|
||||||
let data = parser.parse_struct_body(name)?;
|
let data = parser.parse_struct_body(name)?;
|
||||||
Ok(Event { opcode, xge, data })
|
Ok(Event {
|
||||||
|
opcode,
|
||||||
|
xge,
|
||||||
|
data,
|
||||||
|
ext_idx: self.ext_idx,
|
||||||
|
})
|
||||||
})();
|
})();
|
||||||
res.with_context(|| format!("While parsing event starting at line {}", line))
|
res.with_context(|| format!("While parsing event starting at line {}", line))
|
||||||
}
|
}
|
||||||
|
|
@ -779,6 +784,7 @@ struct Event {
|
||||||
opcode: u32,
|
opcode: u32,
|
||||||
xge: bool,
|
xge: bool,
|
||||||
data: Struct,
|
data: Struct,
|
||||||
|
ext_idx: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -941,6 +947,7 @@ enum StructUsecase<'a> {
|
||||||
EventCopy {
|
EventCopy {
|
||||||
copy: &'a EventCopy,
|
copy: &'a EventCopy,
|
||||||
original: &'a Struct,
|
original: &'a Struct,
|
||||||
|
xge: bool,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -950,6 +957,7 @@ fn format_xevent<F: Write>(
|
||||||
s: &Struct,
|
s: &Struct,
|
||||||
opcode: u32,
|
opcode: u32,
|
||||||
protocols: &Protocols,
|
protocols: &Protocols,
|
||||||
|
ext: Option<usize>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let lt_a = if struct_needs_lt(s, protocols)? {
|
let lt_a = if struct_needs_lt(s, protocols)? {
|
||||||
"<'a>"
|
"<'a>"
|
||||||
|
|
@ -958,6 +966,7 @@ fn format_xevent<F: Write>(
|
||||||
};
|
};
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
writeln!(f, "impl<'a> XEvent<'a> for {}{lt_a} {{", name)?;
|
writeln!(f, "impl<'a> XEvent<'a> for {}{lt_a} {{", name)?;
|
||||||
|
writeln!(f, " const EXTENSION: Option<usize> = {:?};", ext)?;
|
||||||
writeln!(f, " const OPCODE: u16 = {:?};", opcode)?;
|
writeln!(f, " const OPCODE: u16 = {:?};", opcode)?;
|
||||||
writeln!(f, "}}")?;
|
writeln!(f, "}}")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -965,7 +974,14 @@ fn format_xevent<F: Write>(
|
||||||
|
|
||||||
fn format_event<F: Write>(f: &mut F, s: &Event, protocols: &Protocols) -> Result<()> {
|
fn format_event<F: Write>(f: &mut F, s: &Event, protocols: &Protocols) -> Result<()> {
|
||||||
format_struct(f, &s.data, protocols, &StructUsecase::Event { xge: s.xge })?;
|
format_struct(f, &s.data, protocols, &StructUsecase::Event { xge: s.xge })?;
|
||||||
format_xevent(f, s.data.name.as_bstr(), &s.data, s.opcode, protocols)
|
format_xevent(
|
||||||
|
f,
|
||||||
|
s.data.name.as_bstr(),
|
||||||
|
&s.data,
|
||||||
|
s.opcode,
|
||||||
|
protocols,
|
||||||
|
s.ext_idx,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_eventcopy<F: Write>(f: &mut F, s: &EventCopy, protocols: &Protocols) -> Result<()> {
|
fn format_eventcopy<F: Write>(f: &mut F, s: &EventCopy, protocols: &Protocols) -> Result<()> {
|
||||||
|
|
@ -980,9 +996,17 @@ fn format_eventcopy<F: Write>(f: &mut F, s: &EventCopy, protocols: &Protocols) -
|
||||||
&StructUsecase::EventCopy {
|
&StructUsecase::EventCopy {
|
||||||
copy: s,
|
copy: s,
|
||||||
original: &original.data,
|
original: &original.data,
|
||||||
|
xge: original.xge,
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
format_xevent(f, s.name.as_bstr(), &original.data, s.opcode, protocols)
|
format_xevent(
|
||||||
|
f,
|
||||||
|
s.name.as_bstr(),
|
||||||
|
&original.data,
|
||||||
|
s.opcode,
|
||||||
|
protocols,
|
||||||
|
original.ext_idx,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_request<F: Write>(f: &mut F, s: &Request, protocols: &Protocols) -> Result<()> {
|
fn format_request<F: Write>(f: &mut F, s: &Request, protocols: &Protocols) -> Result<()> {
|
||||||
|
|
@ -1276,7 +1300,7 @@ fn format_struct<F: Write>(
|
||||||
writeln!(f, "#[derive(Debug, Clone)]")?;
|
writeln!(f, "#[derive(Debug, Clone)]")?;
|
||||||
writeln!(f, "pub struct {}{lt_a} {{", struct_name)?;
|
writeln!(f, "pub struct {}{lt_a} {{", struct_name)?;
|
||||||
if let StructUsecase::EventCopy { original, .. } = usecase {
|
if let StructUsecase::EventCopy { original, .. } = usecase {
|
||||||
writeln!(f, " data: {}{lt_a},", original.name)?;
|
writeln!(f, " pub data: {}{lt_a},", original.name)?;
|
||||||
} else {
|
} else {
|
||||||
for field in &s.fields {
|
for field in &s.fields {
|
||||||
if let Field::Real(rf) = field {
|
if let Field::Real(rf) = field {
|
||||||
|
|
@ -1308,87 +1332,97 @@ fn format_struct<F: Write>(
|
||||||
writeln!(f, " type Generic<'b> = {}{lt_b};", struct_name)?;
|
writeln!(f, " type Generic<'b> = {}{lt_b};", struct_name)?;
|
||||||
writeln!(f, " const IS_POD: bool = false;")?;
|
writeln!(f, " const IS_POD: bool = false;")?;
|
||||||
writeln!(f, " const HAS_FDS: bool = {has_fds};")?;
|
writeln!(f, " const HAS_FDS: bool = {has_fds};")?;
|
||||||
if !matches!(
|
let mut write_serialize = true;
|
||||||
|
if matches!(
|
||||||
usecase,
|
usecase,
|
||||||
StructUsecase::Event { .. } | StructUsecase::EventCopy { .. } | StructUsecase::Reply
|
StructUsecase::Reply
|
||||||
|
| StructUsecase::Event { xge: true }
|
||||||
|
| StructUsecase::EventCopy { xge: true, .. }
|
||||||
) {
|
) {
|
||||||
|
write_serialize = false;
|
||||||
|
}
|
||||||
|
if write_serialize {
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
writeln!(f, " fn serialize(&self, formatter: &mut Formatter) {{")?;
|
writeln!(f, " fn serialize(&self, formatter: &mut Formatter) {{")?;
|
||||||
for group in &groups {
|
if let StructUsecase::EventCopy { .. } = usecase {
|
||||||
match group {
|
writeln!(f, " self.data.serialize(formatter);")?;
|
||||||
FieldGroup::Pods { fields, .. } => {
|
} else {
|
||||||
writeln!(f, " {{")?;
|
for group in &groups {
|
||||||
for field in fields {
|
match group {
|
||||||
if let Field::Real(rf) = field {
|
FieldGroup::Pods { fields, .. } => {
|
||||||
write!(f, " let {}_bytes = ", rf.name)?;
|
writeln!(f, " {{")?;
|
||||||
match &rf.value {
|
for field in fields {
|
||||||
Some(e) => {
|
if let Field::Real(rf) = field {
|
||||||
writeln!(f, "{{")?;
|
write!(f, " let {}_bytes = ", rf.name)?;
|
||||||
write!(f, " let tmp: ")?;
|
match &rf.value {
|
||||||
write_type(f, &rf.ty, protocols)?;
|
Some(e) => {
|
||||||
write!(f, " = (")?;
|
writeln!(f, "{{")?;
|
||||||
write_expr(f, e, "self.")?;
|
write!(f, " let tmp: ")?;
|
||||||
writeln!(f, ") as _;")?;
|
write_type(f, &rf.ty, protocols)?;
|
||||||
writeln!(f, " tmp.to_ne_bytes()")?;
|
write!(f, " = (")?;
|
||||||
writeln!(f, " }};")?;
|
write_expr(f, e, "self.")?;
|
||||||
|
writeln!(f, ") as _;")?;
|
||||||
|
writeln!(f, " tmp.to_ne_bytes()")?;
|
||||||
|
writeln!(f, " }};")?;
|
||||||
|
}
|
||||||
|
_ => writeln!(f, "self.{}.to_ne_bytes();", rf.name)?,
|
||||||
}
|
}
|
||||||
_ => writeln!(f, "self.{}.to_ne_bytes();", rf.name)?,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
writeln!(f, " formatter.write_bytes(&[")?;
|
||||||
|
for field in fields {
|
||||||
|
match field {
|
||||||
|
Field::Pad(n) => {
|
||||||
|
write!(f, " ")?;
|
||||||
|
for _ in 0..*n {
|
||||||
|
write!(f, " 0,")?;
|
||||||
|
}
|
||||||
|
writeln!(f)?;
|
||||||
|
}
|
||||||
|
Field::Real(rf) => {
|
||||||
|
let num_bytes = match rf.ty {
|
||||||
|
Type::I8 | Type::U8 => 1,
|
||||||
|
Type::I16 | Type::U16 => 2,
|
||||||
|
Type::I32 | Type::U32 => 4,
|
||||||
|
Type::I64 | Type::U64 => 8,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
write!(f, " ")?;
|
||||||
|
for i in 0..num_bytes {
|
||||||
|
write!(f, " {}_bytes[{}],", rf.name, i)?;
|
||||||
|
}
|
||||||
|
writeln!(f)?;
|
||||||
|
}
|
||||||
|
Field::Opcode(n) => {
|
||||||
|
writeln!(f, " {},", n)?;
|
||||||
|
}
|
||||||
|
Field::ExtMajor => {
|
||||||
|
writeln!(f, " formatter.ext_opcode(),")?;
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeln!(f, " ]);")?;
|
||||||
|
writeln!(f, " }}")?;
|
||||||
}
|
}
|
||||||
writeln!(f, " formatter.write_bytes(&[")?;
|
FieldGroup::Single(field) => match field {
|
||||||
for field in fields {
|
Field::Align(n) => writeln!(f, " formatter.align({n});")?,
|
||||||
match field {
|
Field::Real(rf) => match &rf.value {
|
||||||
Field::Pad(n) => {
|
Some(v) => {
|
||||||
write!(f, " ")?;
|
writeln!(f, " {{")?;
|
||||||
for _ in 0..*n {
|
write!(f, " let tmp: ")?;
|
||||||
write!(f, " 0,")?;
|
write_type(f, &rf.ty, protocols)?;
|
||||||
}
|
write!(f, " = ")?;
|
||||||
writeln!(f)?;
|
write_expr(f, v, "self.")?;
|
||||||
|
writeln!(f, " as _;")?;
|
||||||
|
writeln!(f, " tmp.serialize(formatter);")?;
|
||||||
|
writeln!(f, " }}")?;
|
||||||
}
|
}
|
||||||
Field::Real(rf) => {
|
_ => writeln!(f, " self.{}.serialize(formatter);", rf.name)?,
|
||||||
let num_bytes = match rf.ty {
|
},
|
||||||
Type::I8 | Type::U8 => 1,
|
_ => unreachable!(),
|
||||||
Type::I16 | Type::U16 => 2,
|
|
||||||
Type::I32 | Type::U32 => 4,
|
|
||||||
Type::I64 | Type::U64 => 8,
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
write!(f, " ")?;
|
|
||||||
for i in 0..num_bytes {
|
|
||||||
write!(f, " {}_bytes[{}],", rf.name, i)?;
|
|
||||||
}
|
|
||||||
writeln!(f)?;
|
|
||||||
}
|
|
||||||
Field::Opcode(n) => {
|
|
||||||
writeln!(f, " {},", n)?;
|
|
||||||
}
|
|
||||||
Field::ExtMajor => {
|
|
||||||
writeln!(f, " formatter.ext_opcode(),")?;
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
writeln!(f, " ]);")?;
|
|
||||||
writeln!(f, " }}")?;
|
|
||||||
}
|
|
||||||
FieldGroup::Single(field) => match field {
|
|
||||||
Field::Align(n) => writeln!(f, " formatter.align({n});")?,
|
|
||||||
Field::Real(rf) => match &rf.value {
|
|
||||||
Some(v) => {
|
|
||||||
writeln!(f, " {{")?;
|
|
||||||
write!(f, " let tmp: ")?;
|
|
||||||
write_type(f, &rf.ty, protocols)?;
|
|
||||||
write!(f, " = ")?;
|
|
||||||
write_expr(f, v, "self.")?;
|
|
||||||
writeln!(f, " as _;")?;
|
|
||||||
writeln!(f, " tmp.serialize(formatter);")?;
|
|
||||||
writeln!(f, " }}")?;
|
|
||||||
}
|
|
||||||
_ => writeln!(f, " self.{}.serialize(formatter);", rf.name)?,
|
|
||||||
},
|
},
|
||||||
_ => unreachable!(),
|
}
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeln!(f, " }}")?;
|
writeln!(f, " }}")?;
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ mod yield_ {
|
||||||
if self.queue.iteration() > self.iteration {
|
if self.queue.iteration() > self.iteration {
|
||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
} else {
|
} else {
|
||||||
cx.waker().wake_by_ref();
|
self.queue.push_yield(cx.waker().clone());
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -435,16 +435,17 @@ mod queue {
|
||||||
use crate::event_loop::{EventLoop, EventLoopDispatcher, EventLoopId};
|
use crate::event_loop::{EventLoop, EventLoopDispatcher, EventLoopId};
|
||||||
use crate::utils::array;
|
use crate::utils::array;
|
||||||
use crate::utils::numcell::NumCell;
|
use crate::utils::numcell::NumCell;
|
||||||
|
use crate::utils::syncqueue::SyncQueue;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::mem;
|
|
||||||
use std::ops::DerefMut;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::task::Waker;
|
||||||
|
|
||||||
pub(super) struct Dispatcher {
|
pub(super) struct Dispatcher {
|
||||||
queue: Rc<DispatchQueue>,
|
queue: Rc<DispatchQueue>,
|
||||||
stash: RefCell<VecDeque<Runnable>>,
|
stash: RefCell<VecDeque<Runnable>>,
|
||||||
|
yield_stash: RefCell<VecDeque<Waker>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dispatcher {
|
impl Dispatcher {
|
||||||
|
|
@ -457,10 +458,12 @@ mod queue {
|
||||||
num_queued: Default::default(),
|
num_queued: Default::default(),
|
||||||
queues: array::from_fn(|_| Default::default()),
|
queues: array::from_fn(|_| Default::default()),
|
||||||
iteration: Default::default(),
|
iteration: Default::default(),
|
||||||
|
yields: Default::default(),
|
||||||
});
|
});
|
||||||
let slf = Rc::new(Dispatcher {
|
let slf = Rc::new(Dispatcher {
|
||||||
queue: queue.clone(),
|
queue: queue.clone(),
|
||||||
stash: RefCell::new(Default::default()),
|
stash: Default::default(),
|
||||||
|
yield_stash: Default::default(),
|
||||||
});
|
});
|
||||||
el.insert(id, None, 0, slf)?;
|
el.insert(id, None, 0, slf)?;
|
||||||
Ok(queue)
|
Ok(queue)
|
||||||
|
|
@ -470,11 +473,12 @@ mod queue {
|
||||||
impl EventLoopDispatcher for Dispatcher {
|
impl EventLoopDispatcher for Dispatcher {
|
||||||
fn dispatch(self: Rc<Self>, _events: i32) -> Result<(), Box<dyn Error>> {
|
fn dispatch(self: Rc<Self>, _events: i32) -> Result<(), Box<dyn Error>> {
|
||||||
let mut stash = self.stash.borrow_mut();
|
let mut stash = self.stash.borrow_mut();
|
||||||
|
let mut yield_stash = self.yield_stash.borrow_mut();
|
||||||
while self.queue.num_queued.get() > 0 {
|
while self.queue.num_queued.get() > 0 {
|
||||||
self.queue.iteration.fetch_add(1);
|
self.queue.iteration.fetch_add(1);
|
||||||
let mut phase = 0;
|
let mut phase = 0;
|
||||||
while phase < NUM_PHASES as usize {
|
while phase < NUM_PHASES as usize {
|
||||||
mem::swap(&mut *stash, &mut *self.queue.queues[phase].borrow_mut());
|
self.queue.queues[phase].swap(&mut *stash);
|
||||||
if stash.is_empty() {
|
if stash.is_empty() {
|
||||||
phase += 1;
|
phase += 1;
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -484,6 +488,10 @@ mod queue {
|
||||||
runnable.run();
|
runnable.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.queue.yields.swap(&mut *yield_stash);
|
||||||
|
for waker in yield_stash.drain(..) {
|
||||||
|
waker.wake();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.queue.dispatch_scheduled.set(false);
|
self.queue.dispatch_scheduled.set(false);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -494,7 +502,7 @@ mod queue {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let _ = self.queue.el.remove(self.queue.id);
|
let _ = self.queue.el.remove(self.queue.id);
|
||||||
for queue in &self.queue.queues {
|
for queue in &self.queue.queues {
|
||||||
mem::take(queue.borrow_mut().deref_mut());
|
queue.swap(&mut VecDeque::new());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -504,13 +512,14 @@ mod queue {
|
||||||
id: EventLoopId,
|
id: EventLoopId,
|
||||||
el: Rc<EventLoop>,
|
el: Rc<EventLoop>,
|
||||||
num_queued: NumCell<usize>,
|
num_queued: NumCell<usize>,
|
||||||
queues: [RefCell<VecDeque<Runnable>>; NUM_PHASES],
|
queues: [SyncQueue<Runnable>; NUM_PHASES],
|
||||||
iteration: NumCell<u64>,
|
iteration: NumCell<u64>,
|
||||||
|
yields: SyncQueue<Waker>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DispatchQueue {
|
impl DispatchQueue {
|
||||||
pub fn push(&self, runnable: Runnable, phase: Phase) {
|
pub fn push(&self, runnable: Runnable, phase: Phase) {
|
||||||
self.queues[phase as usize].borrow_mut().push_back(runnable);
|
self.queues[phase as usize].push(runnable);
|
||||||
self.num_queued.fetch_add(1);
|
self.num_queued.fetch_add(1);
|
||||||
if !self.dispatch_scheduled.get() {
|
if !self.dispatch_scheduled.get() {
|
||||||
let _ = self.el.schedule(self.id);
|
let _ = self.el.schedule(self.id);
|
||||||
|
|
@ -518,6 +527,10 @@ mod queue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn push_yield(&self, waker: Waker) {
|
||||||
|
self.yields.push(waker);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn iteration(&self) -> u64 {
|
pub fn iteration(&self) -> u64 {
|
||||||
self.iteration.get()
|
self.iteration.get()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -211,8 +211,6 @@ pub struct Client {
|
||||||
pub xwayland_queue: Option<Rc<AsyncQueue<XWaylandEvent>>>,
|
pub xwayland_queue: Option<Rc<AsyncQueue<XWaylandEvent>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAX_PENDING_BUFFERS: usize = 10;
|
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
pub fn invalid_request(&self, obj: &dyn Object, request: u32) {
|
pub fn invalid_request(&self, obj: &dyn Object, request: u32) {
|
||||||
log::error!(
|
log::error!(
|
||||||
|
|
@ -303,7 +301,7 @@ impl Client {
|
||||||
fmt.write_len();
|
fmt.write_len();
|
||||||
if swapchain.cur.is_full() {
|
if swapchain.cur.is_full() {
|
||||||
swapchain.commit();
|
swapchain.commit();
|
||||||
if swapchain.pending.len() > MAX_PENDING_BUFFERS {
|
if swapchain.exceeds_limit() {
|
||||||
if !self.checking_queue_size.replace(true) {
|
if !self.checking_queue_size.replace(true) {
|
||||||
self.state.slow_clients.push(self.clone());
|
self.state.slow_clients.push(self.clone());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,10 +66,6 @@ impl NodeSeatState {
|
||||||
self.dnd_targets.remove(&seat.id);
|
self.dnd_targets.remove(&seat.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn remove_pointer_grabs(&self) {
|
|
||||||
// self.grabs.clear();
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn is_active(&self) -> bool {
|
pub fn is_active(&self) -> bool {
|
||||||
self.kb_foci.len() > 0
|
self.kb_foci.len() > 0
|
||||||
}
|
}
|
||||||
|
|
@ -85,7 +81,7 @@ impl NodeSeatState {
|
||||||
seat.ungrab_kb();
|
seat.ungrab_kb();
|
||||||
seat.keyboard_node.set(seat.state.root.clone());
|
seat.keyboard_node.set(seat.state.root.clone());
|
||||||
if let Some(tl) = seat.toplevel_focus_history.last() {
|
if let Some(tl) = seat.toplevel_focus_history.last() {
|
||||||
seat.focus_node(tl.focus_surface(&seat));
|
seat.focus_node(tl.focus_surface(seat.id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -198,7 +194,11 @@ impl WlSeatGlobal {
|
||||||
pub fn last_tiled_keyboard_toplevel(&self, new: &dyn Node) -> Option<Rc<dyn ToplevelNode>> {
|
pub fn last_tiled_keyboard_toplevel(&self, new: &dyn Node) -> Option<Rc<dyn ToplevelNode>> {
|
||||||
let is_container = new.is_container();
|
let is_container = new.is_container();
|
||||||
for tl in self.toplevel_focus_history.rev_iter() {
|
for tl in self.toplevel_focus_history.rev_iter() {
|
||||||
if !tl.parent_is_float() && (!is_container || !tl.is_contained_in(new.id())) {
|
let parent_is_float = match tl.parent() {
|
||||||
|
Some(pn) => pn.is_float(),
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if !parent_is_float && (!is_container || !tl.as_node().is_contained_in(new.id())) {
|
||||||
return Some(tl.deref().clone());
|
return Some(tl.deref().clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -214,8 +214,8 @@ impl WlSeatGlobal {
|
||||||
|
|
||||||
pub fn focus_toplevel(self: &Rc<Self>, n: Rc<dyn ToplevelNode>) {
|
pub fn focus_toplevel(self: &Rc<Self>, n: Rc<dyn ToplevelNode>) {
|
||||||
let node = self.toplevel_focus_history.add_last(n.clone());
|
let node = self.toplevel_focus_history.add_last(n.clone());
|
||||||
n.set_focus_history_link(self, node);
|
n.data().toplevel_history.insert(self.id, node);
|
||||||
self.focus_node(n.focus_surface(self));
|
self.focus_node(n.focus_surface(self.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ungrab_kb(self: &Rc<Self>) {
|
fn ungrab_kb(self: &Rc<Self>) {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use crate::ifs::wl_callback::WlCallback;
|
||||||
use crate::ifs::wl_seat::{Dnd, NodeSeatState, SeatId, WlSeatGlobal};
|
use crate::ifs::wl_seat::{Dnd, NodeSeatState, SeatId, WlSeatGlobal};
|
||||||
use crate::ifs::wl_surface::cursor::CursorSurface;
|
use crate::ifs::wl_surface::cursor::CursorSurface;
|
||||||
use crate::ifs::wl_surface::wl_subsurface::WlSubsurface;
|
use crate::ifs::wl_surface::wl_subsurface::WlSubsurface;
|
||||||
use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceError, XdgSurfaceRole};
|
use crate::ifs::wl_surface::xdg_surface::{XdgSurfaceError};
|
||||||
use crate::ifs::wl_surface::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1Error;
|
use crate::ifs::wl_surface::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1Error;
|
||||||
use crate::leaks::Tracker;
|
use crate::leaks::Tracker;
|
||||||
use crate::object::Object;
|
use crate::object::Object;
|
||||||
|
|
@ -20,7 +20,7 @@ use crate::pixman::Region;
|
||||||
use crate::rect::Rect;
|
use crate::rect::Rect;
|
||||||
use crate::render::Renderer;
|
use crate::render::Renderer;
|
||||||
use crate::tree::walker::NodeVisitor;
|
use crate::tree::walker::NodeVisitor;
|
||||||
use crate::tree::{ContainerSplit, Node, NodeId};
|
use crate::tree::{ContainerNode, ContainerSplit, Node, NodeId};
|
||||||
use crate::utils::buffd::{MsgParser, MsgParserError};
|
use crate::utils::buffd::{MsgParser, MsgParserError};
|
||||||
use crate::utils::clonecell::CloneCell;
|
use crate::utils::clonecell::CloneCell;
|
||||||
use crate::utils::linkedlist::LinkedList;
|
use crate::utils::linkedlist::LinkedList;
|
||||||
|
|
@ -37,6 +37,7 @@ use std::mem;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
use crate::tree::toplevel::ToplevelNode;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
const INVALID_SCALE: u32 = 0;
|
const INVALID_SCALE: u32 = 0;
|
||||||
|
|
@ -88,7 +89,7 @@ pub struct WlSurface {
|
||||||
ext: CloneCell<Rc<dyn SurfaceExt>>,
|
ext: CloneCell<Rc<dyn SurfaceExt>>,
|
||||||
pub frame_requests: RefCell<Vec<Rc<WlCallback>>>,
|
pub frame_requests: RefCell<Vec<Rc<WlCallback>>>,
|
||||||
seat_state: NodeSeatState,
|
seat_state: NodeSeatState,
|
||||||
xdg: CloneCell<Option<Rc<XdgSurface>>>,
|
toplevel: CloneCell<Option<Rc<dyn ToplevelNode>>>,
|
||||||
cursors: SmallMap<SeatId, Rc<CursorSurface>, 1>,
|
cursors: SmallMap<SeatId, Rc<CursorSurface>, 1>,
|
||||||
pub dnd_icons: SmallMap<SeatId, Rc<WlSeatGlobal>, 1>,
|
pub dnd_icons: SmallMap<SeatId, Rc<WlSeatGlobal>, 1>,
|
||||||
pub tracker: Tracker<Self>,
|
pub tracker: Tracker<Self>,
|
||||||
|
|
@ -203,7 +204,7 @@ impl WlSurface {
|
||||||
ext: CloneCell::new(client.state.none_surface_ext.clone()),
|
ext: CloneCell::new(client.state.none_surface_ext.clone()),
|
||||||
frame_requests: RefCell::new(vec![]),
|
frame_requests: RefCell::new(vec![]),
|
||||||
seat_state: Default::default(),
|
seat_state: Default::default(),
|
||||||
xdg: Default::default(),
|
toplevel: Default::default(),
|
||||||
cursors: Default::default(),
|
cursors: Default::default(),
|
||||||
dnd_icons: Default::default(),
|
dnd_icons: Default::default(),
|
||||||
tracker: Default::default(),
|
tracker: Default::default(),
|
||||||
|
|
@ -242,10 +243,10 @@ impl WlSurface {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn accepts_kb_focus(&self) -> bool {
|
pub fn accepts_kb_focus(&self) -> bool {
|
||||||
if let Some(xdg) = self.xdg.get() {
|
match self.toplevel.get() {
|
||||||
return xdg.role() == XdgSurfaceRole::XdgToplevel;
|
Some(tl) => tl.accepts_keyboard_focus(),
|
||||||
|
_ => self.ext.get().accepts_kb_focus(),
|
||||||
}
|
}
|
||||||
self.ext.get().accepts_kb_focus()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_enter(&self, output: WlOutputId) {
|
fn send_enter(&self, output: WlOutputId) {
|
||||||
|
|
@ -255,19 +256,19 @@ impl WlSurface {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_xdg_surface(&self, xdg: Option<Rc<XdgSurface>>) {
|
fn set_toplevel(&self, tl: Option<Rc<dyn ToplevelNode>>) {
|
||||||
let ch = self.children.borrow();
|
let ch = self.children.borrow();
|
||||||
if let Some(ch) = &*ch {
|
if let Some(ch) = &*ch {
|
||||||
for ss in ch.subsurfaces.values() {
|
for ss in ch.subsurfaces.values() {
|
||||||
ss.surface.set_xdg_surface(xdg.clone());
|
ss.surface.set_toplevel(tl.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.seat_state.is_active() {
|
if self.seat_state.is_active() {
|
||||||
if let Some(xdg) = &xdg {
|
if let Some(tl) = &tl {
|
||||||
xdg.surface_active_changed(true);
|
tl.surface_active_changed(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.xdg.set(xdg);
|
self.toplevel.set(tl);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_role(&self, role: SurfaceRole) -> Result<(), WlSurfaceError> {
|
pub fn set_role(&self, role: SurfaceRole) -> Result<(), WlSurfaceError> {
|
||||||
|
|
@ -367,7 +368,7 @@ impl WlSurface {
|
||||||
}
|
}
|
||||||
self.buffer.set(None);
|
self.buffer.set(None);
|
||||||
self.frame_requests.borrow_mut().clear();
|
self.frame_requests.borrow_mut().clear();
|
||||||
self.xdg.set(None);
|
self.toplevel.set(None);
|
||||||
self.client.remove_obj(self)?;
|
self.client.remove_obj(self)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -588,7 +589,7 @@ impl Object for WlSurface {
|
||||||
self.unset_ext();
|
self.unset_ext();
|
||||||
mem::take(self.frame_requests.borrow_mut().deref_mut());
|
mem::take(self.frame_requests.borrow_mut().deref_mut());
|
||||||
self.buffer.set(None);
|
self.buffer.set(None);
|
||||||
self.xdg.set(None);
|
self.toplevel.set(None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -611,18 +612,19 @@ impl Node for WlSurface {
|
||||||
ss.surface.destroy_node(false);
|
ss.surface.destroy_node(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(xdg) = self.xdg.get() {
|
if let Some(tl) = self.toplevel.get() {
|
||||||
|
let data = tl.data();
|
||||||
let mut remove = vec![];
|
let mut remove = vec![];
|
||||||
for (seat, s) in &xdg.focus_surface {
|
for (seat, s) in data.focus_surface.iter() {
|
||||||
if s.id == self.id {
|
if s.id == self.id {
|
||||||
remove.push(seat);
|
remove.push(seat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for seat in remove {
|
for seat in remove {
|
||||||
xdg.focus_surface.remove(&seat);
|
data.focus_surface.remove(&seat);
|
||||||
}
|
}
|
||||||
if self.seat_state.is_active() {
|
if self.seat_state.is_active() {
|
||||||
xdg.surface_active_changed(false);
|
tl.surface_active_changed(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.seat_state.destroy_node(self);
|
self.seat_state.destroy_node(self);
|
||||||
|
|
@ -642,39 +644,71 @@ impl Node for WlSurface {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_parent_mono(&self) -> Option<bool> {
|
fn get_parent_mono(&self) -> Option<bool> {
|
||||||
self.xdg.get().and_then(|x| x.get_mono())
|
self.toplevel.get()
|
||||||
|
.and_then(|t| t.parent())
|
||||||
|
.and_then(|p| p.get_mono())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_parent_split(&self) -> Option<ContainerSplit> {
|
fn get_parent_split(&self) -> Option<ContainerSplit> {
|
||||||
self.xdg.get().and_then(|x| x.get_split())
|
self.toplevel.get()
|
||||||
|
.and_then(|t| t.parent())
|
||||||
|
.and_then(|p| p.get_split())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_parent_mono(&self, mono: bool) {
|
fn set_parent_mono(&self, mono: bool) {
|
||||||
self.xdg.get().map(|x| x.set_mono(mono));
|
if let Some(tl) = self.toplevel.get() {
|
||||||
|
if let Some(pn) = tl.parent() {
|
||||||
|
let node = if mono { Some(tl.as_node()) } else { None };
|
||||||
|
pn.set_mono(node)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_parent_split(&self, split: ContainerSplit) {
|
fn set_parent_split(&self, split: ContainerSplit) {
|
||||||
self.xdg.get().map(|x| x.set_split(split));
|
if let Some(tl) = self.toplevel.get() {
|
||||||
|
if let Some(pn) = tl.parent() {
|
||||||
|
pn.set_split(split);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_split(self: Rc<Self>, split: ContainerSplit) {
|
fn create_split(self: Rc<Self>, split: ContainerSplit) {
|
||||||
self.xdg.get().map(|x| x.create_split(split));
|
let tl = match self.toplevel.get() {
|
||||||
|
Some(tl) => tl,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
let ws = match tl.workspace() {
|
||||||
|
Some(ws) => ws,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
let pn = match tl.parent() {
|
||||||
|
Some(pn) => pn,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
let cn = ContainerNode::new(
|
||||||
|
&self.client.state,
|
||||||
|
&ws,
|
||||||
|
pn.clone(),
|
||||||
|
tl.clone().into_node(),
|
||||||
|
split,
|
||||||
|
);
|
||||||
|
pn.replace_child(tl.as_node(), cn);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
|
fn move_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
|
||||||
let xdg = match self.xdg.get() {
|
if let Some(tl) = self.toplevel.get() {
|
||||||
Some(x) => x,
|
if let Some(pn) = tl.parent() {
|
||||||
_ => return,
|
pn.move_focus_from_child(seat, tl.as_node(), direction);
|
||||||
};
|
}
|
||||||
xdg.move_focus(seat, direction);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_self(self: Rc<Self>, direction: Direction) {
|
fn move_self(self: Rc<Self>, direction: Direction) {
|
||||||
let xdg = match self.xdg.get() {
|
if let Some(tl) = self.toplevel.get() {
|
||||||
Some(x) => x,
|
if let Some(pn) = tl.parent() {
|
||||||
_ => return,
|
pn.move_child(tl.into_node(), direction);
|
||||||
};
|
}
|
||||||
xdg.move_self(direction);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn absolute_position(&self) -> Rect {
|
fn absolute_position(&self) -> Rect {
|
||||||
|
|
@ -682,8 +716,8 @@ impl Node for WlSurface {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn active_changed(&self, active: bool) {
|
fn active_changed(&self, active: bool) {
|
||||||
if let Some(xdg) = self.xdg.get() {
|
if let Some(tl) = self.toplevel.get() {
|
||||||
xdg.surface_active_changed(active);
|
tl.surface_active_changed(active);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -704,21 +738,22 @@ impl Node for WlSurface {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>) {
|
fn focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>) {
|
||||||
if let Some(xdg) = self.xdg.get() {
|
if let Some(tl) = self.toplevel.get() {
|
||||||
xdg.focus_surface.insert(seat.id(), self.clone());
|
tl.data().focus_surface.insert(seat.id(), self.clone());
|
||||||
|
tl.activate();
|
||||||
}
|
}
|
||||||
seat.focus_surface(&self);
|
seat.focus_surface(&self);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus_parent(&self, seat: &Rc<WlSeatGlobal>) {
|
fn focus_parent(&self, seat: &Rc<WlSeatGlobal>) {
|
||||||
if let Some(xdg) = self.xdg.get() {
|
if let Some(tl) = self.toplevel.get() {
|
||||||
xdg.focus_parent(seat);
|
tl.parent().map(|p| p.focus_self(seat));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toggle_floating(self: Rc<Self>, seat: &Rc<WlSeatGlobal>) {
|
fn toggle_floating(self: Rc<Self>, _seat: &Rc<WlSeatGlobal>) {
|
||||||
if let Some(xdg) = self.xdg.get() {
|
if let Some(tl) = self.toplevel.get() {
|
||||||
xdg.toggle_floating(seat);
|
tl.toggle_floating();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ pub mod xdg_popup;
|
||||||
pub mod xdg_toplevel;
|
pub mod xdg_toplevel;
|
||||||
|
|
||||||
use crate::client::ClientError;
|
use crate::client::ClientError;
|
||||||
use crate::ifs::wl_seat::{NodeSeatState, SeatId, WlSeatGlobal};
|
use crate::ifs::wl_seat::{NodeSeatState};
|
||||||
use crate::ifs::wl_surface::xdg_surface::xdg_popup::{XdgPopup, XdgPopupError};
|
use crate::ifs::wl_surface::xdg_surface::xdg_popup::{XdgPopup, XdgPopupError};
|
||||||
use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel;
|
use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel;
|
||||||
use crate::ifs::wl_surface::{
|
use crate::ifs::wl_surface::{
|
||||||
|
|
@ -12,16 +12,14 @@ use crate::ifs::xdg_wm_base::XdgWmBase;
|
||||||
use crate::leaks::Tracker;
|
use crate::leaks::Tracker;
|
||||||
use crate::object::Object;
|
use crate::object::Object;
|
||||||
use crate::rect::Rect;
|
use crate::rect::Rect;
|
||||||
use crate::tree::{ContainerSplit, FindTreeResult, FoundNode, Node, WorkspaceNode};
|
use crate::tree::{FindTreeResult, FoundNode, Node, WorkspaceNode};
|
||||||
use crate::utils::buffd::MsgParser;
|
use crate::utils::buffd::MsgParser;
|
||||||
use crate::utils::buffd::MsgParserError;
|
use crate::utils::buffd::MsgParserError;
|
||||||
use crate::utils::clonecell::CloneCell;
|
use crate::utils::clonecell::CloneCell;
|
||||||
use crate::utils::copyhashmap::CopyHashMap;
|
use crate::utils::copyhashmap::CopyHashMap;
|
||||||
use crate::utils::smallmap::SmallMap;
|
|
||||||
use crate::wire::xdg_surface::*;
|
use crate::wire::xdg_surface::*;
|
||||||
use crate::wire::{WlSurfaceId, XdgPopupId, XdgSurfaceId};
|
use crate::wire::{WlSurfaceId, XdgPopupId, XdgSurfaceId};
|
||||||
use crate::NumCell;
|
use crate::NumCell;
|
||||||
use jay_config::Direction;
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
@ -63,7 +61,6 @@ pub struct XdgSurface {
|
||||||
ext: CloneCell<Option<Rc<dyn XdgSurfaceExt>>>,
|
ext: CloneCell<Option<Rc<dyn XdgSurfaceExt>>>,
|
||||||
popups: CopyHashMap<XdgPopupId, Rc<XdgPopup>>,
|
popups: CopyHashMap<XdgPopupId, Rc<XdgPopup>>,
|
||||||
pending: PendingXdgSurfaceData,
|
pending: PendingXdgSurfaceData,
|
||||||
pub(super) focus_surface: SmallMap<SeatId, Rc<WlSurface>, 1>,
|
|
||||||
seat_state: NodeSeatState,
|
seat_state: NodeSeatState,
|
||||||
pub workspace: CloneCell<Option<Rc<WorkspaceNode>>>,
|
pub workspace: CloneCell<Option<Rc<WorkspaceNode>>>,
|
||||||
pub tracker: Tracker<Self>,
|
pub tracker: Tracker<Self>,
|
||||||
|
|
@ -75,43 +72,6 @@ struct PendingXdgSurfaceData {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait XdgSurfaceExt: Debug {
|
pub trait XdgSurfaceExt: Debug {
|
||||||
fn focus_parent(&self, seat: &Rc<WlSeatGlobal>) {
|
|
||||||
let _ = seat;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn toggle_floating(self: Rc<Self>, seat: &Rc<WlSeatGlobal>) {
|
|
||||||
let _ = seat;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_mono(&self) -> Option<bool> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_split(&self) -> Option<ContainerSplit> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_mono(&self, mono: bool) {
|
|
||||||
let _ = mono;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_split(&self, split: ContainerSplit) {
|
|
||||||
let _ = split;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_split(self: Rc<Self>, split: ContainerSplit) {
|
|
||||||
let _ = split;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn move_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
|
|
||||||
let _ = seat;
|
|
||||||
let _ = direction;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn move_self(self: Rc<Self>, direction: Direction) {
|
|
||||||
let _ = direction;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn initial_configure(self: Rc<Self>) -> Result<(), XdgSurfaceError> {
|
fn initial_configure(self: Rc<Self>) -> Result<(), XdgSurfaceError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -120,17 +80,9 @@ pub trait XdgSurfaceExt: Debug {
|
||||||
// nothing
|
// nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_node(self: Rc<Self>) -> Option<Rc<dyn Node>> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extents_changed(&self) {
|
fn extents_changed(&self) {
|
||||||
// nothing
|
// nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
fn surface_active_changed(self: Rc<Self>, active: bool) {
|
|
||||||
let _ = active;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl XdgSurface {
|
impl XdgSurface {
|
||||||
|
|
@ -148,7 +100,6 @@ impl XdgSurface {
|
||||||
ext: Default::default(),
|
ext: Default::default(),
|
||||||
popups: Default::default(),
|
popups: Default::default(),
|
||||||
pending: Default::default(),
|
pending: Default::default(),
|
||||||
focus_surface: Default::default(),
|
|
||||||
seat_state: Default::default(),
|
seat_state: Default::default(),
|
||||||
workspace: Default::default(),
|
workspace: Default::default(),
|
||||||
tracker: Default::default(),
|
tracker: Default::default(),
|
||||||
|
|
@ -168,48 +119,6 @@ impl XdgSurface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn surface_active_changed(&self, active: bool) {
|
|
||||||
if let Some(ext) = self.ext.get() {
|
|
||||||
ext.surface_active_changed(active);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_mono(&self) -> Option<bool> {
|
|
||||||
self.ext.get().and_then(|e| e.get_mono())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_split(&self) -> Option<ContainerSplit> {
|
|
||||||
self.ext.get().and_then(|e| e.get_split())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_mono(&self, mono: bool) {
|
|
||||||
self.ext.get().map(|e| e.set_mono(mono));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_split(&self, split: ContainerSplit) {
|
|
||||||
self.ext.get().map(|e| e.set_split(split));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_split(&self, split: ContainerSplit) {
|
|
||||||
self.ext.get().map(|e| e.create_split(split));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn move_focus(&self, seat: &Rc<WlSeatGlobal>, direction: Direction) {
|
|
||||||
if let Some(ext) = self.ext.get() {
|
|
||||||
ext.move_focus(seat, direction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn move_self(&self, direction: Direction) {
|
|
||||||
if let Some(ext) = self.ext.get() {
|
|
||||||
ext.move_self(direction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn role(&self) -> XdgSurfaceRole {
|
|
||||||
self.role.get()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_workspace(&self, ws: &Rc<WorkspaceNode>) {
|
fn set_workspace(&self, ws: &Rc<WorkspaceNode>) {
|
||||||
self.workspace.set(Some(ws.clone()));
|
self.workspace.set(Some(ws.clone()));
|
||||||
let pu = self.popups.lock();
|
let pu = self.popups.lock();
|
||||||
|
|
@ -235,18 +144,6 @@ impl XdgSurface {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn focus_parent(&self, seat: &Rc<WlSeatGlobal>) {
|
|
||||||
if let Some(ext) = self.ext.get() {
|
|
||||||
ext.focus_parent(seat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn toggle_floating(&self, seat: &Rc<WlSeatGlobal>) {
|
|
||||||
if let Some(ext) = self.ext.get() {
|
|
||||||
ext.toggle_floating(seat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn destroy_node(&self) {
|
fn destroy_node(&self) {
|
||||||
self.workspace.set(None);
|
self.workspace.set(None);
|
||||||
self.surface.destroy_node(false);
|
self.surface.destroy_node(false);
|
||||||
|
|
@ -278,7 +175,6 @@ impl XdgSurface {
|
||||||
return Err(XdgSurfaceError::AlreadyAttached(self.surface.id));
|
return Err(XdgSurfaceError::AlreadyAttached(self.surface.id));
|
||||||
}
|
}
|
||||||
self.surface.ext.set(self.clone());
|
self.surface.ext.set(self.clone());
|
||||||
self.surface.set_xdg_surface(Some(self.clone()));
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -293,8 +189,6 @@ impl XdgSurface {
|
||||||
return Err(DestroyError::PopupsNotYetDestroyed);
|
return Err(DestroyError::PopupsNotYetDestroyed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.focus_surface.clear();
|
|
||||||
self.surface.set_xdg_surface(None);
|
|
||||||
self.surface.unset_ext();
|
self.surface.unset_ext();
|
||||||
self.base.surfaces.remove(&self.id);
|
self.base.surfaces.remove(&self.id);
|
||||||
self.surface.client.remove_obj(self)?;
|
self.surface.client.remove_obj(self)?;
|
||||||
|
|
@ -318,7 +212,8 @@ impl XdgSurface {
|
||||||
let toplevel = Rc::new(XdgToplevel::new(req.id, self));
|
let toplevel = Rc::new(XdgToplevel::new(req.id, self));
|
||||||
track!(self.surface.client, toplevel);
|
track!(self.surface.client, toplevel);
|
||||||
self.surface.client.add_client_obj(&toplevel)?;
|
self.surface.client.add_client_obj(&toplevel)?;
|
||||||
self.ext.set(Some(toplevel));
|
self.ext.set(Some(toplevel.clone()));
|
||||||
|
self.surface.set_toplevel(Some(toplevel));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -422,7 +317,6 @@ impl Object for XdgSurface {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn break_loops(&self) {
|
fn break_loops(&self) {
|
||||||
self.focus_surface.take();
|
|
||||||
self.ext.take();
|
self.ext.take();
|
||||||
self.popups.clear();
|
self.popups.clear();
|
||||||
self.workspace.set(None);
|
self.workspace.set(None);
|
||||||
|
|
|
||||||
|
|
@ -353,10 +353,6 @@ impl XdgSurfaceExt for XdgPopup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_node(self: Rc<Self>) -> Option<Rc<dyn Node>> {
|
|
||||||
Some(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extents_changed(&self) {
|
fn extents_changed(&self) {
|
||||||
self.xdg.surface.client.state.tree_changed();
|
self.xdg.surface.client.state.tree_changed();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,23 +2,21 @@ use crate::bugs::Bugs;
|
||||||
use crate::client::{Client, ClientError};
|
use crate::client::{Client, ClientError};
|
||||||
use crate::cursor::KnownCursor;
|
use crate::cursor::KnownCursor;
|
||||||
use crate::fixed::Fixed;
|
use crate::fixed::Fixed;
|
||||||
use crate::ifs::wl_seat::{NodeSeatState, SeatId, WlSeatGlobal};
|
use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal};
|
||||||
use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceError, XdgSurfaceExt};
|
use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceError, XdgSurfaceExt};
|
||||||
use crate::leaks::Tracker;
|
use crate::leaks::Tracker;
|
||||||
use crate::object::Object;
|
use crate::object::Object;
|
||||||
use crate::rect::Rect;
|
use crate::rect::Rect;
|
||||||
use crate::render::Renderer;
|
use crate::render::Renderer;
|
||||||
use crate::tree::walker::NodeVisitor;
|
use crate::tree::walker::NodeVisitor;
|
||||||
use crate::tree::{ContainerNode, ContainerSplit, FindTreeResult};
|
use crate::tree::{FindTreeResult};
|
||||||
use crate::tree::{FoundNode, Node, NodeId, ToplevelNodeId, WorkspaceNode};
|
use crate::tree::{FoundNode, Node, NodeId, ToplevelNodeId, WorkspaceNode};
|
||||||
use crate::utils::buffd::MsgParser;
|
use crate::utils::buffd::MsgParser;
|
||||||
use crate::utils::buffd::MsgParserError;
|
use crate::utils::buffd::MsgParserError;
|
||||||
use crate::utils::clonecell::CloneCell;
|
use crate::utils::clonecell::CloneCell;
|
||||||
use crate::utils::linkedlist::LinkedNode;
|
|
||||||
use crate::utils::smallmap::SmallMap;
|
|
||||||
use crate::wire::xdg_toplevel::*;
|
use crate::wire::xdg_toplevel::*;
|
||||||
use crate::wire::XdgToplevelId;
|
use crate::wire::XdgToplevelId;
|
||||||
use crate::{bugs, NumCell};
|
use crate::{bugs};
|
||||||
use ahash::{AHashMap, AHashSet};
|
use ahash::{AHashMap, AHashSet};
|
||||||
use jay_config::Direction;
|
use jay_config::Direction;
|
||||||
use num_derive::FromPrimitive;
|
use num_derive::FromPrimitive;
|
||||||
|
|
@ -27,9 +25,8 @@ use std::fmt::{Debug, Formatter};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::ifs::wl_surface::WlSurface;
|
use crate::ifs::wl_surface::WlSurface;
|
||||||
use crate::tree::toplevel::ToplevelNode;
|
use crate::tree::toplevel::{ToplevelData, ToplevelNode};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, FromPrimitive)]
|
#[derive(Copy, Clone, Debug, FromPrimitive)]
|
||||||
|
|
@ -51,15 +48,10 @@ const STATE_MAXIMIZED: u32 = 1;
|
||||||
const STATE_FULLSCREEN: u32 = 2;
|
const STATE_FULLSCREEN: u32 = 2;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
const STATE_RESIZING: u32 = 3;
|
const STATE_RESIZING: u32 = 3;
|
||||||
#[allow(dead_code)]
|
|
||||||
const STATE_ACTIVATED: u32 = 4;
|
const STATE_ACTIVATED: u32 = 4;
|
||||||
#[allow(dead_code)]
|
|
||||||
const STATE_TILED_LEFT: u32 = 5;
|
const STATE_TILED_LEFT: u32 = 5;
|
||||||
#[allow(dead_code)]
|
|
||||||
const STATE_TILED_RIGHT: u32 = 6;
|
const STATE_TILED_RIGHT: u32 = 6;
|
||||||
#[allow(dead_code)]
|
|
||||||
const STATE_TILED_TOP: u32 = 7;
|
const STATE_TILED_TOP: u32 = 7;
|
||||||
#[allow(dead_code)]
|
|
||||||
const STATE_TILED_BOTTOM: u32 = 8;
|
const STATE_TILED_BOTTOM: u32 = 8;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||||
|
|
@ -77,8 +69,6 @@ pub struct XdgToplevel {
|
||||||
pub parent: CloneCell<Option<Rc<XdgToplevel>>>,
|
pub parent: CloneCell<Option<Rc<XdgToplevel>>>,
|
||||||
pub children: RefCell<AHashMap<XdgToplevelId, Rc<XdgToplevel>>>,
|
pub children: RefCell<AHashMap<XdgToplevelId, Rc<XdgToplevel>>>,
|
||||||
states: RefCell<AHashSet<u32>>,
|
states: RefCell<AHashSet<u32>>,
|
||||||
pub toplevel_history: SmallMap<SeatId, LinkedNode<Rc<dyn ToplevelNode>>, 1>,
|
|
||||||
active_surfaces: NumCell<u32>,
|
|
||||||
pub decoration: Cell<Decoration>,
|
pub decoration: Cell<Decoration>,
|
||||||
bugs: Cell<&'static Bugs>,
|
bugs: Cell<&'static Bugs>,
|
||||||
min_width: Cell<Option<i32>>,
|
min_width: Cell<Option<i32>>,
|
||||||
|
|
@ -87,6 +77,7 @@ pub struct XdgToplevel {
|
||||||
max_height: Cell<Option<i32>>,
|
max_height: Cell<Option<i32>>,
|
||||||
title: RefCell<String>,
|
title: RefCell<String>,
|
||||||
pub tracker: Tracker<Self>,
|
pub tracker: Tracker<Self>,
|
||||||
|
toplevel_data: ToplevelData,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for XdgToplevel {
|
impl Debug for XdgToplevel {
|
||||||
|
|
@ -110,8 +101,6 @@ impl XdgToplevel {
|
||||||
parent: Default::default(),
|
parent: Default::default(),
|
||||||
children: RefCell::new(Default::default()),
|
children: RefCell::new(Default::default()),
|
||||||
states: RefCell::new(states),
|
states: RefCell::new(states),
|
||||||
toplevel_history: Default::default(),
|
|
||||||
active_surfaces: Default::default(),
|
|
||||||
decoration: Cell::new(Decoration::Server),
|
decoration: Cell::new(Decoration::Server),
|
||||||
bugs: Cell::new(&bugs::NONE),
|
bugs: Cell::new(&bugs::NONE),
|
||||||
min_width: Cell::new(None),
|
min_width: Cell::new(None),
|
||||||
|
|
@ -120,24 +109,7 @@ impl XdgToplevel {
|
||||||
max_height: Cell::new(None),
|
max_height: Cell::new(None),
|
||||||
title: RefCell::new("".to_string()),
|
title: RefCell::new("".to_string()),
|
||||||
tracker: Default::default(),
|
tracker: Default::default(),
|
||||||
}
|
toplevel_data: Default::default(),
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_active(self: &Rc<Self>, active: bool) {
|
|
||||||
if let Some(parent) = self.parent_node.get() {
|
|
||||||
parent.child_active_changed(&**self, active);
|
|
||||||
}
|
|
||||||
let changed = {
|
|
||||||
let mut states = self.states.borrow_mut();
|
|
||||||
match active {
|
|
||||||
true => states.insert(STATE_ACTIVATED),
|
|
||||||
false => states.remove(&STATE_ACTIVATED),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if changed {
|
|
||||||
let rect = self.xdg.absolute_desired_extents.get();
|
|
||||||
self.send_configure_checked(rect.width(), rect.height());
|
|
||||||
self.xdg.do_send_configure();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -195,6 +167,7 @@ impl XdgToplevel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.xdg.surface.client.remove_obj(self.deref())?;
|
self.xdg.surface.client.remove_obj(self.deref())?;
|
||||||
|
self.xdg.surface.set_toplevel(None);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -307,27 +280,15 @@ impl XdgToplevel {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toggle_floating(self: &Rc<Self>) {
|
|
||||||
let parent = match self.parent_node.get() {
|
|
||||||
Some(p) => p,
|
|
||||||
_ => return,
|
|
||||||
};
|
|
||||||
if parent.is_float() {
|
|
||||||
parent.remove_child(&**self);
|
|
||||||
self.map_tiled();
|
|
||||||
} else if let Some(ws) = self.xdg.workspace.get() {
|
|
||||||
parent.remove_child(&**self);
|
|
||||||
self.map_floating(&ws);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn notify_parent(&self) {
|
fn notify_parent(&self) {
|
||||||
let parent = match self.parent_node.get() {
|
let parent = match self.parent_node.get() {
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
let extents = self.xdg.extents.get();
|
let extents = self.xdg.extents.get();
|
||||||
parent.clone().child_active_changed(self, self.active_surfaces.get() > 0);
|
parent
|
||||||
|
.clone()
|
||||||
|
.child_active_changed(self, self.toplevel_data.active_surfaces.get() > 0);
|
||||||
parent.child_size_changed(self, extents.width(), extents.height());
|
parent.child_size_changed(self, extents.width(), extents.height());
|
||||||
parent.child_title_changed(self, self.title.borrow_mut().deref());
|
parent.child_title_changed(self, self.title.borrow_mut().deref());
|
||||||
}
|
}
|
||||||
|
|
@ -400,7 +361,7 @@ impl Node for XdgToplevel {
|
||||||
self.xdg.surface.client.state.tree_changed();
|
self.xdg.surface.client.state.tree_changed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.toplevel_history.take();
|
self.toplevel_data.clear();
|
||||||
self.xdg.destroy_node();
|
self.xdg.destroy_node();
|
||||||
self.xdg.seat_state.destroy_node(self)
|
self.xdg.seat_state.destroy_node(self)
|
||||||
}
|
}
|
||||||
|
|
@ -474,87 +435,72 @@ impl Node for XdgToplevel {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToplevelNode for XdgToplevel {
|
impl ToplevelNode for XdgToplevel {
|
||||||
|
fn data(&self) -> &ToplevelData {
|
||||||
|
&self.toplevel_data
|
||||||
|
}
|
||||||
|
|
||||||
fn parent(&self) -> Option<Rc<dyn Node>> {
|
fn parent(&self) -> Option<Rc<dyn Node>> {
|
||||||
self.parent_node.get()
|
self.parent_node.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus_surface(&self, seat: &WlSeatGlobal) -> Rc<WlSurface> {
|
fn workspace(&self) -> Option<Rc<WorkspaceNode>> {
|
||||||
self.xdg
|
self.xdg.workspace.get()
|
||||||
.focus_surface
|
|
||||||
.get(&seat.id())
|
|
||||||
.unwrap_or_else(|| self.xdg.surface.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_focus_history_link(&self, seat: &WlSeatGlobal, link: LinkedNode<Rc<dyn ToplevelNode>>) {
|
|
||||||
self.toplevel_history.insert(seat.id(), link);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_node(&self) -> &dyn Node {
|
fn as_node(&self) -> &dyn Node {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn into_node(self: Rc<Self>) -> Rc<dyn Node> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accepts_keyboard_focus(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_surface(&self) -> Rc<WlSurface> {
|
||||||
|
self.xdg.surface.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_active(&self, active: bool) {
|
||||||
|
if let Some(parent) = self.parent_node.get() {
|
||||||
|
parent.child_active_changed(self, active);
|
||||||
|
}
|
||||||
|
let changed = {
|
||||||
|
let mut states = self.states.borrow_mut();
|
||||||
|
match active {
|
||||||
|
true => states.insert(STATE_ACTIVATED),
|
||||||
|
false => states.remove(&STATE_ACTIVATED),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if changed {
|
||||||
|
let rect = self.xdg.absolute_desired_extents.get();
|
||||||
|
self.send_configure_checked(rect.width(), rect.height());
|
||||||
|
self.xdg.do_send_configure();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn activate(&self) {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toggle_floating(self: Rc<Self>) {
|
||||||
|
let parent = match self.parent_node.get() {
|
||||||
|
Some(p) => p,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
if parent.is_float() {
|
||||||
|
parent.remove_child(&*self);
|
||||||
|
self.map_tiled();
|
||||||
|
} else if let Some(ws) = self.xdg.workspace.get() {
|
||||||
|
parent.remove_child(&*self);
|
||||||
|
self.map_floating(&ws);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl XdgSurfaceExt for XdgToplevel {
|
impl XdgSurfaceExt for XdgToplevel {
|
||||||
fn focus_parent(&self, seat: &Rc<WlSeatGlobal>) {
|
|
||||||
self.parent_node.get().map(|p| p.focus_self(seat));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn toggle_floating(self: Rc<Self>, _seat: &Rc<WlSeatGlobal>) {
|
|
||||||
Self::toggle_floating(&self);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_mono(&self) -> Option<bool> {
|
|
||||||
self.parent_node.get().and_then(|p| p.get_mono())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_split(&self) -> Option<ContainerSplit> {
|
|
||||||
self.parent_node.get().and_then(|p| p.get_split())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_mono(&self, mono: bool) {
|
|
||||||
let node = if mono {
|
|
||||||
Some(self as &dyn Node)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
self.parent_node.get().map(move |p| p.set_mono(node));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_split(&self, split: ContainerSplit) {
|
|
||||||
self.parent_node.get().map(|p| p.set_split(split));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_split(self: Rc<Self>, split: ContainerSplit) {
|
|
||||||
let ws = match self.xdg.workspace.get() {
|
|
||||||
Some(ws) => ws,
|
|
||||||
_ => return,
|
|
||||||
};
|
|
||||||
let pn = match self.parent_node.get() {
|
|
||||||
Some(pn) => pn,
|
|
||||||
_ => return,
|
|
||||||
};
|
|
||||||
let cn = ContainerNode::new(
|
|
||||||
&self.xdg.surface.client.state,
|
|
||||||
&ws,
|
|
||||||
pn.clone(),
|
|
||||||
self.clone(),
|
|
||||||
split,
|
|
||||||
);
|
|
||||||
pn.replace_child(&*self, cn);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn move_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
|
|
||||||
if let Some(pn) = self.parent_node.get() {
|
|
||||||
pn.move_focus_from_child(seat, &*self, direction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn move_self(self: Rc<Self>, direction: Direction) {
|
|
||||||
if let Some(pn) = self.parent_node.get() {
|
|
||||||
pn.move_child(self, direction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn initial_configure(self: Rc<Self>) -> Result<(), XdgSurfaceError> {
|
fn initial_configure(self: Rc<Self>) -> Result<(), XdgSurfaceError> {
|
||||||
self.send_configure(0, 0);
|
self.send_configure(0, 0);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -600,28 +546,12 @@ impl XdgSurfaceExt for XdgToplevel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_node(self: Rc<Self>) -> Option<Rc<dyn Node>> {
|
|
||||||
Some(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extents_changed(&self) {
|
fn extents_changed(&self) {
|
||||||
self.notify_parent();
|
self.notify_parent();
|
||||||
if self.parent_node.get().is_some() {
|
if self.parent_node.get().is_some() {
|
||||||
self.xdg.surface.client.state.tree_changed();
|
self.xdg.surface.client.state.tree_changed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn surface_active_changed(self: Rc<Self>, active: bool) {
|
|
||||||
if active {
|
|
||||||
if self.active_surfaces.fetch_add(1) == 0 {
|
|
||||||
self.set_active(true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if self.active_surfaces.fetch_sub(1) == 1 {
|
|
||||||
self.set_active(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
|
|
||||||
|
|
@ -5,28 +5,118 @@ use crate::ifs::wl_seat::{NodeSeatState, SeatId, WlSeatGlobal};
|
||||||
use crate::ifs::wl_surface::{SurfaceExt, SurfaceRole, WlSurface, WlSurfaceError};
|
use crate::ifs::wl_surface::{SurfaceExt, SurfaceRole, WlSurface, WlSurfaceError};
|
||||||
use crate::rect::Rect;
|
use crate::rect::Rect;
|
||||||
use crate::render::Renderer;
|
use crate::render::Renderer;
|
||||||
use crate::tree::toplevel::ToplevelNode;
|
use crate::tree::toplevel::{ToplevelData, ToplevelNode};
|
||||||
use crate::tree::walker::NodeVisitor;
|
use crate::tree::walker::NodeVisitor;
|
||||||
use crate::tree::{FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode};
|
use crate::tree::{FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode};
|
||||||
|
use crate::utils::copyhashmap::CopyHashMap;
|
||||||
use crate::utils::linkedlist::LinkedNode;
|
use crate::utils::linkedlist::LinkedNode;
|
||||||
use crate::utils::smallmap::SmallMap;
|
use crate::utils::smallmap::SmallMap;
|
||||||
use crate::wire::WlSurfaceId;
|
use crate::wire::WlSurfaceId;
|
||||||
use crate::wire_xcon::CreateNotify;
|
use crate::wire_xcon::CreateNotify;
|
||||||
use crate::xwayland::XWaylandEvent;
|
use crate::xwayland::XWaylandEvent;
|
||||||
use crate::{AsyncQueue, CloneCell, State};
|
use crate::{AsyncQueue, CloneCell, State};
|
||||||
|
use bstr::BString;
|
||||||
use jay_config::Direction;
|
use jay_config::Direction;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum XInputModel {
|
||||||
|
None,
|
||||||
|
Passive,
|
||||||
|
Local,
|
||||||
|
Global,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for XInputModel {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Passive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub struct IcccmHints {
|
||||||
|
pub flags: Cell<i32>,
|
||||||
|
pub input: Cell<u32>,
|
||||||
|
pub initial_state: Cell<i32>,
|
||||||
|
pub icon_pixmap: Cell<u32>,
|
||||||
|
pub icon_window: Cell<u32>,
|
||||||
|
pub icon_x: Cell<i32>,
|
||||||
|
pub icon_y: Cell<i32>,
|
||||||
|
pub icon_mask: Cell<u32>,
|
||||||
|
pub window_group: Cell<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub struct SizeHints {
|
||||||
|
pub flags: Cell<u32>,
|
||||||
|
pub x: Cell<i32>,
|
||||||
|
pub y: Cell<i32>,
|
||||||
|
pub width: Cell<i32>,
|
||||||
|
pub height: Cell<i32>,
|
||||||
|
pub min_width: Cell<i32>,
|
||||||
|
pub min_height: Cell<i32>,
|
||||||
|
pub max_width: Cell<i32>,
|
||||||
|
pub max_height: Cell<i32>,
|
||||||
|
pub width_inc: Cell<i32>,
|
||||||
|
pub height_inc: Cell<i32>,
|
||||||
|
pub min_aspect_num: Cell<i32>,
|
||||||
|
pub min_aspect_den: Cell<i32>,
|
||||||
|
pub max_aspect_num: Cell<i32>,
|
||||||
|
pub max_aspect_den: Cell<i32>,
|
||||||
|
pub base_width: Cell<i32>,
|
||||||
|
pub base_height: Cell<i32>,
|
||||||
|
pub win_gravity: Cell<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub struct MotifHints {
|
||||||
|
pub flags: Cell<u32>,
|
||||||
|
pub decorations: Cell<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub struct XwindowInfo {
|
||||||
|
pub has_alpha: Cell<bool>,
|
||||||
|
pub override_redirect: Cell<bool>,
|
||||||
|
pub extents: Cell<Rect>,
|
||||||
|
pub instance: RefCell<Option<BString>>,
|
||||||
|
pub class: RefCell<Option<BString>>,
|
||||||
|
pub title: RefCell<Option<BString>>,
|
||||||
|
pub role: RefCell<Option<BString>>,
|
||||||
|
pub protocols: CopyHashMap<u32, ()>,
|
||||||
|
pub window_types: CopyHashMap<u32, ()>,
|
||||||
|
pub never_focus: Cell<bool>,
|
||||||
|
pub utf8_title: Cell<bool>,
|
||||||
|
pub icccm_hints: IcccmHints,
|
||||||
|
pub normal_hints: SizeHints,
|
||||||
|
pub motif_hints: MotifHints,
|
||||||
|
pub startup_id: RefCell<Option<BString>>,
|
||||||
|
pub fullscreen: Cell<bool>,
|
||||||
|
pub modal: Cell<bool>,
|
||||||
|
pub maximized_vert: Cell<bool>,
|
||||||
|
pub maximized_horz: Cell<bool>,
|
||||||
|
pub minimized: Cell<bool>,
|
||||||
|
pub pid: Cell<Option<u32>>,
|
||||||
|
pub input_model: Cell<XInputModel>,
|
||||||
|
pub mapped: Cell<bool>,
|
||||||
|
pub wants_floating: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct XwindowData {
|
pub struct XwindowData {
|
||||||
pub state: Rc<State>,
|
pub state: Rc<State>,
|
||||||
pub window_id: u32,
|
pub window_id: u32,
|
||||||
pub override_redirect: bool,
|
|
||||||
pub extents: Cell<Rect>,
|
|
||||||
pub client: Rc<Client>,
|
pub client: Rc<Client>,
|
||||||
pub surface_id: Cell<Option<WlSurfaceId>>,
|
pub surface_id: Cell<Option<WlSurfaceId>>,
|
||||||
pub window: CloneCell<Option<Rc<Xwindow>>>,
|
pub window: CloneCell<Option<Rc<Xwindow>>>,
|
||||||
|
pub info: XwindowInfo,
|
||||||
|
pub children: CopyHashMap<u32, Rc<XwindowData>>,
|
||||||
|
pub parent: CloneCell<Option<Rc<XwindowData>>>,
|
||||||
|
pub stack_link: RefCell<Option<LinkedNode<Rc<XwindowData>>>>,
|
||||||
|
pub map_link: Cell<Option<LinkedNode<Rc<XwindowData>>>>,
|
||||||
|
pub startup_info: RefCell<Vec<u8>>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
tree_id!(XwindowId);
|
tree_id!(XwindowId);
|
||||||
|
|
@ -35,12 +125,13 @@ pub struct Xwindow {
|
||||||
pub seat_state: NodeSeatState,
|
pub seat_state: NodeSeatState,
|
||||||
pub data: Rc<XwindowData>,
|
pub data: Rc<XwindowData>,
|
||||||
pub surface: Rc<WlSurface>,
|
pub surface: Rc<WlSurface>,
|
||||||
pub parent: CloneCell<Option<Rc<dyn Node>>>,
|
pub parent_node: CloneCell<Option<Rc<dyn Node>>>,
|
||||||
pub focus_history: SmallMap<SeatId, LinkedNode<Rc<dyn ToplevelNode>>, 1>,
|
pub focus_history: SmallMap<SeatId, LinkedNode<Rc<dyn ToplevelNode>>, 1>,
|
||||||
pub events: Rc<AsyncQueue<XWaylandEvent>>,
|
pub events: Rc<AsyncQueue<XWaylandEvent>>,
|
||||||
pub workspace: CloneCell<Option<Rc<WorkspaceNode>>>,
|
pub workspace: CloneCell<Option<Rc<WorkspaceNode>>>,
|
||||||
pub display_link: RefCell<Option<LinkedNode<Rc<dyn Node>>>>,
|
pub display_link: RefCell<Option<LinkedNode<Rc<dyn Node>>>>,
|
||||||
pub display_xlink: RefCell<Option<LinkedNode<Rc<Xwindow>>>>,
|
pub display_xlink: RefCell<Option<LinkedNode<Rc<Xwindow>>>>,
|
||||||
|
pub toplevel_data: ToplevelData,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl XwindowData {
|
impl XwindowData {
|
||||||
|
|
@ -52,17 +143,43 @@ impl XwindowData {
|
||||||
event.height as _,
|
event.height as _,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
log::info!("extents = {:?}", extents);
|
|
||||||
Self {
|
Self {
|
||||||
state: state.clone(),
|
state: state.clone(),
|
||||||
window_id: event.window,
|
window_id: event.window,
|
||||||
override_redirect: event.override_redirect != 0,
|
|
||||||
extents: Cell::new(extents),
|
|
||||||
client: client.clone(),
|
client: client.clone(),
|
||||||
surface_id: Cell::new(None),
|
surface_id: Cell::new(None),
|
||||||
window: Default::default(),
|
window: Default::default(),
|
||||||
|
info: XwindowInfo {
|
||||||
|
override_redirect: Cell::new(event.override_redirect != 0),
|
||||||
|
extents: Cell::new(extents),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
children: Default::default(),
|
||||||
|
parent: Default::default(),
|
||||||
|
stack_link: Default::default(),
|
||||||
|
map_link: Default::default(),
|
||||||
|
startup_info: Default::default(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_ancestor_of(&self, mut other: Rc<Self>) -> bool {
|
||||||
|
loop {
|
||||||
|
if other.window_id == self.window_id {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
other = match other.parent.get() {
|
||||||
|
Some(p) => p,
|
||||||
|
_ => return false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Change {
|
||||||
|
None,
|
||||||
|
Map,
|
||||||
|
Unmap,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Xwindow {
|
impl Xwindow {
|
||||||
|
|
@ -76,12 +193,13 @@ impl Xwindow {
|
||||||
seat_state: Default::default(),
|
seat_state: Default::default(),
|
||||||
data: data.clone(),
|
data: data.clone(),
|
||||||
surface: surface.clone(),
|
surface: surface.clone(),
|
||||||
parent: Default::default(),
|
parent_node: Default::default(),
|
||||||
focus_history: Default::default(),
|
focus_history: Default::default(),
|
||||||
events: events.clone(),
|
events: events.clone(),
|
||||||
workspace: Default::default(),
|
workspace: Default::default(),
|
||||||
display_link: Default::default(),
|
display_link: Default::default(),
|
||||||
display_xlink: Default::default(),
|
display_xlink: Default::default(),
|
||||||
|
toplevel_data: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -92,6 +210,7 @@ impl Xwindow {
|
||||||
|
|
||||||
pub fn break_loops(&self) {
|
pub fn break_loops(&self) {
|
||||||
self.destroy_node(true);
|
self.destroy_node(true);
|
||||||
|
self.surface.set_toplevel(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn install(self: &Rc<Self>) -> Result<(), XWindowError> {
|
pub fn install(self: &Rc<Self>) -> Result<(), XWindowError> {
|
||||||
|
|
@ -100,11 +219,12 @@ impl Xwindow {
|
||||||
return Err(XWindowError::AlreadyAttached);
|
return Err(XWindowError::AlreadyAttached);
|
||||||
}
|
}
|
||||||
self.surface.ext.set(self.clone());
|
self.surface.ext.set(self.clone());
|
||||||
|
self.surface.set_toplevel(Some(self.clone()));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn notify_parent(&self) {
|
fn notify_parent(&self) {
|
||||||
let parent = match self.parent.get() {
|
let parent = match self.parent_node.get() {
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
@ -115,45 +235,47 @@ impl Xwindow {
|
||||||
// parent.child_title_changed(self, self.title.borrow_mut().deref());
|
// parent.child_title_changed(self, self.title.borrow_mut().deref());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn managed_post_commit(self: &Rc<Self>) {
|
pub fn is_mapped(&self) -> bool {
|
||||||
let parent = self.parent.get();
|
self.parent_node.get().is_some() || self.display_link.borrow_mut().is_some()
|
||||||
if self.surface.buffer.get().is_some() {
|
}
|
||||||
if parent.is_none() {
|
|
||||||
self.data.state.map_tiled(self.clone());
|
pub fn may_be_mapped(&self) -> bool {
|
||||||
}
|
self.surface.buffer.get().is_some() && self.data.info.mapped.get()
|
||||||
} else {
|
}
|
||||||
if parent.is_some() {
|
|
||||||
self.destroy_node(true);
|
fn map_change(&self) -> Change {
|
||||||
}
|
match (self.may_be_mapped(), self.is_mapped()) {
|
||||||
|
(true, false) => Change::Map,
|
||||||
|
(false, true) => Change::Unmap,
|
||||||
|
_ => Change::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unmanaged_post_commit(self: &Rc<Self>) {
|
pub fn map_status_changed(self: &Rc<Self>) {
|
||||||
let mut dl = self.display_link.borrow_mut();
|
match self.map_change() {
|
||||||
let mut dxl = self.display_xlink.borrow_mut();
|
Change::None => {}
|
||||||
if self.surface.buffer.get().is_some() {
|
Change::Unmap => self.destroy_node(true),
|
||||||
if dl.is_none() {
|
Change::Map if self.data.info.override_redirect.get() => {
|
||||||
*dl = Some(self.data.state.root.stacked.add_last(self.clone()));
|
*self.display_link.borrow_mut() = Some(self.data.state.root.stacked.add_last(self.clone()));
|
||||||
*dxl = Some(self.data.state.root.xstacked.add_last(self.clone()));
|
*self.display_xlink.borrow_mut() = Some(self.data.state.root.xstacked.add_last(self.clone()));
|
||||||
self.data.state.tree_changed();
|
self.data.state.tree_changed();
|
||||||
}
|
}
|
||||||
} else {
|
Change::Map if self.data.info.wants_floating.get() => {
|
||||||
if dl.is_some() {
|
let ws = self.data.state.root.outputs.lock().iter().next().unwrap().1.workspace.get().unwrap();
|
||||||
drop(dl);
|
// todo
|
||||||
drop(dxl);
|
let ext = self.data.info.extents.get();
|
||||||
self.destroy_node(true);
|
self.data.state.map_floating(self.clone(), ext.width(), ext.height(), &ws);
|
||||||
}
|
},
|
||||||
|
Change::Map => {
|
||||||
|
self.data.state.map_tiled(self.clone())
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SurfaceExt for Xwindow {
|
impl SurfaceExt for Xwindow {
|
||||||
fn post_commit(self: Rc<Self>) {
|
fn post_commit(self: Rc<Self>) {
|
||||||
if self.data.override_redirect {
|
self.map_status_changed();
|
||||||
self.unmanaged_post_commit();
|
|
||||||
} else {
|
|
||||||
self.managed_post_commit();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_surface_destroy(&self) -> Result<(), WlSurfaceError> {
|
fn on_surface_destroy(&self) -> Result<(), WlSurfaceError> {
|
||||||
|
|
@ -185,11 +307,12 @@ impl Node for Xwindow {
|
||||||
self.display_link.borrow_mut().take();
|
self.display_link.borrow_mut().take();
|
||||||
self.workspace.take();
|
self.workspace.take();
|
||||||
self.focus_history.clear();
|
self.focus_history.clear();
|
||||||
if let Some(parent) = self.parent.take() {
|
if let Some(parent) = self.parent_node.take() {
|
||||||
parent.remove_child(self);
|
parent.remove_child(self);
|
||||||
}
|
}
|
||||||
self.surface.destroy_node(false);
|
self.surface.destroy_node(false);
|
||||||
self.seat_state.destroy_node(self);
|
self.seat_state.destroy_node(self);
|
||||||
|
self.toplevel_data.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit(self: Rc<Self>, visitor: &mut dyn NodeVisitor) {
|
fn visit(self: Rc<Self>, visitor: &mut dyn NodeVisitor) {
|
||||||
|
|
@ -201,7 +324,7 @@ impl Node for Xwindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_contained_in(&self, other: NodeId) -> bool {
|
fn is_contained_in(&self, other: NodeId) -> bool {
|
||||||
if let Some(parent) = self.parent.get() {
|
if let Some(parent) = self.parent_node.get() {
|
||||||
if parent.id() == other {
|
if parent.id() == other {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -215,7 +338,7 @@ impl Node for Xwindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn absolute_position(&self) -> Rect {
|
fn absolute_position(&self) -> Rect {
|
||||||
self.data.extents.get()
|
self.data.info.extents.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec<FoundNode>) -> FindTreeResult {
|
fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec<FoundNode>) -> FindTreeResult {
|
||||||
|
|
@ -247,7 +370,7 @@ impl Node for Xwindow {
|
||||||
fn change_extents(self: Rc<Self>, rect: &Rect) {
|
fn change_extents(self: Rc<Self>, rect: &Rect) {
|
||||||
let nw = rect.width();
|
let nw = rect.width();
|
||||||
let nh = rect.height();
|
let nh = rect.height();
|
||||||
let de = self.data.extents.replace(*rect);
|
let de = self.data.info.extents.replace(*rect);
|
||||||
if de.width() != nw || de.height() != nh {
|
if de.width() != nw || de.height() != nh {
|
||||||
self.events.push(XWaylandEvent::Configure(self.clone()));
|
self.events.push(XWaylandEvent::Configure(self.clone()));
|
||||||
}
|
}
|
||||||
|
|
@ -258,7 +381,7 @@ impl Node for Xwindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_parent(self: Rc<Self>, parent: Rc<dyn Node>) {
|
fn set_parent(self: Rc<Self>, parent: Rc<dyn Node>) {
|
||||||
self.parent.set(Some(parent));
|
self.parent_node.set(Some(parent));
|
||||||
self.notify_parent();
|
self.notify_parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -268,21 +391,47 @@ impl Node for Xwindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToplevelNode for Xwindow {
|
impl ToplevelNode for Xwindow {
|
||||||
|
fn data(&self) -> &ToplevelData {
|
||||||
|
&self.toplevel_data
|
||||||
|
}
|
||||||
|
|
||||||
fn parent(&self) -> Option<Rc<dyn Node>> {
|
fn parent(&self) -> Option<Rc<dyn Node>> {
|
||||||
self.parent.get()
|
self.parent_node.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus_surface(&self, _seat: &WlSeatGlobal) -> Rc<WlSurface> {
|
fn workspace(&self) -> Option<Rc<WorkspaceNode>> {
|
||||||
self.surface.clone()
|
self.workspace.get()
|
||||||
}
|
|
||||||
|
|
||||||
fn set_focus_history_link(&self, seat: &WlSeatGlobal, link: LinkedNode<Rc<dyn ToplevelNode>>) {
|
|
||||||
self.focus_history.insert(seat.id(), link);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_node(&self) -> &dyn Node {
|
fn as_node(&self) -> &dyn Node {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn into_node(self: Rc<Self>) -> Rc<dyn Node> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accepts_keyboard_focus(&self) -> bool {
|
||||||
|
self.data.info.icccm_hints.input.get() != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_surface(&self) -> Rc<WlSurface> {
|
||||||
|
self.surface.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_active(&self, active: bool) {
|
||||||
|
if let Some(pn) = self.parent_node.get() {
|
||||||
|
pn.child_active_changed(self, active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn activate(&self) {
|
||||||
|
self.events.push(XWaylandEvent::Activate(self.data.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toggle_floating(self: Rc<Self>) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
|
|
||||||
|
|
@ -361,7 +361,7 @@ macro_rules! assert_align_eq {
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! atom_manager {
|
macro_rules! atoms {
|
||||||
{
|
{
|
||||||
$name:ident;
|
$name:ident;
|
||||||
$($field_name:ident,)*
|
$($field_name:ident,)*
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,6 @@ pub enum RenderError {
|
||||||
#[error("EGL display does not support `EGL_EXT_image_dma_buf_import_modifiers`")]
|
#[error("EGL display does not support `EGL_EXT_image_dma_buf_import_modifiers`")]
|
||||||
DmaBufImport,
|
DmaBufImport,
|
||||||
#[error("GLES driver does not support `GL_OES_EGL_image`")]
|
#[error("GLES driver does not support `GL_OES_EGL_image`")]
|
||||||
#[allow(dead_code)]
|
|
||||||
OesEglImage,
|
OesEglImage,
|
||||||
#[error("EGL display does not support `EGL_KHR_image_base`")]
|
#[error("EGL display does not support `EGL_KHR_image_base`")]
|
||||||
ImageBase,
|
ImageBase,
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,9 @@ impl EglDisplay {
|
||||||
ctx,
|
ctx,
|
||||||
};
|
};
|
||||||
ctx.ext = ctx.with_current(|| Ok(get_gl_ext()))?;
|
ctx.ext = ctx.with_current(|| Ok(get_gl_ext()))?;
|
||||||
// if !ctx.ext.contains(GlExt::GL_OES_EGL_IMAGE) {
|
if !ctx.ext.contains(GlExt::GL_OES_EGL_IMAGE) {
|
||||||
// return Err(GlesError::OesEglImage);
|
return Err(RenderError::OesEglImage);
|
||||||
// }
|
}
|
||||||
Ok(Rc::new(ctx))
|
Ok(Rc::new(ctx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use crate::render::gl::sys::{
|
||||||
};
|
};
|
||||||
use crate::render::renderer::context::RenderContext;
|
use crate::render::renderer::context::RenderContext;
|
||||||
use crate::render::renderer::renderer::Renderer;
|
use crate::render::renderer::renderer::Renderer;
|
||||||
use crate::render::sys::{glBlendFunc, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, glFlush};
|
use crate::render::sys::{glBlendFunc, glFlush, GL_ONE, GL_ONE_MINUS_SRC_ALPHA};
|
||||||
use crate::tree::Node;
|
use crate::tree::Node;
|
||||||
use crate::State;
|
use crate::State;
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,7 @@ use crate::render::renderer::context::RenderContext;
|
||||||
use crate::render::sys::{glDisable, glEnable, GL_BLEND};
|
use crate::render::sys::{glDisable, glEnable, GL_BLEND};
|
||||||
use crate::render::Texture;
|
use crate::render::Texture;
|
||||||
use crate::theme::Color;
|
use crate::theme::Color;
|
||||||
use crate::tree::{
|
use crate::tree::{ContainerNode, FloatNode, Node, OutputNode, WorkspaceNode};
|
||||||
ContainerNode, FloatNode, Node, OutputNode, WorkspaceNode,
|
|
||||||
};
|
|
||||||
use crate::State;
|
use crate::State;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
@ -69,7 +67,6 @@ impl Renderer<'_> {
|
||||||
2.0 * (y as f32 / self.fb.height as f32) - 1.0
|
2.0 * (y as f32 / self.fb.height as f32) - 1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn fill_boxes(&self, boxes: &[Rect], color: &Color) {
|
fn fill_boxes(&self, boxes: &[Rect], color: &Color) {
|
||||||
self.fill_boxes2(boxes, color, 0, 0);
|
self.fill_boxes2(boxes, color, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -315,7 +315,10 @@ impl ContainerNode {
|
||||||
|
|
||||||
fn perform_mono_layout(self: &Rc<Self>, child: &ContainerChild) {
|
fn perform_mono_layout(self: &Rc<Self>, child: &ContainerChild) {
|
||||||
let mb = self.mono_body.get();
|
let mb = self.mono_body.get();
|
||||||
child.node.clone().change_extents(&mb.move_(self.abs_x1.get(), self.abs_y1.get()));
|
child
|
||||||
|
.node
|
||||||
|
.clone()
|
||||||
|
.change_extents(&mb.move_(self.abs_x1.get(), self.abs_y1.get()));
|
||||||
self.mono_content
|
self.mono_content
|
||||||
.set(child.content.get().at_point(mb.x1(), mb.y1()));
|
.set(child.content.get().at_point(mb.x1(), mb.y1()));
|
||||||
}
|
}
|
||||||
|
|
@ -566,7 +569,8 @@ impl ContainerNode {
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
for (i, c) in self.children.iter().enumerate() {
|
for (i, c) in self.children.iter().enumerate() {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
rd.border_rects.push(Rect::new_sized(pos - bw, 0, bw, th).unwrap());
|
rd.border_rects
|
||||||
|
.push(Rect::new_sized(pos - bw, 0, bw, th).unwrap());
|
||||||
}
|
}
|
||||||
let mut width = space_per_child;
|
let mut width = space_per_child;
|
||||||
if rem > 0 {
|
if rem > 0 {
|
||||||
|
|
@ -583,9 +587,9 @@ impl ContainerNode {
|
||||||
let title = c.title.borrow_mut();
|
let title = c.title.borrow_mut();
|
||||||
match text::render(&ctx, width, th, &font, &title, Color::GREY) {
|
match text::render(&ctx, width, th, &font, &title, Color::GREY) {
|
||||||
Ok(t) => rd.titles.push(ContainerTitle {
|
Ok(t) => rd.titles.push(ContainerTitle {
|
||||||
x: pos,
|
x: pos,
|
||||||
y: 0,
|
y: 0,
|
||||||
tex: t,
|
tex: t,
|
||||||
}),
|
}),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Could not render title {}: {}", title, ErrorFmt(e));
|
log::error!("Could not render title {}: {}", title, ErrorFmt(e));
|
||||||
|
|
@ -594,7 +598,8 @@ impl ContainerNode {
|
||||||
}
|
}
|
||||||
pos += width + bw;
|
pos += width + bw;
|
||||||
}
|
}
|
||||||
rd.underline_rects.push(Rect::new_sized(0, th, cwidth, 1).unwrap());
|
rd.underline_rects
|
||||||
|
.push(Rect::new_sized(0, th, cwidth, 1).unwrap());
|
||||||
} else {
|
} else {
|
||||||
let split = self.split.get();
|
let split = self.split.get();
|
||||||
for (i, c) in self.children.iter().enumerate() {
|
for (i, c) in self.children.iter().enumerate() {
|
||||||
|
|
@ -607,7 +612,8 @@ impl ContainerNode {
|
||||||
};
|
};
|
||||||
rd.border_rects.push(rect);
|
rd.border_rects.push(rect);
|
||||||
}
|
}
|
||||||
let rect = Rect::new_sized(body.x1(), body.y1() - th - 1, body.width(), th).unwrap();
|
let rect =
|
||||||
|
Rect::new_sized(body.x1(), body.y1() - th - 1, body.width(), th).unwrap();
|
||||||
if c.active.get() {
|
if c.active.get() {
|
||||||
rd.active_title_rects.push(rect);
|
rd.active_title_rects.push(rect);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -799,7 +805,9 @@ impl Node for ContainerNode {
|
||||||
matches!(direction, Direction::Left | Direction::Right)
|
matches!(direction, Direction::Left | Direction::Right)
|
||||||
} else {
|
} else {
|
||||||
match self.split.get() {
|
match self.split.get() {
|
||||||
ContainerSplit::Horizontal => matches!(direction, Direction::Left | Direction::Right),
|
ContainerSplit::Horizontal => {
|
||||||
|
matches!(direction, Direction::Left | Direction::Right)
|
||||||
|
}
|
||||||
ContainerSplit::Vertical => matches!(direction, Direction::Up | Direction::Down),
|
ContainerSplit::Vertical => matches!(direction, Direction::Up | Direction::Down),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -831,8 +839,12 @@ impl Node for ContainerNode {
|
||||||
if mc.is_some() {
|
if mc.is_some() {
|
||||||
self.mono_child.set(Some(sibling.clone()));
|
self.mono_child.set(Some(sibling.clone()));
|
||||||
let body = self.mono_body.get();
|
let body = self.mono_body.get();
|
||||||
self.mono_content.set(sibling.content.get().at_point(body.x1(), body.y1()));
|
self.mono_content
|
||||||
sibling.node.clone().change_extents(&body.move_(self.abs_x1.get(), self.abs_y1.get()));
|
.set(sibling.content.get().at_point(body.x1(), body.y1()));
|
||||||
|
sibling
|
||||||
|
.node
|
||||||
|
.clone()
|
||||||
|
.change_extents(&body.move_(self.abs_x1.get(), self.abs_y1.get()));
|
||||||
}
|
}
|
||||||
sibling.node.clone().do_focus(seat, direction);
|
sibling.node.clone().do_focus(seat, direction);
|
||||||
}
|
}
|
||||||
|
|
@ -1167,7 +1179,10 @@ impl Node for ContainerNode {
|
||||||
.child_size_changed(&*self, rect.width(), rect.height());
|
.child_size_changed(&*self, rect.width(), rect.height());
|
||||||
} else {
|
} else {
|
||||||
if let Some(c) = self.mono_child.get() {
|
if let Some(c) = self.mono_child.get() {
|
||||||
let body = self.mono_body.get().move_(self.abs_x1.get(), self.abs_y1.get());
|
let body = self
|
||||||
|
.mono_body
|
||||||
|
.get()
|
||||||
|
.move_(self.abs_x1.get(), self.abs_y1.get());
|
||||||
c.node.clone().change_extents(&body);
|
c.node.clone().change_extents(&body);
|
||||||
} else {
|
} else {
|
||||||
for child in self.children.iter() {
|
for child in self.children.iter() {
|
||||||
|
|
@ -1187,7 +1202,9 @@ impl Node for ContainerNode {
|
||||||
|
|
||||||
fn set_parent(self: Rc<Self>, parent: Rc<dyn Node>) {
|
fn set_parent(self: Rc<Self>, parent: Rc<dyn Node>) {
|
||||||
self.parent.set(parent.clone());
|
self.parent.set(parent.clone());
|
||||||
parent.clone().child_active_changed(&*self, self.active.get());
|
parent
|
||||||
|
.clone()
|
||||||
|
.child_active_changed(&*self, self.active.get());
|
||||||
parent.child_size_changed(&*self, self.width.get(), self.height.get());
|
parent.child_size_changed(&*self, self.width.get(), self.height.get());
|
||||||
parent
|
parent
|
||||||
.clone()
|
.clone()
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,55 @@
|
||||||
use crate::ifs::wl_seat::WlSeatGlobal;
|
use crate::ifs::wl_seat::{SeatId};
|
||||||
use crate::ifs::wl_surface::WlSurface;
|
use crate::ifs::wl_surface::WlSurface;
|
||||||
use crate::tree::Node;
|
use crate::tree::{Node, WorkspaceNode};
|
||||||
use crate::utils::linkedlist::LinkedNode;
|
use crate::utils::linkedlist::LinkedNode;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use crate::NumCell;
|
||||||
|
use crate::utils::smallmap::SmallMap;
|
||||||
|
|
||||||
pub trait ToplevelNode: Node {
|
pub trait ToplevelNode {
|
||||||
|
fn data(&self) -> &ToplevelData;
|
||||||
fn parent(&self) -> Option<Rc<dyn Node>>;
|
fn parent(&self) -> Option<Rc<dyn Node>>;
|
||||||
fn focus_surface(&self, seat: &WlSeatGlobal) -> Rc<WlSurface>;
|
fn workspace(&self) -> Option<Rc<WorkspaceNode>>;
|
||||||
fn set_focus_history_link(&self, seat: &WlSeatGlobal, link: LinkedNode<Rc<dyn ToplevelNode>>);
|
|
||||||
fn as_node(&self) -> &dyn Node;
|
fn as_node(&self) -> &dyn Node;
|
||||||
|
fn into_node(self: Rc<Self>) -> Rc<dyn Node>;
|
||||||
|
fn accepts_keyboard_focus(&self) -> bool;
|
||||||
|
fn default_surface(&self) -> Rc<WlSurface>;
|
||||||
|
fn set_active(&self, active: bool);
|
||||||
|
fn activate(&self);
|
||||||
|
fn toggle_floating(self: Rc<Self>);
|
||||||
|
}
|
||||||
|
|
||||||
fn parent_is_float(&self) -> bool {
|
#[derive(Default)]
|
||||||
if let Some(parent) = self.parent() {
|
pub struct ToplevelData {
|
||||||
return parent.is_float();
|
pub active_surfaces: NumCell<u32>,
|
||||||
}
|
pub focus_surface: SmallMap<SeatId, Rc<WlSurface>, 1>,
|
||||||
false
|
pub toplevel_history: SmallMap<SeatId, LinkedNode<Rc<dyn ToplevelNode>>, 1>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToplevelData {
|
||||||
|
pub fn clear(&self) {
|
||||||
|
self.focus_surface.clear();
|
||||||
|
self.toplevel_history.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> dyn ToplevelNode + 'a {
|
||||||
|
pub fn surface_active_changed(&self, active: bool) {
|
||||||
|
if active {
|
||||||
|
if self.data().active_surfaces.fetch_add(1) == 0 {
|
||||||
|
self.set_active(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if self.data().active_surfaces.fetch_sub(1) == 1 {
|
||||||
|
self.set_active(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_surface(&self, seat: SeatId) -> Rc<WlSurface> {
|
||||||
|
self.data()
|
||||||
|
.focus_surface
|
||||||
|
.get(&seat)
|
||||||
|
.unwrap_or_else(|| self.default_surface())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
pub trait BitflagsExt {
|
pub trait BitflagsExt {
|
||||||
fn contains(self, other: Self) -> bool;
|
fn contains(self, other: Self) -> bool;
|
||||||
|
fn not_contains(self, other: Self) -> bool;
|
||||||
fn intersects(self, other: Self) -> bool;
|
fn intersects(self, other: Self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -10,6 +11,10 @@ macro_rules! num {
|
||||||
self & other == other
|
self & other == other
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn not_contains(self, other: Self) -> bool {
|
||||||
|
self & other != other
|
||||||
|
}
|
||||||
|
|
||||||
fn intersects(self, other: Self) -> bool {
|
fn intersects(self, other: Self) -> bool {
|
||||||
self & other != 0
|
self & other != 0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use ahash::AHashMap;
|
use ahash::AHashMap;
|
||||||
use std::cell::{RefCell, RefMut};
|
use std::cell::{RefCell, RefMut};
|
||||||
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
|
@ -7,6 +8,12 @@ pub struct CopyHashMap<K, V> {
|
||||||
map: RefCell<AHashMap<K, V>>,
|
map: RefCell<AHashMap<K, V>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<K: Debug, V: Debug> Debug for CopyHashMap<K, V> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.map.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<K, V> Default for CopyHashMap<K, V> {
|
impl<K, V> Default for CopyHashMap<K, V> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::utils::ptr_ext::MutPtrExt;
|
use crate::utils::ptr_ext::MutPtrExt;
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
pub struct SyncQueue<T> {
|
pub struct SyncQueue<T> {
|
||||||
el: UnsafeCell<VecDeque<T>>,
|
el: UnsafeCell<VecDeque<T>>,
|
||||||
|
|
@ -28,4 +29,10 @@ impl<T> SyncQueue<T> {
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
unsafe { self.el.get().deref_mut().is_empty() }
|
unsafe { self.el.get().deref_mut().is_empty() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn swap(&self, queue: &mut VecDeque<T>) {
|
||||||
|
unsafe {
|
||||||
|
mem::swap(self.el.get().deref_mut(), queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
339
src/xcon.rs
339
src/xcon.rs
|
|
@ -1,15 +1,18 @@
|
||||||
use crate::async_engine::SpawnedFuture;
|
use crate::async_engine::SpawnedFuture;
|
||||||
use crate::utils::bufio::{BufIo, BufIoError, BufIoMessage};
|
use crate::utils::bufio::{BufIo, BufIoError, BufIoMessage};
|
||||||
use crate::utils::oserror::OsError;
|
use crate::utils::oserror::OsError;
|
||||||
|
use crate::utils::vec_ext::VecExt;
|
||||||
use crate::wire_xcon::{
|
use crate::wire_xcon::{
|
||||||
Extension, GetInputFocus, ListExtensions, QueryExtension, RenderQueryPictFormats, Setup,
|
CreateGC, CreatePixmap, Extension, FreeGC, FreePixmap, GetInputFocus, GetProperty,
|
||||||
EXTENSIONS,
|
ListExtensions, PutImage, QueryExtension, RenderCreateCursor, RenderCreatePicture,
|
||||||
|
RenderQueryPictFormats, Setup, EXTENSIONS,
|
||||||
};
|
};
|
||||||
use crate::xcon::consts::RENDER_PICT_TYPE_DIRECT;
|
use crate::xcon::consts::{IMAGE_FORMAT_Z_PIXMAP, RENDER_PICT_TYPE_DIRECT};
|
||||||
pub use crate::xcon::formatter::Formatter;
|
pub use crate::xcon::formatter::Formatter;
|
||||||
use crate::xcon::incoming::handle_incoming;
|
use crate::xcon::incoming::handle_incoming;
|
||||||
use crate::xcon::outgoing::handle_outgoing;
|
use crate::xcon::outgoing::handle_outgoing;
|
||||||
pub use crate::xcon::parser::Parser;
|
pub use crate::xcon::parser::Parser;
|
||||||
|
use crate::xcon::wire_type::SendEvent;
|
||||||
pub use crate::xcon::wire_type::{Message, Request, XEvent};
|
pub use crate::xcon::wire_type::{Message, Request, XEvent};
|
||||||
use crate::xcon::xauthority::{XAuthority, LOCAL, MIT_MAGIC_COOKIE};
|
use crate::xcon::xauthority::{XAuthority, LOCAL, MIT_MAGIC_COOKIE};
|
||||||
use crate::{AsyncEngine, AsyncError, AsyncQueue, CloneCell, ErrorFmt, NumCell, Phase};
|
use crate::{AsyncEngine, AsyncError, AsyncQueue, CloneCell, ErrorFmt, NumCell, Phase};
|
||||||
|
|
@ -95,6 +98,24 @@ pub enum XconError {
|
||||||
QueryPictFormats(#[source] Box<XconError>),
|
QueryPictFormats(#[source] Box<XconError>),
|
||||||
#[error("The server does not support the picture format for cursors")]
|
#[error("The server does not support the picture format for cursors")]
|
||||||
CursorFormatNotSupported,
|
CursorFormatNotSupported,
|
||||||
|
#[error("Could not create a pixmap")]
|
||||||
|
CreatePixmap(#[source] Box<XconError>),
|
||||||
|
#[error("Could not create a graphics context")]
|
||||||
|
CreateGc(#[source] Box<XconError>),
|
||||||
|
#[error("Could not upload an image")]
|
||||||
|
PutImage(#[source] Box<XconError>),
|
||||||
|
#[error("Could not create a picture")]
|
||||||
|
CreatePicture(#[source] Box<XconError>),
|
||||||
|
#[error("Could not create a cursor")]
|
||||||
|
CreateCursor(#[source] Box<XconError>),
|
||||||
|
#[error("Property has an invalid type")]
|
||||||
|
InvalidPropertyType,
|
||||||
|
#[error("Property has an invalid format. Expected: {0}; Actual: {1}")]
|
||||||
|
InvalidPropertyFormat(u8, u8),
|
||||||
|
#[error("Length of the property data is not a multiple of its format")]
|
||||||
|
IrregularPropertyLength,
|
||||||
|
#[error("The property is not set")]
|
||||||
|
PropertyUnavailable,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -107,6 +128,7 @@ struct ExtensionIdRange {
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
struct ExtensionData {
|
struct ExtensionData {
|
||||||
opcodes: [Option<u8>; EXTENSIONS.len()],
|
opcodes: [Option<u8>; EXTENSIONS.len()],
|
||||||
|
first_event: [Option<u8>; EXTENSIONS.len()],
|
||||||
ext_by_opcode: AHashMap<u8, Extension>,
|
ext_by_opcode: AHashMap<u8, Extension>,
|
||||||
events: Vec<ExtensionIdRange>,
|
events: Vec<ExtensionIdRange>,
|
||||||
errors: Vec<ExtensionIdRange>,
|
errors: Vec<ExtensionIdRange>,
|
||||||
|
|
@ -124,6 +146,12 @@ pub struct Xcon {
|
||||||
xid_max: u32,
|
xid_max: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Drop for Xcon {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.data.kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct XconData {
|
struct XconData {
|
||||||
bufio: Rc<BufIo>,
|
bufio: Rc<BufIo>,
|
||||||
next_serial: NumCell<u64>,
|
next_serial: NumCell<u64>,
|
||||||
|
|
@ -147,6 +175,7 @@ pub struct Event {
|
||||||
ext: Option<Extension>,
|
ext: Option<Extension>,
|
||||||
code: u16,
|
code: u16,
|
||||||
buf: Vec<u8>,
|
buf: Vec<u8>,
|
||||||
|
serial: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for Event {
|
impl Deref for Event {
|
||||||
|
|
@ -166,6 +195,10 @@ impl Event {
|
||||||
self.code
|
self.code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn serial(&self) -> u64 {
|
||||||
|
self.serial
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse<'a, M: Message<'a>>(&'a self) -> Result<M, XconError> {
|
pub fn parse<'a, M: Message<'a>>(&'a self) -> Result<M, XconError> {
|
||||||
let mut parser = Parser::new(&self.buf, vec![]);
|
let mut parser = Parser::new(&self.buf, vec![]);
|
||||||
M::deserialize(&mut parser)
|
M::deserialize(&mut parser)
|
||||||
|
|
@ -448,30 +481,178 @@ impl Xcon {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call<'a, T: Request<'a>>(self: &Rc<Self>, t: &T) -> AsyncReply<T::Reply> {
|
pub fn call<'a, T: Request<'a>>(self: &Rc<Self>, t: &T) -> AsyncReply<T::Reply> {
|
||||||
self.data.call(t, &self.extensions)
|
self.data.call_with_serial(t, &self.extensions).0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn find_cursor_format(self: &Rc<Self>) -> Result<u32, XconError> {
|
pub fn call_with_serial<'a, T: Request<'a>>(
|
||||||
let res = match self.call(&RenderQueryPictFormats {}).await {
|
self: &Rc<Self>,
|
||||||
Ok(r) => r,
|
t: &T,
|
||||||
Err(e) => return Err(XconError::QueryPictFormats(Box::new(e))),
|
) -> (AsyncReply<T::Reply>, u64) {
|
||||||
};
|
self.data.call_with_serial(t, &self.extensions)
|
||||||
for format in res.get().formats.iter() {
|
}
|
||||||
let valid = format.ty == RENDER_PICT_TYPE_DIRECT
|
|
||||||
&& format.depth == 32
|
pub fn send_event<'a, T: XEvent<'a>>(
|
||||||
&& format.direct.red_shift == 16
|
self: &Rc<Self>,
|
||||||
&& format.direct.red_mask == 0xff
|
propagate: bool,
|
||||||
&& format.direct.green_shift == 8
|
destination: u32,
|
||||||
&& format.direct.green_mask == 0xff
|
event_mask: u32,
|
||||||
&& format.direct.blue_shift == 0
|
t: &T,
|
||||||
&& format.direct.blue_mask == 0xff
|
) -> AsyncReply<()> {
|
||||||
&& format.direct.alpha_shift == 24
|
self.data
|
||||||
&& format.direct.alpha_mask == 0xff;
|
.send_event(t, &self.extensions, propagate, destination, event_mask)
|
||||||
if valid {
|
}
|
||||||
return Ok(format.id);
|
|
||||||
|
pub async fn get_property<T: PropertyType>(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
window: u32,
|
||||||
|
property: u32,
|
||||||
|
ty: u32,
|
||||||
|
buf: &mut Vec<T>,
|
||||||
|
) -> Result<u32, XconError> {
|
||||||
|
let len = buf.len();
|
||||||
|
match self.get_property2(window, property, ty, buf).await {
|
||||||
|
Ok(n) => Ok(n),
|
||||||
|
Err(e) => {
|
||||||
|
buf.truncate(len);
|
||||||
|
Err(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(XconError::CursorFormatNotSupported)
|
}
|
||||||
|
|
||||||
|
async fn get_property2<T: PropertyType>(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
window: u32,
|
||||||
|
property: u32,
|
||||||
|
ty: u32,
|
||||||
|
buf: &mut Vec<T>,
|
||||||
|
) -> Result<u32, XconError> {
|
||||||
|
let mut gp = GetProperty {
|
||||||
|
delete: 0,
|
||||||
|
window,
|
||||||
|
property,
|
||||||
|
ty,
|
||||||
|
long_offset: 0,
|
||||||
|
long_length: 128,
|
||||||
|
};
|
||||||
|
let format = mem::size_of::<T>() as u8 * 8;
|
||||||
|
loop {
|
||||||
|
let res = self.call(&gp).await?;
|
||||||
|
let res = res.get();
|
||||||
|
if res.format == 0 {
|
||||||
|
return Err(XconError::PropertyUnavailable);
|
||||||
|
}
|
||||||
|
if gp.ty != 0 && gp.ty != res.ty {
|
||||||
|
return Err(XconError::InvalidPropertyType);
|
||||||
|
}
|
||||||
|
gp.ty = res.ty;
|
||||||
|
if res.format != format {
|
||||||
|
return Err(XconError::InvalidPropertyFormat(format, res.format));
|
||||||
|
}
|
||||||
|
if res.data.len() % mem::size_of::<T>() != 0 {
|
||||||
|
return Err(XconError::IrregularPropertyLength);
|
||||||
|
}
|
||||||
|
let len = res.data.len() / mem::size_of::<T>();
|
||||||
|
buf.reserve(len);
|
||||||
|
let (_, uninit) = buf.split_at_spare_mut_bytes_ext();
|
||||||
|
uninit[..res.data.len()].copy_from_slice(uapi::as_maybe_uninit_bytes(res.data));
|
||||||
|
unsafe {
|
||||||
|
buf.set_len(buf.len() + len);
|
||||||
|
}
|
||||||
|
if res.bytes_after == 0 {
|
||||||
|
return Ok(res.ty);
|
||||||
|
}
|
||||||
|
gp.long_offset += gp.long_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_cursor(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
pixels: &[Cell<u8>],
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
xhot: i32,
|
||||||
|
yhot: i32,
|
||||||
|
) -> Result<u32, XconError> {
|
||||||
|
let cursor_format = 'cursor_format: {
|
||||||
|
let res = match self.call(&RenderQueryPictFormats {}).await {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(e) => return Err(XconError::QueryPictFormats(Box::new(e))),
|
||||||
|
};
|
||||||
|
for format in res.get().formats.iter() {
|
||||||
|
let valid = format.ty == RENDER_PICT_TYPE_DIRECT
|
||||||
|
&& format.depth == 32
|
||||||
|
&& format.direct.red_shift == 16
|
||||||
|
&& format.direct.red_mask == 0xff
|
||||||
|
&& format.direct.green_shift == 8
|
||||||
|
&& format.direct.green_mask == 0xff
|
||||||
|
&& format.direct.blue_shift == 0
|
||||||
|
&& format.direct.blue_mask == 0xff
|
||||||
|
&& format.direct.alpha_shift == 24
|
||||||
|
&& format.direct.alpha_mask == 0xff;
|
||||||
|
if valid {
|
||||||
|
break 'cursor_format format.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Err(XconError::CursorFormatNotSupported);
|
||||||
|
};
|
||||||
|
let pixmap = self.generate_id()?;
|
||||||
|
let gc = self.generate_id()?;
|
||||||
|
let picture = self.generate_id()?;
|
||||||
|
let cursor = self.generate_id()?;
|
||||||
|
let create_pixmap = self.call(&CreatePixmap {
|
||||||
|
depth: 32,
|
||||||
|
pid: pixmap,
|
||||||
|
drawable: self.setup.get().screens[0].root,
|
||||||
|
width: width as _,
|
||||||
|
height: height as _,
|
||||||
|
});
|
||||||
|
let create_gc = self.call(&CreateGC {
|
||||||
|
cid: gc,
|
||||||
|
drawable: pixmap,
|
||||||
|
values: Default::default(),
|
||||||
|
});
|
||||||
|
let put_image = self.call(&PutImage {
|
||||||
|
format: IMAGE_FORMAT_Z_PIXMAP,
|
||||||
|
drawable: pixmap,
|
||||||
|
gc,
|
||||||
|
width: width as _,
|
||||||
|
height: height as _,
|
||||||
|
dst_x: 0,
|
||||||
|
dst_y: 0,
|
||||||
|
left_pad: 0,
|
||||||
|
depth: 32,
|
||||||
|
data: unsafe { mem::transmute(pixels) },
|
||||||
|
});
|
||||||
|
self.call(&FreeGC { gc });
|
||||||
|
let create_picture = self.call(&RenderCreatePicture {
|
||||||
|
pid: picture,
|
||||||
|
drawable: pixmap,
|
||||||
|
format: cursor_format,
|
||||||
|
values: Default::default(),
|
||||||
|
});
|
||||||
|
self.call(&FreePixmap { pixmap });
|
||||||
|
let create_cursor = self.call(&RenderCreateCursor {
|
||||||
|
cid: cursor,
|
||||||
|
source: picture,
|
||||||
|
x: xhot as _,
|
||||||
|
y: yhot as _,
|
||||||
|
});
|
||||||
|
if let Err(e) = create_pixmap.await {
|
||||||
|
return Err(XconError::CreatePixmap(Box::new(e)));
|
||||||
|
}
|
||||||
|
if let Err(e) = create_gc.await {
|
||||||
|
return Err(XconError::CreateGc(Box::new(e)));
|
||||||
|
}
|
||||||
|
if let Err(e) = put_image.await {
|
||||||
|
return Err(XconError::PutImage(Box::new(e)));
|
||||||
|
}
|
||||||
|
if let Err(e) = create_picture.await {
|
||||||
|
return Err(XconError::CreatePicture(Box::new(e)));
|
||||||
|
}
|
||||||
|
if let Err(e) = create_cursor.await {
|
||||||
|
return Err(XconError::CreateCursor(Box::new(e)));
|
||||||
|
}
|
||||||
|
Ok(cursor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -489,35 +670,86 @@ impl XconData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cold]
|
||||||
|
fn dead<T: Message<'static>>(self: &Rc<Self>) -> AsyncReply<T> {
|
||||||
|
AsyncReply {
|
||||||
|
slot: Rc::new(AsyncReplySlot {
|
||||||
|
data: Cell::new(Some(Err(XconError::Dead))),
|
||||||
|
waker: Cell::new(None),
|
||||||
|
}),
|
||||||
|
xorg: self.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cold]
|
||||||
|
fn ext_unavailable<T: Message<'static>>(self: &Rc<Self>, idx: usize) -> AsyncReply<T> {
|
||||||
|
AsyncReply {
|
||||||
|
slot: Rc::new(AsyncReplySlot {
|
||||||
|
data: Cell::new(Some(Err(XconError::ExtensionUnavailable(
|
||||||
|
EXTENSIONS[idx].name(),
|
||||||
|
)))),
|
||||||
|
waker: Cell::new(None),
|
||||||
|
}),
|
||||||
|
xorg: self.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_event<'a, T: XEvent<'a>>(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
t: &T,
|
||||||
|
extensions: &ExtensionData,
|
||||||
|
propagate: bool,
|
||||||
|
destination: u32,
|
||||||
|
event_mask: u32,
|
||||||
|
) -> AsyncReply<()> {
|
||||||
|
if self.dead.get() {
|
||||||
|
return self.dead();
|
||||||
|
}
|
||||||
|
let first_event = match T::EXTENSION {
|
||||||
|
None => 0,
|
||||||
|
Some(idx) => match extensions.first_event[idx] {
|
||||||
|
Some(o) => o,
|
||||||
|
_ => return self.ext_unavailable(idx),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let mut fds = vec![];
|
||||||
|
let mut buf = self.bufio.buf();
|
||||||
|
let mut formatter = Formatter::new(&mut fds, &mut buf, 0);
|
||||||
|
let se = SendEvent {
|
||||||
|
propagate: propagate as u8,
|
||||||
|
destination,
|
||||||
|
event_mask,
|
||||||
|
};
|
||||||
|
se.serialize(&mut formatter);
|
||||||
|
t.serialize(&mut formatter);
|
||||||
|
formatter.pad_to(44);
|
||||||
|
formatter.write_request_length();
|
||||||
|
buf[12] = first_event + T::OPCODE as u8;
|
||||||
|
self.need_sync.set(true);
|
||||||
|
self.send(fds, buf).0
|
||||||
|
}
|
||||||
|
|
||||||
fn call<'a, T: Request<'a>>(
|
fn call<'a, T: Request<'a>>(
|
||||||
self: &Rc<Self>,
|
self: &Rc<Self>,
|
||||||
t: &T,
|
t: &T,
|
||||||
extensions: &ExtensionData,
|
extensions: &ExtensionData,
|
||||||
) -> AsyncReply<T::Reply> {
|
) -> AsyncReply<T::Reply> {
|
||||||
|
self.call_with_serial(t, extensions).0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_with_serial<'a, T: Request<'a>>(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
t: &T,
|
||||||
|
extensions: &ExtensionData,
|
||||||
|
) -> (AsyncReply<T::Reply>, u64) {
|
||||||
if self.dead.get() {
|
if self.dead.get() {
|
||||||
return AsyncReply {
|
return (self.dead(), 0);
|
||||||
slot: Rc::new(AsyncReplySlot {
|
|
||||||
data: Cell::new(Some(Err(XconError::Dead))),
|
|
||||||
waker: Cell::new(None),
|
|
||||||
}),
|
|
||||||
xorg: self.clone(),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
let opcode = match T::EXTENSION {
|
let opcode = match T::EXTENSION {
|
||||||
None => 0,
|
None => 0,
|
||||||
Some(idx) => match extensions.opcodes[idx] {
|
Some(idx) => match extensions.opcodes[idx] {
|
||||||
Some(o) => o,
|
Some(o) => o,
|
||||||
_ => {
|
_ => return (self.ext_unavailable(idx), 0),
|
||||||
return AsyncReply {
|
|
||||||
slot: Rc::new(AsyncReplySlot {
|
|
||||||
data: Cell::new(Some(Err(XconError::ExtensionUnavailable(
|
|
||||||
EXTENSIONS[idx].name(),
|
|
||||||
)))),
|
|
||||||
waker: Cell::new(None),
|
|
||||||
}),
|
|
||||||
xorg: self.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let mut fds = vec![];
|
let mut fds = vec![];
|
||||||
|
|
@ -525,21 +757,31 @@ impl XconData {
|
||||||
let mut formatter = Formatter::new(&mut fds, &mut buf, opcode);
|
let mut formatter = Formatter::new(&mut fds, &mut buf, opcode);
|
||||||
t.serialize(&mut formatter);
|
t.serialize(&mut formatter);
|
||||||
formatter.write_request_length();
|
formatter.write_request_length();
|
||||||
|
self.need_sync.set(T::IS_VOID);
|
||||||
|
self.send(fds, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send<T: Message<'static>>(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
fds: Vec<Rc<OwnedFd>>,
|
||||||
|
buf: Vec<u8>,
|
||||||
|
) -> (AsyncReply<T>, u64) {
|
||||||
self.bufio.send(BufIoMessage { fds, buf });
|
self.bufio.send(BufIoMessage { fds, buf });
|
||||||
let slot = Rc::new(AsyncReplySlot {
|
let slot = Rc::new(AsyncReplySlot {
|
||||||
data: Cell::new(None),
|
data: Cell::new(None),
|
||||||
waker: Cell::new(None),
|
waker: Cell::new(None),
|
||||||
});
|
});
|
||||||
|
let serial = self.next_serial.fetch_add(1);
|
||||||
let handler = Box::new(AsyncReplyHandler {
|
let handler = Box::new(AsyncReplyHandler {
|
||||||
serial: self.next_serial.fetch_add(1),
|
serial,
|
||||||
slot: Rc::downgrade(&slot),
|
slot: Rc::downgrade(&slot),
|
||||||
});
|
});
|
||||||
self.reply_handlers.borrow_mut().push_back(handler);
|
self.reply_handlers.borrow_mut().push_back(handler);
|
||||||
self.need_sync.set(T::IS_VOID);
|
let rep = AsyncReply {
|
||||||
AsyncReply {
|
|
||||||
slot,
|
slot,
|
||||||
xorg: self.clone(),
|
xorg: self.clone(),
|
||||||
}
|
};
|
||||||
|
(rep, serial)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_sync(&self) {
|
fn send_sync(&self) {
|
||||||
|
|
@ -590,6 +832,7 @@ impl XconData {
|
||||||
}
|
}
|
||||||
if let Some(e) = e {
|
if let Some(e) = e {
|
||||||
ed.opcodes[e as usize] = Some(data.major_opcode);
|
ed.opcodes[e as usize] = Some(data.major_opcode);
|
||||||
|
ed.first_event[e as usize] = Some(data.first_event);
|
||||||
ed.ext_by_opcode.insert(data.major_opcode, e);
|
ed.ext_by_opcode.insert(data.major_opcode, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -617,3 +860,9 @@ fn parse_display() -> Result<u32, XconError> {
|
||||||
};
|
};
|
||||||
Ok(num)
|
Ok(num)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe trait PropertyType {}
|
||||||
|
|
||||||
|
unsafe impl PropertyType for u8 {}
|
||||||
|
unsafe impl PropertyType for u16 {}
|
||||||
|
unsafe impl PropertyType for u32 {}
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,76 @@ pub const INPUT_DEVICE_ALL_MASTER: u16 = 1;
|
||||||
|
|
||||||
pub const WINDOW_CLASS_INPUT_OUTPUT: u16 = 1;
|
pub const WINDOW_CLASS_INPUT_OUTPUT: u16 = 1;
|
||||||
|
|
||||||
pub const PROP_MODE_REPLACE: u8 = 0;
|
pub const ATOM_NONE: u32 = 0;
|
||||||
|
pub const ATOM_ANY: u32 = 0;
|
||||||
pub const ATOM_WM_CLASS: u32 = 67;
|
pub const ATOM_PRIMARY: u32 = 1;
|
||||||
|
pub const ATOM_SECONDARY: u32 = 2;
|
||||||
|
pub const ATOM_ARC: u32 = 3;
|
||||||
|
pub const ATOM_ATOM: u32 = 4;
|
||||||
|
pub const ATOM_BITMAP: u32 = 5;
|
||||||
|
pub const ATOM_CARDINAL: u32 = 6;
|
||||||
|
pub const ATOM_COLORMAP: u32 = 7;
|
||||||
|
pub const ATOM_CURSOR: u32 = 8;
|
||||||
|
pub const ATOM_CUT_BUFFER0: u32 = 9;
|
||||||
|
pub const ATOM_CUT_BUFFER1: u32 = 10;
|
||||||
|
pub const ATOM_CUT_BUFFER2: u32 = 11;
|
||||||
|
pub const ATOM_CUT_BUFFER3: u32 = 12;
|
||||||
|
pub const ATOM_CUT_BUFFER4: u32 = 13;
|
||||||
|
pub const ATOM_CUT_BUFFER5: u32 = 14;
|
||||||
|
pub const ATOM_CUT_BUFFER6: u32 = 15;
|
||||||
|
pub const ATOM_CUT_BUFFER7: u32 = 16;
|
||||||
|
pub const ATOM_DRAWABLE: u32 = 17;
|
||||||
|
pub const ATOM_FONT: u32 = 18;
|
||||||
|
pub const ATOM_INTEGER: u32 = 19;
|
||||||
|
pub const ATOM_PIXMAP: u32 = 20;
|
||||||
|
pub const ATOM_POINT: u32 = 21;
|
||||||
|
pub const ATOM_RECTANGLE: u32 = 22;
|
||||||
|
pub const ATOM_RESOURCE_MANAGER: u32 = 23;
|
||||||
|
pub const ATOM_RGB_COLOR_MAP: u32 = 24;
|
||||||
|
pub const ATOM_RGB_BEST_MAP: u32 = 25;
|
||||||
|
pub const ATOM_RGB_BLUE_MAP: u32 = 26;
|
||||||
|
pub const ATOM_RGB_DEFAULT_MAP: u32 = 27;
|
||||||
|
pub const ATOM_RGB_GRAY_MAP: u32 = 28;
|
||||||
|
pub const ATOM_RGB_GREEN_MAP: u32 = 29;
|
||||||
|
pub const ATOM_RGB_RED_MAP: u32 = 30;
|
||||||
pub const ATOM_STRING: u32 = 31;
|
pub const ATOM_STRING: u32 = 31;
|
||||||
|
pub const ATOM_VISUALID: u32 = 32;
|
||||||
|
pub const ATOM_WINDOW: u32 = 33;
|
||||||
|
pub const ATOM_WM_COMMAND: u32 = 34;
|
||||||
|
pub const ATOM_WM_HINTS: u32 = 35;
|
||||||
|
pub const ATOM_WM_CLIENT_MACHINE: u32 = 36;
|
||||||
|
pub const ATOM_WM_ICON_NAME: u32 = 37;
|
||||||
|
pub const ATOM_WM_ICON_SIZE: u32 = 38;
|
||||||
|
pub const ATOM_WM_NAME: u32 = 39;
|
||||||
|
pub const ATOM_WM_NORMAL_HINTS: u32 = 40;
|
||||||
|
pub const ATOM_WM_SIZE_HINTS: u32 = 41;
|
||||||
|
pub const ATOM_WM_ZOOM_HINTS: u32 = 42;
|
||||||
|
pub const ATOM_MIN_SPACE: u32 = 43;
|
||||||
|
pub const ATOM_NORM_SPACE: u32 = 44;
|
||||||
|
pub const ATOM_MAX_SPACE: u32 = 45;
|
||||||
|
pub const ATOM_END_SPACE: u32 = 46;
|
||||||
|
pub const ATOM_SUPERSCRIPT_X: u32 = 47;
|
||||||
|
pub const ATOM_SUPERSCRIPT_Y: u32 = 48;
|
||||||
|
pub const ATOM_SUBSCRIPT_X: u32 = 49;
|
||||||
|
pub const ATOM_SUBSCRIPT_Y: u32 = 50;
|
||||||
|
pub const ATOM_UNDERLINE_POSITION: u32 = 51;
|
||||||
|
pub const ATOM_UNDERLINE_THICKNESS: u32 = 52;
|
||||||
|
pub const ATOM_STRIKEOUT_ASCENT: u32 = 53;
|
||||||
|
pub const ATOM_STRIKEOUT_DESCENT: u32 = 54;
|
||||||
|
pub const ATOM_ITALIC_ANGLE: u32 = 55;
|
||||||
|
pub const ATOM_X_HEIGHT: u32 = 56;
|
||||||
|
pub const ATOM_QUAD_WIDTH: u32 = 57;
|
||||||
|
pub const ATOM_WEIGHT: u32 = 58;
|
||||||
|
pub const ATOM_POINT_SIZE: u32 = 59;
|
||||||
|
pub const ATOM_RESOLUTION: u32 = 60;
|
||||||
|
pub const ATOM_COPYRIGHT: u32 = 61;
|
||||||
|
pub const ATOM_NOTICE: u32 = 62;
|
||||||
|
pub const ATOM_FONT_NAME: u32 = 63;
|
||||||
|
pub const ATOM_FAMILY_NAME: u32 = 64;
|
||||||
|
pub const ATOM_FULL_NAME: u32 = 65;
|
||||||
|
pub const ATOM_CAP_HEIGHT: u32 = 66;
|
||||||
|
pub const ATOM_WM_CLASS: u32 = 67;
|
||||||
|
pub const ATOM_WM_TRANSIENT_FOR: u32 = 68;
|
||||||
|
|
||||||
pub const EVENT_MASK_NO_EVENT: u32 = 0;
|
pub const EVENT_MASK_NO_EVENT: u32 = 0;
|
||||||
pub const EVENT_MASK_KEY_PRESS: u32 = 1;
|
pub const EVENT_MASK_KEY_PRESS: u32 = 1;
|
||||||
|
|
@ -111,3 +177,77 @@ pub const COMPOSITE_REDIRECT_MANUAL: u8 = 1;
|
||||||
|
|
||||||
pub const RENDER_PICT_TYPE_INDEXED: u8 = 0;
|
pub const RENDER_PICT_TYPE_INDEXED: u8 = 0;
|
||||||
pub const RENDER_PICT_TYPE_DIRECT: u8 = 1;
|
pub const RENDER_PICT_TYPE_DIRECT: u8 = 1;
|
||||||
|
|
||||||
|
pub const PROP_MODE_REPLACE: u8 = 0;
|
||||||
|
pub const PROP_MODE_PREPEND: u8 = 1;
|
||||||
|
pub const PROP_MODE_APPEND: u8 = 2;
|
||||||
|
|
||||||
|
pub const ICCCM_WM_HINT_INPUT: i32 = 1 << 0;
|
||||||
|
pub const ICCCM_WM_HINT_STATE: i32 = 1 << 1;
|
||||||
|
pub const ICCCM_WM_HINT_ICON_PIXMAP: i32 = 1 << 2;
|
||||||
|
pub const ICCCM_WM_HINT_ICON_WINDOW: i32 = 1 << 3;
|
||||||
|
pub const ICCCM_WM_HINT_ICON_POSITION: i32 = 1 << 4;
|
||||||
|
pub const ICCCM_WM_HINT_ICON_MASK: i32 = 1 << 5;
|
||||||
|
pub const ICCCM_WM_HINT_WINDOW_GROUP: i32 = 1 << 6;
|
||||||
|
pub const ICCCM_WM_HINT_X_URGENCY: i32 = 1 << 8;
|
||||||
|
|
||||||
|
pub const ICCCM_SIZE_HINT_US_POSITION: u32 = 1 << 0;
|
||||||
|
pub const ICCCM_SIZE_HINT_US_SIZE: u32 = 1 << 1;
|
||||||
|
pub const ICCCM_SIZE_HINT_P_POSITION: u32 = 1 << 2;
|
||||||
|
pub const ICCCM_SIZE_HINT_P_SIZE: u32 = 1 << 3;
|
||||||
|
pub const ICCCM_SIZE_HINT_P_MIN_SIZE: u32 = 1 << 4;
|
||||||
|
pub const ICCCM_SIZE_HINT_P_MAX_SIZE: u32 = 1 << 5;
|
||||||
|
pub const ICCCM_SIZE_HINT_P_RESIZE_INC: u32 = 1 << 6;
|
||||||
|
pub const ICCCM_SIZE_HINT_P_ASPECT: u32 = 1 << 7;
|
||||||
|
pub const ICCCM_SIZE_HINT_BASE_SIZE: u32 = 1 << 8;
|
||||||
|
pub const ICCCM_SIZE_HINT_P_WIN_GRAVITY: u32 = 1 << 9;
|
||||||
|
|
||||||
|
pub const MWM_HINTS_FLAGS_FIELD: usize = 0;
|
||||||
|
pub const MWM_HINTS_DECORATIONS_FIELD: usize = 2;
|
||||||
|
pub const MWM_HINTS_DECORATIONS: u32 = 1 << 1;
|
||||||
|
pub const MWM_DECOR_ALL: u32 = 1 << 0;
|
||||||
|
pub const MWM_DECOR_BORDER: u32 = 1 << 1;
|
||||||
|
pub const MWM_DECOR_TITLE: u32 = 1 << 3;
|
||||||
|
|
||||||
|
pub const RES_CLIENT_ID_MASK_CLIENT_XID: u32 = 1;
|
||||||
|
pub const RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID: u32 = 2;
|
||||||
|
|
||||||
|
pub const INPUT_FOCUS_NONE: u8 = 0;
|
||||||
|
pub const INPUT_FOCUS_POINTER_ROOT: u8 = 1;
|
||||||
|
pub const INPUT_FOCUS_PARENT: u8 = 2;
|
||||||
|
pub const INPUT_FOCUS_FOLLOW_KEYBOARD: u8 = 3;
|
||||||
|
|
||||||
|
pub const NOTIFY_MODE_NORMAL :u8 = 0;
|
||||||
|
pub const NOTIFY_MODE_GRAB :u8 = 1;
|
||||||
|
pub const NOTIFY_MODE_UNGRAB :u8 = 2;
|
||||||
|
pub const NOTIFY_MODE_WHILE_GRABBED :u8 = 3;
|
||||||
|
|
||||||
|
pub const NOTIFY_DETAIL_ANCESTOR : u8 = 0;
|
||||||
|
pub const NOTIFY_DETAIL_VIRTUAL : u8 = 1;
|
||||||
|
pub const NOTIFY_DETAIL_INFERIOR : u8 = 2;
|
||||||
|
pub const NOTIFY_DETAIL_NONLINEAR : u8 = 3;
|
||||||
|
pub const NOTIFY_DETAIL_NONLINEAR_VIRTUAL : u8 = 4;
|
||||||
|
pub const NOTIFY_DETAIL_POINTER : u8 = 5;
|
||||||
|
pub const NOTIFY_DETAIL_POINTER_ROOT : u8 = 6;
|
||||||
|
pub const NOTIFY_DETAIL_NONE : u8 = 7;
|
||||||
|
|
||||||
|
pub const ICCCM_WM_STATE_WITHDRAWN : u32 = 0;
|
||||||
|
pub const ICCCM_WM_STATE_NORMAL : u32 = 1;
|
||||||
|
pub const ICCCM_WM_STATE_ICONIC : u32 = 3;
|
||||||
|
|
||||||
|
pub const _NET_WM_STATE_REMOVE: u32 = 0;
|
||||||
|
pub const _NET_WM_STATE_ADD: u32 = 1;
|
||||||
|
pub const _NET_WM_STATE_TOGGLE: u32 = 2;
|
||||||
|
|
||||||
|
pub const _NET_WM_MOVERESIZE_SIZE_TOPLEFT : u32 = 0;
|
||||||
|
pub const _NET_WM_MOVERESIZE_SIZE_TOP : u32 = 1;
|
||||||
|
pub const _NET_WM_MOVERESIZE_SIZE_TOPRIGHT : u32 = 2;
|
||||||
|
pub const _NET_WM_MOVERESIZE_SIZE_RIGHT : u32 = 3;
|
||||||
|
pub const _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT : u32 = 4;
|
||||||
|
pub const _NET_WM_MOVERESIZE_SIZE_BOTTOM : u32 = 5;
|
||||||
|
pub const _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT : u32 = 6;
|
||||||
|
pub const _NET_WM_MOVERESIZE_SIZE_LEFT : u32 = 7;
|
||||||
|
pub const _NET_WM_MOVERESIZE_MOVE : u32 = 8;
|
||||||
|
pub const _NET_WM_MOVERESIZE_SIZE_KEYBOARD : u32 = 9;
|
||||||
|
pub const _NET_WM_MOVERESIZE_MOVE_KEYBOARD : u32 = 10;
|
||||||
|
pub const _NET_WM_MOVERESIZE_CANCEL : u32 = 11;
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,14 @@ impl<'a> Formatter<'a> {
|
||||||
self.buf.extend_from_slice(&BUF[..pad]);
|
self.buf.extend_from_slice(&BUF[..pad]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pad_to(&mut self, size: usize) {
|
||||||
|
static BUF: [u8; 8] = [0; 8];
|
||||||
|
while self.buf.len() < size {
|
||||||
|
let len = (size - self.buf.len()).min(8);
|
||||||
|
self.buf.extend_from_slice(&BUF[..len]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn align(&mut self, alignment: usize) {
|
pub fn align(&mut self, alignment: usize) {
|
||||||
static BUF: [u8; 8] = [0; 8];
|
static BUF: [u8; 8] = [0; 8];
|
||||||
let len = self.buf.len().wrapping_neg() & (alignment - 1);
|
let len = self.buf.len().wrapping_neg() & (alignment - 1);
|
||||||
|
|
|
||||||
|
|
@ -202,6 +202,7 @@ impl Incoming {
|
||||||
ext,
|
ext,
|
||||||
code,
|
code,
|
||||||
buf: mem::take(&mut msg_buf),
|
buf: mem::take(&mut msg_buf),
|
||||||
|
serial,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ pub trait Request<'a>: Message<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait XEvent<'a>: Message<'a> {
|
pub trait XEvent<'a>: Message<'a> {
|
||||||
|
const EXTENSION: Option<usize>;
|
||||||
const OPCODE: u16;
|
const OPCODE: u16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,3 +117,38 @@ unsafe impl<'a> Message<'a> for Rc<OwnedFd> {
|
||||||
parser.read_fd()
|
parser.read_fd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(super) struct SendEvent {
|
||||||
|
pub propagate: u8,
|
||||||
|
pub destination: u32,
|
||||||
|
pub event_mask: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<'a> Message<'a> for SendEvent {
|
||||||
|
type Generic<'b> = SendEvent;
|
||||||
|
const IS_POD: bool = false;
|
||||||
|
const HAS_FDS: bool = false;
|
||||||
|
|
||||||
|
fn serialize(&self, formatter: &mut Formatter) {
|
||||||
|
{
|
||||||
|
let propagate_bytes = self.propagate.to_ne_bytes();
|
||||||
|
let destination_bytes = self.destination.to_ne_bytes();
|
||||||
|
let event_mask_bytes = self.event_mask.to_ne_bytes();
|
||||||
|
formatter.write_bytes(&[
|
||||||
|
25,
|
||||||
|
propagate_bytes[0],
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
destination_bytes[0],
|
||||||
|
destination_bytes[1],
|
||||||
|
destination_bytes[2],
|
||||||
|
destination_bytes[3],
|
||||||
|
event_mask_bytes[0],
|
||||||
|
event_mask_bytes[1],
|
||||||
|
event_mask_bytes[2],
|
||||||
|
event_mask_bytes[3],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ mod xwm;
|
||||||
|
|
||||||
use crate::client::ClientError;
|
use crate::client::ClientError;
|
||||||
use crate::forker::ForkerProxy;
|
use crate::forker::ForkerProxy;
|
||||||
use crate::ifs::wl_surface::xwindow::Xwindow;
|
use crate::ifs::wl_surface::xwindow::{Xwindow, XwindowData};
|
||||||
use crate::ifs::wl_surface::WlSurface;
|
use crate::ifs::wl_surface::WlSurface;
|
||||||
use crate::utils::oserror::OsError;
|
use crate::utils::oserror::OsError;
|
||||||
use crate::utils::tri::Try;
|
use crate::utils::tri::Try;
|
||||||
|
|
@ -60,16 +60,12 @@ enum XWaylandError {
|
||||||
SelectRootEvents(#[source] XconError),
|
SelectRootEvents(#[source] XconError),
|
||||||
#[error("Could not create the WM window")]
|
#[error("Could not create the WM window")]
|
||||||
CreateXWindow(#[source] XconError),
|
CreateXWindow(#[source] XconError),
|
||||||
#[error("Could not acquire a selection")]
|
|
||||||
SelectionOwner(#[source] XconError),
|
|
||||||
#[error("Could not set the cursor of the root window")]
|
#[error("Could not set the cursor of the root window")]
|
||||||
SetCursor(#[source] XconError),
|
SetCursor(#[source] XconError),
|
||||||
#[error("composite_redirect_subwindows failed")]
|
#[error("composite_redirect_subwindows failed")]
|
||||||
CompositeRedirectSubwindows(#[source] XconError),
|
CompositeRedirectSubwindows(#[source] XconError),
|
||||||
#[error("Could not spawn the Xwayland client")]
|
#[error("Could not spawn the Xwayland client")]
|
||||||
SpawnClient(#[source] ClientError),
|
SpawnClient(#[source] ClientError),
|
||||||
#[error("Could not map a window")]
|
|
||||||
MapWindow(#[source] XconError),
|
|
||||||
#[error("An unspecified XconError occurred")]
|
#[error("An unspecified XconError occurred")]
|
||||||
XconError(#[from] XconError),
|
XconError(#[from] XconError),
|
||||||
}
|
}
|
||||||
|
|
@ -263,4 +259,5 @@ pub enum XWaylandEvent {
|
||||||
SurfaceCreated(Rc<WlSurface>),
|
SurfaceCreated(Rc<WlSurface>),
|
||||||
SurfaceDestroyed(WlSurfaceId),
|
SurfaceDestroyed(WlSurfaceId),
|
||||||
Configure(Rc<Xwindow>),
|
Configure(Rc<Xwindow>),
|
||||||
|
Activate(Rc<XwindowData>),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1321
src/xwayland/xwm.rs
1321
src/xwayland/xwm.rs
File diff suppressed because it is too large
Load diff
22
wire-xcon/res.txt
Normal file
22
wire-xcon/res.txt
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
ext "X-Resource"
|
||||||
|
|
||||||
|
struct ResClientIdSpec {
|
||||||
|
client: u32,
|
||||||
|
mask: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ResClientIdValue {
|
||||||
|
spec: ResClientIdSpec,
|
||||||
|
length: u32 = mul(len(value), literal(4)),
|
||||||
|
value: list(u32, div(field(length), literal(4))),
|
||||||
|
}
|
||||||
|
|
||||||
|
request ResQueryClientIds = 4 (
|
||||||
|
num_specs: u32 = len(specs),
|
||||||
|
specs: list(ResClientIdSpec, field(num_specs)),
|
||||||
|
) {
|
||||||
|
@pad 1,
|
||||||
|
num_ids: u32 = len(ids),
|
||||||
|
@pad 20,
|
||||||
|
ids: list(ResClientIdValue, field(num_ids)),
|
||||||
|
}
|
||||||
|
|
@ -244,6 +244,22 @@ request ChangeProperty = 18 (
|
||||||
data: list(u8, mul(field(data_len), div(field(format), literal(8)))),
|
data: list(u8, mul(field(data_len), div(field(format), literal(8)))),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
request GetProperty = 20 (
|
||||||
|
delete: u8,
|
||||||
|
window: u32,
|
||||||
|
property: u32,
|
||||||
|
ty: u32,
|
||||||
|
long_offset: u32,
|
||||||
|
long_length: u32,
|
||||||
|
) {
|
||||||
|
format: u8,
|
||||||
|
ty: u32,
|
||||||
|
bytes_after: u32,
|
||||||
|
value_len: u32 = div(mul(len(data), literal(8)), field(format)),
|
||||||
|
@pad 12,
|
||||||
|
data: list(u8, mul(field(value_len), div(field(format), literal(8)))),
|
||||||
|
}
|
||||||
|
|
||||||
request InternAtom = 16 (
|
request InternAtom = 16 (
|
||||||
only_if_exists: u8,
|
only_if_exists: u8,
|
||||||
name_len: u16 = len(name),
|
name_len: u16 = len(name),
|
||||||
|
|
@ -338,3 +354,70 @@ event ClientMessage = 33 {
|
||||||
ty: u32,
|
ty: u32,
|
||||||
data: list(u32, literal(5)),
|
data: list(u32, literal(5)),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
request GetGeometry = 14 (
|
||||||
|
@pad 1,
|
||||||
|
drawable: u32,
|
||||||
|
) {
|
||||||
|
depth: u8,
|
||||||
|
root: u32,
|
||||||
|
x: i16,
|
||||||
|
y: i16,
|
||||||
|
width: u16,
|
||||||
|
height: u16,
|
||||||
|
border_width: u16,
|
||||||
|
@pad 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
event PropertyNotify = 28 {
|
||||||
|
@pad 1,
|
||||||
|
window: u32,
|
||||||
|
atom: u32,
|
||||||
|
time: u32,
|
||||||
|
state: u8,
|
||||||
|
@pad 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
request GetAtomName = 17 (
|
||||||
|
@pad 1,
|
||||||
|
atom: u32,
|
||||||
|
) {
|
||||||
|
@pad 1,
|
||||||
|
name_len: u16 = len(name),
|
||||||
|
@pad 22,
|
||||||
|
name: str(field(name_len)),
|
||||||
|
}
|
||||||
|
|
||||||
|
request SetInputFocus = 42 (
|
||||||
|
revert_to: u8,
|
||||||
|
focus: u32,
|
||||||
|
time: u32,
|
||||||
|
);
|
||||||
|
|
||||||
|
event FocusIn = 9 {
|
||||||
|
detail: u8,
|
||||||
|
event: u32,
|
||||||
|
mode: u8,
|
||||||
|
@pad 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
request KillClient = 113 (
|
||||||
|
@pad 1,
|
||||||
|
resource: u32,
|
||||||
|
);
|
||||||
|
|
||||||
|
event UnmapNotify = 18 {
|
||||||
|
@pad 1,
|
||||||
|
event: u32,
|
||||||
|
window: u32,
|
||||||
|
from_configure: u8,
|
||||||
|
@pad 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
event MapNotify = 19 {
|
||||||
|
@pad 1,
|
||||||
|
event: u32,
|
||||||
|
window: u32,
|
||||||
|
override_redirect: u8,
|
||||||
|
@pad 3,
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue