1
0
Fork 0
forked from wry/wry

autocommit 2022-04-08 23:02:38 CEST

This commit is contained in:
Julian Orth 2022-04-08 23:02:38 +02:00
parent 0bd9a70e69
commit 21e2216ce5
40 changed files with 587 additions and 255 deletions

View file

@ -21,6 +21,7 @@ use jay_config::{
Command, Command,
Direction::{Down, Left, Right, Up}, Direction::{Down, Left, Right, Up},
}; };
use jay_config::keyboard::syms::SYM_c;
const MOD: Modifiers = ALT; const MOD: Modifiers = ALT;
@ -44,6 +45,8 @@ fn configure_seat(s: Seat) {
s.bind(MOD | SYM_f, move || s.focus_parent()); s.bind(MOD | SYM_f, move || s.focus_parent());
s.bind(MOD | SHIFT | SYM_c, move || s.close());
s.bind(MOD | SHIFT | SYM_f, move || s.toggle_floating()); s.bind(MOD | SHIFT | SYM_f, move || s.toggle_floating());
s.bind(SYM_Super_L, || Command::new("alacritty").spawn()); s.bind(SYM_Super_L, || Command::new("alacritty").spawn());

View file

@ -296,6 +296,10 @@ impl Client {
self.send(&ClientMessage::CreateSplit { seat, axis }); self.send(&ClientMessage::CreateSplit { seat, axis });
} }
pub fn close(&self, seat: Seat) {
self.send(&ClientMessage::Close { seat });
}
pub fn focus_parent(&self, seat: Seat) { pub fn focus_parent(&self, seat: Seat) {
self.send(&ClientMessage::FocusParent { seat }); self.send(&ClientMessage::FocusParent { seat });
} }

View file

@ -146,6 +146,9 @@ pub enum ClientMessage<'a> {
seat: Seat, seat: Seat,
axis: Axis, axis: Axis,
}, },
Close {
seat: Seat,
},
FocusParent { FocusParent {
seat: Seat, seat: Seat,
}, },

View file

@ -117,6 +117,10 @@ impl Seat {
get!().focus_parent(self); get!().focus_parent(self);
} }
pub fn close(self) {
get!().close(self);
}
pub fn toggle_floating(self) { pub fn toggle_floating(self) {
get!().toggle_floating(self); get!().toggle_floating(self);
} }

View file

@ -25,6 +25,7 @@ pub enum LogLevel {
#[derive(Encode, Decode, Copy, Clone, Debug, Eq, PartialEq)] #[derive(Encode, Decode, Copy, Clone, Debug, Eq, PartialEq)]
pub enum Direction { pub enum Direction {
Unspecified,
Left, Left,
Down, Down,
Up, Up,

View file

@ -1,5 +1,5 @@
use { use {
crate::{video::drm::ConnectorType, fixed::Fixed}, crate::{fixed::Fixed, video::drm::ConnectorType},
std::{ std::{
fmt::{Debug, Display, Formatter}, fmt::{Debug, Display, Formatter},
rc::Rc, rc::Rc,

View file

@ -11,7 +11,6 @@ use {
}, },
backends::metal::video::{MetalDrmDevice, PendingDrmDevice}, backends::metal::video::{MetalDrmDevice, PendingDrmDevice},
dbus::DbusError, dbus::DbusError,
video::{drm::DrmError, gbm::GbmError},
libinput::{ libinput::{
consts::{ consts::{
AccelProfile, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE, AccelProfile, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
@ -35,6 +34,7 @@ use {
smallmap::SmallMap, smallmap::SmallMap,
syncqueue::SyncQueue, syncqueue::SyncQueue,
}, },
video::{drm::DrmError, gbm::GbmError},
}, },
std::{ std::{
cell::{Cell, RefCell}, cell::{Cell, RefCell},

View file

@ -7,9 +7,9 @@ use {
MetalBackend, MetalDevice, MetalError, MetalInputDevice, MetalBackend, MetalDevice, MetalError, MetalInputDevice,
}, },
dbus::TRUE, dbus::TRUE,
video::drm::DrmMaster,
udev::UdevDevice, udev::UdevDevice,
utils::{errorfmt::ErrorFmt, nonblock::set_nonblock}, utils::{errorfmt::ErrorFmt, nonblock::set_nonblock},
video::drm::DrmMaster,
wire_dbus::org::freedesktop::login1::session::{PauseDevice, ResumeDevice}, wire_dbus::org::freedesktop::login1::session::{PauseDevice, ResumeDevice},
}, },
bstr::ByteSlice, bstr::ByteSlice,

View file

@ -5,6 +5,14 @@ use {
BackendEvent, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId, MonitorInfo, BackendEvent, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId, MonitorInfo,
}, },
backends::metal::{DrmId, MetalBackend, MetalError}, backends::metal::{DrmId, MetalBackend, MetalError},
edid::Descriptor,
format::{Format, XRGB8888},
render::{Framebuffer, RenderContext},
state::State,
utils::{
bitflags::BitflagsExt, clonecell::CloneCell, debug_fn::debug_fn, errorfmt::ErrorFmt,
numcell::NumCell, oserror::OsError, syncqueue::SyncQueue,
},
video::{ video::{
drm::{ drm::{
drm_mode_modeinfo, Change, ConnectorStatus, ConnectorType, DrmBlob, DrmConnector, drm_mode_modeinfo, Change, ConnectorStatus, ConnectorType, DrmBlob, DrmConnector,
@ -16,14 +24,6 @@ use {
gbm::{GbmDevice, GBM_BO_USE_RENDERING, GBM_BO_USE_SCANOUT}, gbm::{GbmDevice, GBM_BO_USE_RENDERING, GBM_BO_USE_SCANOUT},
ModifiedFormat, INVALID_MODIFIER, ModifiedFormat, INVALID_MODIFIER,
}, },
edid::Descriptor,
format::{Format, XRGB8888},
render::{Framebuffer, RenderContext},
state::State,
utils::{
bitflags::BitflagsExt, clonecell::CloneCell, debug_fn::debug_fn, errorfmt::ErrorFmt,
numcell::NumCell, oserror::OsError, syncqueue::SyncQueue,
},
}, },
ahash::{AHashMap, AHashSet}, ahash::{AHashMap, AHashSet},
bstr::{BString, ByteSlice}, bstr::{BString, ByteSlice},
@ -280,10 +280,10 @@ fn create_connector(
if let Some(d) = descriptor { if let Some(d) = descriptor {
match d { match d {
Descriptor::DisplayProductSerialNumber(s) => { Descriptor::DisplayProductSerialNumber(s) => {
serial_number = s.to_string(); serial_number = s.clone();
} }
Descriptor::DisplayProductName(s) => { Descriptor::DisplayProductName(s) => {
name = s.to_string(); name = s.clone();
} }
_ => {} _ => {}
} }

View file

@ -6,11 +6,6 @@ use {
InputDevice, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId, InputEvent, InputDevice, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId, InputEvent,
KeyState, Mode, MonitorInfo, ScrollAxis, KeyState, Mode, MonitorInfo, ScrollAxis,
}, },
video::{
drm::{ConnectorType, Drm, DrmError},
gbm::{GbmDevice, GbmError, GBM_BO_USE_RENDERING},
ModifiedFormat, INVALID_MODIFIER,
},
fixed::Fixed, fixed::Fixed,
format::XRGB8888, format::XRGB8888,
render::{Framebuffer, RenderContext, RenderError}, render::{Framebuffer, RenderContext, RenderError},
@ -19,6 +14,11 @@ use {
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell, clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell,
queue::AsyncQueue, syncqueue::SyncQueue, queue::AsyncQueue, syncqueue::SyncQueue,
}, },
video::{
drm::{ConnectorType, Drm, DrmError},
gbm::{GbmDevice, GbmError, GBM_BO_USE_RENDERING},
ModifiedFormat, INVALID_MODIFIER,
},
wire_xcon::{ wire_xcon::{
ChangeProperty, ChangeWindowAttributes, ConfigureNotify, CreateCursor, CreatePixmap, ChangeProperty, ChangeWindowAttributes, ConfigureNotify, CreateCursor, CreatePixmap,
CreateWindow, CreateWindowValues, DestroyNotify, Dri3Open, Dri3PixmapFromBuffer, CreateWindow, CreateWindowValues, DestroyNotify, Dri3Open, Dri3PixmapFromBuffer,

View file

@ -132,6 +132,12 @@ impl ConfigProxyHandler {
Ok(()) Ok(())
} }
fn handle_close(&self, seat: Seat) -> Result<(), CphError> {
let seat = self.get_seat(seat)?;
seat.close();
Ok(())
}
fn handle_focus(&self, seat: Seat, direction: Direction) -> Result<(), CphError> { fn handle_focus(&self, seat: Seat, direction: Direction) -> Result<(), CphError> {
let seat = self.get_seat(seat)?; let seat = self.get_seat(seat)?;
seat.move_focus(direction); seat.move_focus(direction);
@ -763,6 +769,9 @@ impl ConfigProxyHandler {
ClientMessage::ConnectorSetPosition { connector, x, y } => self ClientMessage::ConnectorSetPosition { connector, x, y } => self
.handle_connector_set_position(connector, x, y) .handle_connector_set_position(connector, x, y)
.wrn("connector_set_position")?, .wrn("connector_set_position")?,
ClientMessage::Close { seat } => self
.handle_close(seat)
.wrn("close")?,
} }
Ok(()) Ok(())
} }

View file

@ -347,9 +347,9 @@ pub struct DetailedTimingDescriptor {
pub enum Descriptor { pub enum Descriptor {
Unknown(u8), Unknown(u8),
DetailedTimingDescriptor(DetailedTimingDescriptor), DetailedTimingDescriptor(DetailedTimingDescriptor),
DisplayProductSerialNumber(BString), DisplayProductSerialNumber(String),
AlphanumericDataString(BString), AlphanumericDataString(String),
DisplayProductName(BString), DisplayProductName(String),
DisplayRangeLimitsAndAdditionalTiming(DisplayRangeLimitsAndAdditionalTiming), DisplayRangeLimitsAndAdditionalTiming(DisplayRangeLimitsAndAdditionalTiming),
EstablishedTimings3(EstablishedTimings3), EstablishedTimings3(EstablishedTimings3),
ColorManagementData(ColorManagementData), ColorManagementData(ColorManagementData),
@ -880,11 +880,15 @@ impl<'a> EdidParser<'a> {
let _ctx = self.push_ctx(EdidParseContext::Descriptor); let _ctx = self.push_ctx(EdidParseContext::Descriptor);
let b = self.read_n::<18>()?; let b = self.read_n::<18>()?;
let str = || { let str = || {
let s = &b[5..]; let mut s = &b[5..];
match s.find_byte(b'\n') { if let Some(n) = s.find_byte(b'\n') {
Some(n) => s[..n].as_bstr().to_owned(), s = &s[..n];
_ => s.as_bstr().to_owned(), };
let mut res = String::new();
for &b in s {
res.push_str(CP437[b as usize]);
} }
res
}; };
let res = if (b[0], b[1]) == (0, 0) { let res = if (b[0], b[1]) == (0, 0) {
match b[3] { match b[3] {
@ -1079,3 +1083,20 @@ pub fn parse(data: &[u8]) -> Result<EdidFile, EdidError> {
}; };
parser.parse() parser.parse()
} }
const CP437: &[&str] = &[
"\u{0}", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "§", "", "", "", "", "", "", "", "", "", "", " ", "!", "\"", "#", "$",
"%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", ":", ";", "<", "=", ">", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
"K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]",
"^", "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p",
"q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "", "Ç", "ü", "é", "â",
"ä", "à", "å", "ç", "ê", "ë", "è", "ï", "î", "ì", "Ä", "Å", "É", "æ", "Æ", "ô", "ö", "ò", "û",
"ù", "ÿ", "Ö", "Ü", "¢", "£", "¥", "", "ƒ", "á", "í", "ó", "ú", "ñ", "Ñ", "ª", "º", "¿", "",
"¬", "½", "¼", "¡", "«", "»", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "α", "ß", "Γ",
"π", "Σ", "σ", "µ", "τ", "Φ", "Θ", "Ω", "δ", "", "φ", "ε", "", "", "±", "", "", "", "",
"÷", "", "°", "", "·", "", "", "²", "", "\u{a0}",
];

View file

@ -1,16 +1,16 @@
use { use {
crate::{ crate::{
client::{Client, ClientError}, client::{Client, ClientError},
video::{
dma::{DmaBuf, DmaBufPlane},
INVALID_MODIFIER,
},
globals::{Global, GlobalName}, globals::{Global, GlobalName},
ifs::wl_buffer::WlBuffer, ifs::wl_buffer::WlBuffer,
leaks::Tracker, leaks::Tracker,
object::Object, object::Object,
render::RenderError, render::RenderError,
utils::buffd::{MsgParser, MsgParserError}, utils::buffd::{MsgParser, MsgParserError},
video::{
dma::{DmaBuf, DmaBufPlane},
INVALID_MODIFIER,
},
wire::{wl_drm::*, WlDrmId}, wire::{wl_drm::*, WlDrmId},
}, },
bstr::ByteSlice, bstr::ByteSlice,

View file

@ -274,6 +274,11 @@ impl WlSeatGlobal {
} }
} }
pub fn close(self: &Rc<Self>) {
let kb_node = self.keyboard_node.get();
kb_node.close();
}
pub fn move_focus(self: &Rc<Self>, direction: Direction) { pub fn move_focus(self: &Rc<Self>, direction: Direction) {
let kb_node = self.keyboard_node.get(); let kb_node = self.keyboard_node.get();
kb_node.move_focus(self, direction); kb_node.move_focus(self, direction);

View file

@ -81,16 +81,32 @@ impl NodeSeatState {
} }
pub fn release_kb_focus(&self) { pub fn release_kb_focus(&self) {
self.release_kb_focus2(true);
}
fn release_kb_focus2(&self, focus_last: bool) {
while let Some((_, seat)) = self.kb_foci.pop() { while let Some((_, seat)) = self.kb_foci.pop() {
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 focus_last {
seat.focus_node(tl.focus_surface(seat.id)); if let Some(tl) = seat.toplevel_focus_history.last() {
seat.focus_node(tl.focus_surface(seat.id));
}
} }
} }
} }
pub fn for_each_kb_focus<F: FnMut(Rc<WlSeatGlobal>)>(&self, mut f: F) {
self.kb_foci.iter().for_each(|(_, s)| f(s));
}
pub fn destroy_node(&self, node: &dyn Node) { pub fn destroy_node(&self, node: &dyn Node) {
self.destroy_node2(node, true);
}
fn destroy_node2(&self, node: &dyn Node, focus_last: bool) {
// NOTE: Also called by set_visible(false)
while let Some((_, seat)) = self.grabs.pop() { while let Some((_, seat)) = self.grabs.pop() {
seat.pointer_owner.revert_to_default(&seat); seat.pointer_owner.revert_to_default(&seat);
} }
@ -109,7 +125,16 @@ impl NodeSeatState {
} }
seat.state.tree_changed(); seat.state.tree_changed();
} }
self.release_kb_focus(); self.release_kb_focus2(focus_last);
}
pub fn set_visible(&self, node: &dyn Node, visible: bool) {
if !visible {
if !self.kb_foci.is_empty() {
node.active_changed(false);
}
self.destroy_node2(node, false);
}
} }
} }

View file

@ -84,6 +84,7 @@ pub struct WlSurface {
pub id: WlSurfaceId, pub id: WlSurfaceId,
pub node_id: SurfaceNodeId, pub node_id: SurfaceNodeId,
pub client: Rc<Client>, pub client: Rc<Client>,
visible: Cell<bool>,
role: Cell<SurfaceRole>, role: Cell<SurfaceRole>,
pending: PendingState, pending: PendingState,
input_region: Cell<Option<Rc<Region>>>, input_region: Cell<Option<Rc<Region>>>,
@ -199,6 +200,7 @@ impl WlSurface {
id, id,
node_id: client.state.node_ids.next(), node_id: client.state.node_ids.next(),
client: client.clone(), client: client.clone(),
visible: Cell::new(false),
role: Cell::new(SurfaceRole::None), role: Cell::new(SurfaceRole::None),
pending: Default::default(), pending: Default::default(),
input_region: Cell::new(None), input_region: Cell::new(None),
@ -624,6 +626,27 @@ impl Node for WlSurface {
self.node_id.into() self.node_id.into()
} }
fn close(&self) {
if let Some(tl) = self.toplevel.get() {
tl.close();
}
}
fn visible(&self) -> bool {
self.visible.get()
}
fn set_visible(&self, visible: bool) {
self.visible.set(visible);
let children = self.children.borrow_mut();
if let Some(children) = children.deref() {
for child in children.subsurfaces.values() {
child.surface.set_visible(visible);
}
}
self.seat_state.set_visible(self, visible);
}
fn seat_state(&self) -> &NodeSeatState { fn seat_state(&self) -> &NodeSeatState {
&self.seat_state &self.seat_state
} }

View file

@ -288,6 +288,15 @@ impl Node for XdgPopup {
visitor.visit_surface(&self.xdg.surface); visitor.visit_surface(&self.xdg.surface);
} }
fn visible(&self) -> bool {
self.xdg.surface.visible.get()
}
fn set_visible(&self, visible: bool) {
self.xdg.surface.set_visible(visible);
self.xdg.seat_state.set_visible(self, visible);
}
fn get_workspace(&self) -> Option<Rc<WorkspaceNode>> { fn get_workspace(&self) -> Option<Rc<WorkspaceNode>> {
self.xdg.workspace.get() self.xdg.workspace.get()
} }

View file

@ -143,6 +143,12 @@ impl XdgToplevel {
self.send_configure(width, height) self.send_configure(width, height)
} }
fn send_close(&self) {
self.xdg.surface.client.event(Close {
self_id: self.id,
});
}
fn send_configure(&self, width: i32, height: i32) { fn send_configure(&self, width: i32, height: i32) {
let states: Vec<_> = self.states.borrow().iter().copied().collect(); let states: Vec<_> = self.states.borrow().iter().copied().collect();
self.xdg.surface.client.event(Configure { self.xdg.surface.client.event(Configure {
@ -384,6 +390,15 @@ impl Node for XdgToplevel {
visitor.visit_surface(&self.xdg.surface); visitor.visit_surface(&self.xdg.surface);
} }
fn visible(&self) -> bool {
self.xdg.surface.visible.get()
}
fn set_visible(&self, visible: bool) {
self.xdg.surface.set_visible(visible);
self.xdg.seat_state.set_visible(self, visible);
}
fn get_workspace(&self) -> Option<Rc<WorkspaceNode>> { fn get_workspace(&self) -> Option<Rc<WorkspaceNode>> {
self.xdg.workspace.get() self.xdg.workspace.get()
} }
@ -508,6 +523,10 @@ impl ToplevelNode for XdgToplevel {
self.map_floating(&ws); self.map_floating(&ws);
} }
} }
fn close(&self) {
self.send_close();
}
} }
impl XdgSurfaceExt for XdgToplevel { impl XdgSurfaceExt for XdgToplevel {
@ -546,12 +565,12 @@ impl XdgSurfaceExt for XdgToplevel {
} }
} }
} }
{ // {
let seats = surface.client.state.globals.lock_seats(); // let seats = surface.client.state.globals.lock_seats();
for seat in seats.values() { // for seat in seats.values() {
seat.focus_toplevel(self.clone()); // seat.focus_toplevel(self.clone());
} // }
} // }
surface.client.state.tree_changed(); surface.client.state.tree_changed();
} }
} }

View file

@ -1,4 +1,3 @@
use std::ops::Not;
use { use {
crate::{ crate::{
client::Client, client::Client,
@ -27,7 +26,7 @@ use {
jay_config::Direction, jay_config::Direction,
std::{ std::{
cell::{Cell, RefCell}, cell::{Cell, RefCell},
ops::{Deref}, ops::{Deref, Not},
rc::Rc, rc::Rc,
}, },
thiserror::Error, thiserror::Error,
@ -142,7 +141,6 @@ pub struct Xwindow {
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 toplevel_data: ToplevelData, pub toplevel_data: ToplevelData,
} }
@ -219,7 +217,6 @@ impl Xwindow {
events: events.clone(), events: events.clone(),
workspace: Default::default(), workspace: Default::default(),
display_link: Default::default(), display_link: Default::default(),
display_xlink: Default::default(),
toplevel_data: Default::default(), toplevel_data: Default::default(),
} }
} }
@ -279,8 +276,6 @@ impl Xwindow {
Change::Map if self.data.info.override_redirect.get() => { Change::Map if self.data.info.override_redirect.get() => {
*self.display_link.borrow_mut() = *self.display_link.borrow_mut() =
Some(self.data.state.root.stacked.add_last(self.clone())); Some(self.data.state.root.stacked.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();
} }
Change::Map if self.data.info.wants_floating.get() => { Change::Map if self.data.info.wants_floating.get() => {
@ -334,13 +329,21 @@ impl Node for Xwindow {
self.id.into() self.id.into()
} }
fn visible(&self) -> bool {
self.surface.visible.get()
}
fn set_visible(&self, visible: bool) {
self.surface.set_visible(visible);
self.seat_state.set_visible(self, visible);
}
fn seat_state(&self) -> &NodeSeatState { fn seat_state(&self) -> &NodeSeatState {
&self.seat_state &self.seat_state
} }
fn destroy_node(&self, _detach: bool) { fn destroy_node(&self, _detach: bool) {
self.toplevel_data.clear(); self.toplevel_data.clear();
self.display_xlink.borrow_mut().take();
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();
@ -449,7 +452,8 @@ impl ToplevelNode for Xwindow {
} }
fn accepts_keyboard_focus(&self) -> bool { fn accepts_keyboard_focus(&self) -> bool {
self.data.info.never_focus.get().not() && self.data.info.input_model.get() != XInputModel::None self.data.info.never_focus.get().not()
&& self.data.info.input_model.get() != XInputModel::None
} }
fn default_surface(&self) -> Rc<WlSurface> { fn default_surface(&self) -> Rc<WlSurface> {
@ -482,6 +486,10 @@ impl ToplevelNode for Xwindow {
.map_floating(self.clone(), extents.width(), extents.height(), &ws); .map_floating(self.clone(), extents.width(), extents.height(), &ws);
} }
} }
fn close(&self) {
self.events.push(XWaylandEvent::Close(self.data.clone()));
}
} }
#[derive(Debug, Error)] #[derive(Debug, Error)]

View file

@ -370,6 +370,10 @@ impl Node for ZwlrLayerSurfaceV1 {
self.surface.clone().visit(visitor); self.surface.clone().visit(visitor);
} }
fn visible(&self) -> bool {
true
}
fn absolute_position(&self) -> Rect { fn absolute_position(&self) -> Rect {
self.pos.get() self.pos.get()
} }

View file

@ -1,10 +1,6 @@
use { use {
crate::{ crate::{
client::ClientError, client::ClientError,
video::{
dma::{DmaBuf, DmaBufPlane},
INVALID_MODIFIER,
},
ifs::{wl_buffer::WlBuffer, zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1}, ifs::{wl_buffer::WlBuffer, zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1},
leaks::Tracker, leaks::Tracker,
object::Object, object::Object,
@ -13,6 +9,10 @@ use {
buffd::{MsgParser, MsgParserError}, buffd::{MsgParser, MsgParserError},
errorfmt::ErrorFmt, errorfmt::ErrorFmt,
}, },
video::{
dma::{DmaBuf, DmaBufPlane},
INVALID_MODIFIER,
},
wire::{zwp_linux_buffer_params_v1::*, WlBufferId, ZwpLinuxBufferParamsV1Id}, wire::{zwp_linux_buffer_params_v1::*, WlBufferId, ZwpLinuxBufferParamsV1Id},
}, },
ahash::AHashMap, ahash::AHashMap,

View file

@ -1,12 +1,12 @@
use { use {
crate::{ crate::{
client::{Client, ClientError}, client::{Client, ClientError},
video::INVALID_MODIFIER,
globals::{Global, GlobalName}, globals::{Global, GlobalName},
ifs::zwp_linux_buffer_params_v1::ZwpLinuxBufferParamsV1, ifs::zwp_linux_buffer_params_v1::ZwpLinuxBufferParamsV1,
leaks::Tracker, leaks::Tracker,
object::Object, object::Object,
utils::buffd::{MsgParser, MsgParserError}, utils::buffd::{MsgParser, MsgParserError},
video::INVALID_MODIFIER,
wire::{zwp_linux_dmabuf_v1::*, ZwpLinuxDmabufV1Id}, wire::{zwp_linux_dmabuf_v1::*, ZwpLinuxDmabufV1Id},
}, },
std::rc::Rc, std::rc::Rc,

View file

@ -45,7 +45,6 @@ mod compositor;
mod config; mod config;
mod cursor; mod cursor;
mod dbus; mod dbus;
mod video;
mod edid; mod edid;
mod event_loop; mod event_loop;
mod fixed; mod fixed;
@ -70,6 +69,7 @@ mod tools;
mod tree; mod tree;
mod udev; mod udev;
mod utils; mod utils;
mod video;
mod wheel; mod wheel;
mod wire; mod wire;
mod wire_dbus; mod wire_dbus;

View file

@ -1,6 +1,5 @@
use { use {
crate::{ crate::{
video::{dma::DmaBuf, drm::Drm, gbm::GbmDevice, INVALID_MODIFIER},
format::{formats, Format}, format::{formats, Format},
render::{ render::{
egl::{ egl::{
@ -27,6 +26,7 @@ use {
sys::{eglInitialize, EGL_PLATFORM_GBM_KHR}, sys::{eglInitialize, EGL_PLATFORM_GBM_KHR},
RenderError, RenderError,
}, },
video::{dma::DmaBuf, drm::Drm, gbm::GbmDevice, INVALID_MODIFIER},
}, },
ahash::AHashMap, ahash::AHashMap,
std::{ptr, rc::Rc}, std::{ptr, rc::Rc},

View file

@ -1,9 +1,5 @@
use { use {
crate::{ crate::{
video::{
dma::DmaBuf,
drm::{Drm, NodeType},
},
format::{Format, XRGB8888}, format::{Format, XRGB8888},
render::{ render::{
egl::{context::EglContext, display::EglDisplay}, egl::{context::EglContext, display::EglDisplay},
@ -13,6 +9,10 @@ use {
renderer::{framebuffer::Framebuffer, image::Image}, renderer::{framebuffer::Framebuffer, image::Image},
RenderError, Texture, RenderError, Texture,
}, },
video::{
dma::DmaBuf,
drm::{Drm, NodeType},
},
}, },
ahash::AHashMap, ahash::AHashMap,
std::{ std::{

View file

@ -25,7 +25,7 @@ use {
}, },
state::State, state::State,
theme::Color, theme::Color,
tree::{ContainerNode, FloatNode, Node, OutputNode, WorkspaceNode}, tree::{ContainerNode, FloatNode, OutputNode, WorkspaceNode},
utils::rc_eq::rc_eq, utils::rc_eq::rc_eq,
}, },
std::{ops::Deref, rc::Rc}, std::{ops::Deref, rc::Rc},
@ -70,23 +70,14 @@ impl Renderer<'_> {
self.render_workspace(&ws, x, y + th); self.render_workspace(&ws, x, y + th);
} }
for stacked in self.state.root.stacked.iter() { for stacked in self.state.root.stacked.iter() {
if let Some(ws) = stacked.get_workspace() { if stacked.visible() {
if ws.visible.get() { let pos = stacked.absolute_position();
let pos = stacked.absolute_position(); if pos.intersects(&opos) {
if pos.intersects(&opos) { let (x, y) = opos.translate(pos.x1(), pos.y1());
let (x, y) = opos.translate(pos.x1(), pos.y1()); stacked.render(self, x, y);
stacked.render(self, x, y);
}
} }
} }
} }
for stacked in self.state.root.xstacked.iter() {
let pos = stacked.absolute_position();
if pos.intersects(&opos) {
let (x, y) = opos.translate(pos.x1(), pos.y1());
stacked.render(self, x, y);
}
}
render_layer!(output.layers[2]); render_layer!(output.layers[2]);
render_layer!(output.layers[3]); render_layer!(output.layers[3]);
} }

View file

@ -74,6 +74,11 @@ pub trait Node {
fn destroy_node(&self, detach: bool); fn destroy_node(&self, detach: bool);
fn visit(self: Rc<Self>, visitor: &mut dyn NodeVisitor); fn visit(self: Rc<Self>, visitor: &mut dyn NodeVisitor);
fn visit_children(&self, visitor: &mut dyn NodeVisitor); fn visit_children(&self, visitor: &mut dyn NodeVisitor);
fn visible(&self) -> bool;
fn set_visible(&self, visible: bool) {
let _ = visible;
}
fn get_workspace(&self) -> Option<Rc<WorkspaceNode>> { fn get_workspace(&self) -> Option<Rc<WorkspaceNode>> {
None None
@ -134,6 +139,10 @@ pub trait Node {
let _ = direction; let _ = direction;
} }
fn close(&self) {
// nothing
}
fn move_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) { fn move_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
let _ = seat; let _ = seat;
let _ = direction; let _ = direction;
@ -144,7 +153,7 @@ pub trait Node {
} }
fn move_focus_from_child( fn move_focus_from_child(
&self, self: Rc<Self>,
seat: &Rc<WlSeatGlobal>, seat: &Rc<WlSeatGlobal>,
child: &dyn Node, child: &dyn Node,
direction: Direction, direction: Direction,

View file

@ -31,6 +31,8 @@ use {
rc::Rc, rc::Rc,
}, },
}; };
use crate::tree::{generic_node_visitor};
use crate::utils::smallmap::SmallMap;
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
@ -102,12 +104,14 @@ pub struct ContainerNode {
compute_render_data_scheduled: Cell<bool>, compute_render_data_scheduled: Cell<bool>,
num_children: NumCell<usize>, num_children: NumCell<usize>,
pub children: LinkedList<ContainerChild>, pub children: LinkedList<ContainerChild>,
focus_history: LinkedList<NodeRef<ContainerChild>>,
child_nodes: RefCell<AHashMap<NodeId, LinkedNode<ContainerChild>>>, child_nodes: RefCell<AHashMap<NodeId, LinkedNode<ContainerChild>>>,
seat_state: NodeSeatState, seat_state: NodeSeatState,
workspace: CloneCell<Rc<WorkspaceNode>>, workspace: CloneCell<Rc<WorkspaceNode>>,
seats: RefCell<AHashMap<SeatId, SeatState>>, seats: RefCell<AHashMap<SeatId, SeatState>>,
state: Rc<State>, state: Rc<State>,
pub render_data: RefCell<ContainerRenderData>, pub render_data: RefCell<ContainerRenderData>,
visible: Cell<bool>,
} }
impl Debug for ContainerNode { impl Debug for ContainerNode {
@ -116,14 +120,17 @@ impl Debug for ContainerNode {
} }
} }
#[derive(Clone)]
pub struct ContainerChild { pub struct ContainerChild {
pub node: Rc<dyn Node>, pub node: Rc<dyn Node>,
pub active: Cell<bool>, pub active: Cell<bool>,
title: RefCell<String>,
pub title_rect: Cell<Rect>,
focus_history: Cell<Option<LinkedNode<NodeRef<ContainerChild>>>>,
// fields below only valid in tabbed layout
pub body: Cell<Rect>, pub body: Cell<Rect>,
pub content: Cell<Rect>, pub content: Cell<Rect>,
factor: Cell<f64>, factor: Cell<f64>,
title: RefCell<String>,
} }
struct SeatState { struct SeatState {
@ -166,11 +173,13 @@ impl ContainerNode {
child.id(), child.id(),
children.add_last(ContainerChild { children.add_last(ContainerChild {
node: child.clone(), node: child.clone(),
active: Cell::new(false), active: Default::default(),
body: Cell::new(Default::default()), body: Default::default(),
content: Cell::new(Default::default()), content: Default::default(),
factor: Cell::new(1.0), factor: Cell::new(1.0),
title: Default::default(), title: Default::default(),
title_rect: Default::default(),
focus_history: Default::default(),
}), }),
); );
let slf = Rc::new(Self { let slf = Rc::new(Self {
@ -193,12 +202,14 @@ impl ContainerNode {
compute_render_data_scheduled: Cell::new(false), compute_render_data_scheduled: Cell::new(false),
num_children: NumCell::new(1), num_children: NumCell::new(1),
children, children,
focus_history: Default::default(),
child_nodes: RefCell::new(child_nodes), child_nodes: RefCell::new(child_nodes),
seat_state: Default::default(), seat_state: Default::default(),
workspace: CloneCell::new(workspace.clone()), workspace: CloneCell::new(workspace.clone()),
seats: RefCell::new(Default::default()), seats: RefCell::new(Default::default()),
state: state.clone(), state: state.clone(),
render_data: Default::default(), render_data: Default::default(),
visible: Cell::new(false),
}); });
child.set_parent(slf.clone()); child.set_parent(slf.clone());
slf slf
@ -254,24 +265,26 @@ impl ContainerNode {
where where
F: FnOnce(ContainerChild) -> LinkedNode<ContainerChild>, F: FnOnce(ContainerChild) -> LinkedNode<ContainerChild>,
{ {
{ let new_ref = {
let mut links = self.child_nodes.borrow_mut(); let mut links = self.child_nodes.borrow_mut();
if links.contains_key(&new.id()) { if links.contains_key(&new.id()) {
log::error!("Tried to add a child to a container that already contains the child"); log::error!("Tried to add a child to a container that already contains the child");
return; return;
} }
links.insert( let link = f(ContainerChild {
new.id(), node: new.clone(),
f(ContainerChild { active: Default::default(),
node: new.clone(), body: Default::default(),
active: Cell::new(false), content: Default::default(),
body: Default::default(), factor: Default::default(),
content: Default::default(), title: Default::default(),
factor: Cell::new(0.0), title_rect: Default::default(),
title: Default::default(), focus_history: Default::default(),
}), });
); let r = link.to_ref();
} links.insert( new.id(), link, );
r
};
new.clone().set_workspace(&self.workspace.get()); new.clone().set_workspace(&self.workspace.get());
new.clone().set_parent(self.clone()); new.clone().set_parent(self.clone());
let num_children = self.num_children.fetch_add(1) + 1; let num_children = self.num_children.fetch_add(1) + 1;
@ -288,6 +301,9 @@ impl ContainerNode {
sum_factors += factor; sum_factors += factor;
} }
self.sum_factors.set(sum_factors); self.sum_factors.set(sum_factors);
if self.mono_child.get().is_some() {
self.activate_child(&new_ref);
}
self.schedule_layout(); self.schedule_layout();
self.cancel_seat_ops(); self.cancel_seat_ops();
} }
@ -332,6 +348,25 @@ impl ContainerNode {
.change_extents(&mb.move_(self.abs_x1.get(), self.abs_y1.get())); .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()));
let th = self.state.theme.title_height.get();
let bw = self.state.theme.border_width.get();
let num_children = self.num_children.get() as i32;
let content_width = self.width.get().sub(bw * (num_children - 1)).max(0);
let width_per_child = content_width / num_children;
let mut rem = content_width % num_children;
let mut pos = 0;
for child in self.children.iter() {
let mut width = width_per_child;
if rem > 0 {
width += 1;
rem -= 1;
}
child
.title_rect
.set(Rect::new_sized(pos, 0, width, th).unwrap());
pos += width + bw;
}
} }
fn perform_split_layout(self: &Rc<Self>) { fn perform_split_layout(self: &Rc<Self>) {
@ -402,7 +437,17 @@ impl ContainerNode {
} }
self.sum_factors.set(1.0); self.sum_factors.set(1.0);
for child in self.children.iter() { for child in self.children.iter() {
let body = child.body.get().move_(self.abs_x1.get(), self.abs_y1.get()); let body = child.body.get();
child.title_rect.set(
Rect::new_sized(
body.x1(),
body.y1() - title_height - 1,
body.width(),
title_height,
)
.unwrap(),
);
let body = body.move_(self.abs_x1.get(), self.abs_y1.get());
child.node.clone().change_extents(&body); child.node.clone().change_extents(&body);
child.position_content(); child.position_content();
} }
@ -567,77 +612,79 @@ impl ContainerNode {
let font = theme.font.borrow_mut(); let font = theme.font.borrow_mut();
let cwidth = self.width.get(); let cwidth = self.width.get();
let cheight = self.height.get(); let cheight = self.height.get();
let num_children = self.num_children.get() as i32;
let ctx = self.state.render_ctx.get(); let ctx = self.state.render_ctx.get();
rd.titles.clear(); rd.titles.clear();
rd.title_rects.clear(); rd.title_rects.clear();
rd.active_title_rects.clear(); rd.active_title_rects.clear();
rd.border_rects.clear(); rd.border_rects.clear();
rd.underline_rects.clear(); rd.underline_rects.clear();
let mut render_title = |title: &str, width: i32, x: i32, y: i32| { let mono = self.mono_child.get().is_some();
if th == 0 || width == 0 || title.is_empty() { let split = self.split.get();
return; for (i, child) in self.children.iter().enumerate() {
let rect = child.title_rect.get();
if i > 0 {
let rect = if mono {
Rect::new_sized(rect.x1() - bw, 0, bw, th)
} else if split == ContainerSplit::Horizontal {
Rect::new_sized(rect.x1() - bw, 0, bw, cheight)
} else {
Rect::new_sized(0, rect.y1() - bw, cwidth, bw)
};
rd.border_rects.push(rect.unwrap());
} }
if let Some(ctx) = &ctx { if child.active.get() {
match text::render(ctx, width, th, &font, title, Color::GREY) { rd.active_title_rects.push(rect);
Ok(t) => rd.titles.push(ContainerTitle { x, y, tex: t }), } else {
Err(e) => { rd.title_rects.push(rect);
log::error!("Could not render title {}: {}", title, ErrorFmt(e)); }
if !mono {
let rect = Rect::new_sized(rect.x1(), rect.y2(), rect.width(), 1).unwrap();
rd.underline_rects.push(rect);
}
'render_title: {
let title = child.title.borrow_mut();
if th == 0 || rect.width() == 0 || title.is_empty() {
break 'render_title;
}
if let Some(ctx) = &ctx {
match text::render(ctx, rect.width(), th, &font, title.deref(), Color::GREY) {
Ok(t) => rd.titles.push(ContainerTitle {
x: rect.x1(),
y: rect.y1(),
tex: t,
}),
Err(e) => {
log::error!("Could not render title {}: {}", title, ErrorFmt(e));
}
} }
} }
} }
}; }
if self.mono_child.get().is_some() { if mono {
let content_width = self.width.get().sub(bw * (num_children - 1)).max(0);
let space_per_child = content_width / num_children;
let mut rem = content_width % num_children;
let mut pos = 0;
for (i, c) in self.children.iter().enumerate() {
if i > 0 {
rd.border_rects
.push(Rect::new_sized(pos - bw, 0, bw, th).unwrap());
}
let mut width = space_per_child;
if rem > 0 {
rem -= 1;
width += 1;
}
let rect = Rect::new_sized(pos, 0, width, th).unwrap();
if c.active.get() {
rd.active_title_rects.push(rect);
} else {
rd.title_rects.push(rect);
}
let title = c.title.borrow_mut();
render_title(&title, width, pos, 0);
pos += width + bw;
}
rd.underline_rects rd.underline_rects
.push(Rect::new_sized(0, th, cwidth, 1).unwrap()); .push(Rect::new_sized(0, th, cwidth, 1).unwrap());
} else { }
let split = self.split.get(); }
for (i, c) in self.children.iter().enumerate() {
let body = c.body.get(); fn activate_child(self: &Rc<Self>, child: &NodeRef<ContainerChild>) {
if i > 0 { if let Some(mc) = self.mono_child.get() {
let rect = if split == ContainerSplit::Horizontal { if mc.node.id() == child.node.id() {
Rect::new_sized(body.x1() - bw, 0, bw, cheight).unwrap() return;
} else {
Rect::new_sized(0, body.y1() - th - 1 - bw, cwidth, bw).unwrap()
};
rd.border_rects.push(rect);
}
let rect =
Rect::new_sized(body.x1(), body.y1() - th - 1, body.width(), th).unwrap();
if c.active.get() {
rd.active_title_rects.push(rect);
} else {
rd.title_rects.push(rect);
}
let rect = Rect::new_sized(body.x1(), body.y1() - 1, body.width(), 1).unwrap();
rd.underline_rects.push(rect);
let title = c.title.borrow_mut();
render_title(&title, body.width(), body.x1(), body.y1() - th - 1);
} }
let seats = SmallMap::<SeatId, Rc<WlSeatGlobal>, 3>::new();
mc.node.visit_children(&mut generic_node_visitor(|node| {
node.seat_state().for_each_kb_focus(|s| {
seats.insert(s.id(), s);
});
}));
mc.node.set_visible(false);
for (_, seat) in seats.take() {
child.node.clone().do_focus(&seat, Direction::Unspecified);
}
self.mono_child.set(Some(child.clone()));
self.schedule_layout();
} else {
} }
} }
} }
@ -676,6 +723,18 @@ impl Node for ContainerNode {
self.id.into() self.id.into()
} }
fn visible(&self) -> bool {
self.visible.get()
}
fn set_visible(&self, visible: bool) {
self.visible.set(visible);
for child in self.children.iter() {
child.node.set_visible(visible);
}
self.seat_state.set_visible(self, visible);
}
fn seat_state(&self) -> &NodeSeatState { fn seat_state(&self) -> &NodeSeatState {
&self.seat_state &self.seat_state
} }
@ -771,11 +830,16 @@ impl Node for ContainerNode {
let node = if let Some(cn) = self.mono_child.get() { let node = if let Some(cn) = self.mono_child.get() {
Some(cn) Some(cn)
} else { } else {
match direction { let split = self.split.get();
Direction::Left => self.children.last(), match (direction, split) {
Direction::Down => self.children.first(), (Direction::Left, ContainerSplit::Horizontal) => self.children.last(),
Direction::Up => self.children.last(), (Direction::Down, ContainerSplit::Vertical) => self.children.first(),
Direction::Right => self.children.first(), (Direction::Up, ContainerSplit::Vertical) => self.children.last(),
(Direction::Right, ContainerSplit::Horizontal) => self.children.first(),
_ => match self.focus_history.last() {
Some(n) => Some(n.deref().clone()),
None => self.children.last(),
}
} }
}; };
if let Some(node) = node { if let Some(node) = node {
@ -798,7 +862,7 @@ impl Node for ContainerNode {
} }
fn move_focus_from_child( fn move_focus_from_child(
&self, self: Rc<Self>,
seat: &Rc<WlSeatGlobal>, seat: &Rc<WlSeatGlobal>,
child: &dyn Node, child: &dyn Node,
direction: Direction, direction: Direction,
@ -821,7 +885,7 @@ impl Node for ContainerNode {
if !in_line { if !in_line {
self.parent self.parent
.get() .get()
.move_focus_from_child(seat, self, direction); .move_focus_from_child(seat, &*self, direction);
return; return;
} }
let prev = match direction { let prev = match direction {
@ -829,6 +893,7 @@ impl Node for ContainerNode {
Direction::Down => false, Direction::Down => false,
Direction::Up => true, Direction::Up => true,
Direction::Right => false, Direction::Right => false,
Direction::Unspecified => true,
}; };
let sibling = match prev { let sibling = match prev {
true => child.prev(), true => child.prev(),
@ -839,21 +904,15 @@ impl Node for ContainerNode {
None => { None => {
self.parent self.parent
.get() .get()
.move_focus_from_child(seat, self, direction); .move_focus_from_child(seat, &*self, direction);
return; return;
} }
}; };
if mc.is_some() { if mc.is_some() {
self.mono_child.set(Some(sibling.clone())); self.activate_child(&sibling);
let body = self.mono_body.get(); } else {
self.mono_content sibling.node.clone().do_focus(seat, direction);
.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);
} }
// //
fn move_child(self: Rc<Self>, child: Rc<dyn Node>, direction: Direction) { fn move_child(self: Rc<Self>, child: Rc<dyn Node>, direction: Direction) {
@ -882,12 +941,10 @@ impl Node for ContainerNode {
neighbor.node.clone().insert_child(child, direction); neighbor.node.clone().insert_child(child, direction);
return; return;
} }
let cc = cc.deref().clone(); match prev {
let link = match prev { true => neighbor.prepend_existing(&cc),
true => neighbor.prepend(cc), false => neighbor.append_existing(&cc),
false => neighbor.append(cc), }
};
self.child_nodes.borrow_mut().insert(child.id(), link);
self.schedule_layout(); self.schedule_layout();
return; return;
} }
@ -932,7 +989,6 @@ impl Node for ContainerNode {
if button != BTN_LEFT { if button != BTN_LEFT {
return; return;
} }
let title_height = self.state.theme.title_height.get();
let mut seat_datas = self.seats.borrow_mut(); let mut seat_datas = self.seats.borrow_mut();
let seat_data = match seat_datas.get_mut(&seat.id()) { let seat_data = match seat_datas.get_mut(&seat.id()) {
Some(s) => s, Some(s) => s,
@ -943,51 +999,38 @@ impl Node for ContainerNode {
return; return;
} }
let (kind, child) = 'res: { let (kind, child) = 'res: {
if self.mono_child.get().is_some() { let mono = self.mono_child.get().is_some();
let width_per_child = self.width.get() / self.num_children.get() as i32; for child in self.children.iter() {
let mut width_per_child_rem = self.width.get() % self.num_children.get() as i32; let rect = child.title_rect.get();
let mut pos = 0; if rect.contains(seat_data.x, seat_data.y) {
for child in self.children.iter() { self.activate_child(&child);
pos += width_per_child; break 'res (SeatOpKind::Move, child);
if width_per_child_rem > 0 { } else if !mono {
pos += 1; if self.split.get() == ContainerSplit::Horizontal {
width_per_child_rem -= 1; if seat_data.x < rect.x1() {
} break 'res (
if pos > seat_data.x { SeatOpKind::Resize {
break 'res (SeatOpKind::Move, child); dist_left: seat_data.x
- child.prev().unwrap().body.get().x2(),
dist_right: child.body.get().x1() - seat_data.x,
},
child,
);
}
} else {
if seat_data.y < rect.y1() {
break 'res (
SeatOpKind::Resize {
dist_left: seat_data.y
- child.prev().unwrap().body.get().y2(),
dist_right: child.body.get().y1() - seat_data.y,
},
child,
);
}
} }
} }
} else if self.split.get() == ContainerSplit::Horizontal { }
for child in self.children.iter() {
let body = child.body.get();
if seat_data.x < body.x2() {
let op = if seat_data.x < body.x1() {
SeatOpKind::Resize {
dist_left: seat_data.x - child.prev().unwrap().body.get().x2(),
dist_right: body.x1() - seat_data.x,
}
} else {
SeatOpKind::Move
};
break 'res (op, child);
}
}
} else {
for child in self.children.iter() {
let body = child.body.get();
if seat_data.y < body.y1() {
let op = if seat_data.y < body.y1() - title_height - 1 {
SeatOpKind::Resize {
dist_left: seat_data.y - child.prev().unwrap().body.get().y2(),
dist_right: body.y1() - seat_data.y,
}
} else {
SeatOpKind::Move
};
break 'res (op, child);
}
}
};
return; return;
}; };
seat_data.op = Some(SeatOp { child, kind }) seat_data.op = Some(SeatOp { child, kind })
@ -1049,6 +1092,7 @@ impl Node for ContainerNode {
Some(c) => c, Some(c) => c,
None => return, None => return,
}; };
node.focus_history.set(None);
let link = node.append(ContainerChild { let link = node.append(ContainerChild {
node: new.clone(), node: new.clone(),
active: Cell::new(false), active: Cell::new(false),
@ -1056,6 +1100,8 @@ impl Node for ContainerNode {
content: Cell::new(node.content.get()), content: Cell::new(node.content.get()),
factor: Cell::new(node.factor.get()), factor: Cell::new(node.factor.get()),
title: Default::default(), title: Default::default(),
title_rect: Cell::new(node.title_rect.get()),
focus_history: Cell::new(None),
}); });
let body = link.body.get(); let body = link.body.get();
drop(node); drop(node);
@ -1083,6 +1129,7 @@ impl Node for ContainerNode {
} }
let node = { let node = {
let node = node; let node = node;
node.focus_history.set(None);
node.to_ref() node.to_ref()
}; };
let num_children = self.num_children.fetch_sub(1) - 1; let num_children = self.num_children.fetch_sub(1) - 1;
@ -1137,6 +1184,7 @@ impl Node for ContainerNode {
None => return, None => return,
}; };
node.active.set(active); node.active.set(active);
node.focus_history.set(Some(self.focus_history.add_last(node.clone())));
self.schedule_compute_render_data(); self.schedule_compute_render_data();
} }
@ -1242,5 +1290,6 @@ fn direction_to_split(dir: Direction) -> (ContainerSplit, bool) {
Direction::Down => (ContainerSplit::Vertical, false), Direction::Down => (ContainerSplit::Vertical, false),
Direction::Up => (ContainerSplit::Vertical, true), Direction::Up => (ContainerSplit::Vertical, true),
Direction::Right => (ContainerSplit::Horizontal, false), Direction::Right => (ContainerSplit::Horizontal, false),
Direction::Unspecified => (ContainerSplit::Horizontal, true),
} }
} }

View file

@ -4,7 +4,6 @@ use {
cursor::KnownCursor, cursor::KnownCursor,
ifs::{ ifs::{
wl_seat::{NodeSeatState, WlSeatGlobal}, wl_seat::{NodeSeatState, WlSeatGlobal},
wl_surface::xwindow::Xwindow,
zwlr_layer_shell_v1::{OVERLAY, TOP}, zwlr_layer_shell_v1::{OVERLAY, TOP},
}, },
tree::{walker::NodeVisitor, FindTreeResult, FoundNode, Node, NodeId, OutputNode}, tree::{walker::NodeVisitor, FindTreeResult, FoundNode, Node, NodeId, OutputNode},
@ -17,7 +16,6 @@ pub struct DisplayNode {
pub id: NodeId, pub id: NodeId,
pub outputs: CopyHashMap<ConnectorId, Rc<OutputNode>>, pub outputs: CopyHashMap<ConnectorId, Rc<OutputNode>>,
pub stacked: LinkedList<Rc<dyn Node>>, pub stacked: LinkedList<Rc<dyn Node>>,
pub xstacked: LinkedList<Rc<Xwindow>>,
pub seat_state: NodeSeatState, pub seat_state: NodeSeatState,
} }
@ -27,7 +25,6 @@ impl DisplayNode {
id, id,
outputs: Default::default(), outputs: Default::default(),
stacked: Default::default(), stacked: Default::default(),
xstacked: Default::default(),
seat_state: Default::default(), seat_state: Default::default(),
} }
} }
@ -42,6 +39,10 @@ impl Node for DisplayNode {
&self.seat_state &self.seat_state
} }
fn visible(&self) -> bool {
true
}
fn destroy_node(&self, _detach: bool) { fn destroy_node(&self, _detach: bool) {
let mut outputs = self.outputs.lock(); let mut outputs = self.outputs.lock();
for output in outputs.values() { for output in outputs.values() {
@ -79,7 +80,9 @@ impl Node for DisplayNode {
x, x,
y, y,
}); });
if output.find_layer_surface_at(x, y, &[OVERLAY, TOP], tree) == FindTreeResult::AcceptsInput { if output.find_layer_surface_at(x, y, &[OVERLAY, TOP], tree)
== FindTreeResult::AcceptsInput
{
return FindTreeResult::AcceptsInput; return FindTreeResult::AcceptsInput;
} }
tree.pop(); tree.pop();

View file

@ -327,6 +327,18 @@ impl Node for FloatNode {
&self.seat_state &self.seat_state
} }
fn visible(&self) -> bool {
self.visible.get()
}
fn set_visible(&self, visible: bool) {
self.visible.set(visible);
if let Some(child) = self.child.get() {
child.set_visible(visible);
}
self.seat_state.set_visible(self, visible);
}
fn destroy_node(&self, _detach: bool) { fn destroy_node(&self, _detach: bool) {
let _v = self.display_link.take(); let _v = self.display_link.take();
let _v = self.workspace_link.take(); let _v = self.workspace_link.take();

View file

@ -1,4 +1,3 @@
use std::cell::Cell;
use { use {
crate::{ crate::{
backend::Mode, backend::Mode,
@ -8,6 +7,7 @@ use {
wl_output::WlOutputGlobal, wl_output::WlOutputGlobal,
wl_seat::{NodeSeatState, WlSeatGlobal}, wl_seat::{NodeSeatState, WlSeatGlobal},
wl_surface::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, wl_surface::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
zwlr_layer_shell_v1::{BACKGROUND, BOTTOM},
}, },
rect::Rect, rect::Rect,
render::{Renderer, Texture}, render::{Renderer, Texture},
@ -18,13 +18,12 @@ use {
utils::{clonecell::CloneCell, errorfmt::ErrorFmt, linkedlist::LinkedList}, utils::{clonecell::CloneCell, errorfmt::ErrorFmt, linkedlist::LinkedList},
}, },
std::{ std::{
cell::RefCell, cell::{Cell, RefCell},
fmt::{Debug, Formatter}, fmt::{Debug, Formatter},
ops::{Deref, Sub}, ops::{Deref, Sub},
rc::Rc, rc::Rc,
}, },
}; };
use crate::ifs::zwlr_layer_shell_v1::{BACKGROUND, BOTTOM};
tree_id!(OutputNodeId); tree_id!(OutputNodeId);
pub struct OutputNode { pub struct OutputNode {
@ -119,12 +118,13 @@ impl OutputNode {
} }
pub fn show_workspace(&self, ws: &Rc<WorkspaceNode>) { pub fn show_workspace(&self, ws: &Rc<WorkspaceNode>) {
ws.visible.set(true);
if let Some(old) = self.workspace.set(Some(ws.clone())) { if let Some(old) = self.workspace.set(Some(ws.clone())) {
if old.id != ws.id { if old.id == ws.id {
old.visible.set(false); return;
} }
old.visible.set(false);
} }
ws.visible.set(true);
ws.clone().change_extents(&self.workspace_rect()); ws.clone().change_extents(&self.workspace_rect());
} }
@ -172,7 +172,13 @@ impl OutputNode {
self.global.send_mode(); self.global.send_mode();
} }
pub fn find_layer_surface_at(&self, x: i32, y: i32, layers: &[u32], tree: &mut Vec<FoundNode>) -> FindTreeResult { pub fn find_layer_surface_at(
&self,
x: i32,
y: i32,
layers: &[u32],
tree: &mut Vec<FoundNode>,
) -> FindTreeResult {
let len = tree.len(); let len = tree.len();
for layer in layers.iter().copied() { for layer in layers.iter().copied() {
for surface in self.layers[layer as usize].rev_iter() { for surface in self.layers[layer as usize].rev_iter() {
@ -218,6 +224,10 @@ impl Node for OutputNode {
&self.seat_state &self.seat_state
} }
fn visible(&self) -> bool {
true
}
fn destroy_node(&self, detach: bool) { fn destroy_node(&self, detach: bool) {
if detach { if detach {
self.state.root.clone().remove_child(self); self.state.root.clone().remove_child(self);

View file

@ -18,6 +18,7 @@ pub trait ToplevelNode {
fn set_active(&self, active: bool); fn set_active(&self, active: bool);
fn activate(&self); fn activate(&self);
fn toggle_floating(self: Rc<Self>); fn toggle_floating(self: Rc<Self>);
fn close(&self);
} }
#[derive(Default)] #[derive(Default)]

View file

@ -108,6 +108,68 @@ impl<T: NodeVisitorBase> NodeVisitor for T {
} }
} }
pub struct GenericNodeVisitor<F> {
f: F,
}
pub fn generic_node_visitor<F: FnMut(Rc<dyn Node>)>(f: F) -> GenericNodeVisitor<F> {
GenericNodeVisitor {
f,
}
}
impl<F: FnMut(Rc<dyn Node>)> NodeVisitor for GenericNodeVisitor<F> {
fn visit_surface(&mut self, node: &Rc<WlSurface>) {
(self.f)(node.clone());
node.visit_children(self);
}
fn visit_container(&mut self, node: &Rc<ContainerNode>) {
(self.f)(node.clone());
node.visit_children(self);
}
fn visit_toplevel(&mut self, node: &Rc<XdgToplevel>) {
(self.f)(node.clone());
node.visit_children(self);
}
fn visit_popup(&mut self, node: &Rc<XdgPopup>) {
(self.f)(node.clone());
node.visit_children(self);
}
fn visit_display(&mut self, node: &Rc<DisplayNode>) {
(self.f)(node.clone());
node.visit_children(self);
}
fn visit_output(&mut self, node: &Rc<OutputNode>) {
(self.f)(node.clone());
node.visit_children(self);
}
fn visit_float(&mut self, node: &Rc<FloatNode>) {
(self.f)(node.clone());
node.visit_children(self);
}
fn visit_workspace(&mut self, node: &Rc<WorkspaceNode>) {
(self.f)(node.clone());
node.visit_children(self);
}
fn visit_layer_surface(&mut self, node: &Rc<ZwlrLayerSurfaceV1>) {
(self.f)(node.clone());
node.visit_children(self);
}
fn visit_xwindow(&mut self, node: &Rc<Xwindow>) {
(self.f)(node.clone());
node.visit_children(self);
}
}
// pub fn visit_containers<F: FnMut(&Rc<ContainerNode>)>(f: F) -> impl NodeVisitor { // pub fn visit_containers<F: FnMut(&Rc<ContainerNode>)>(f: F) -> impl NodeVisitor {
// struct V<F>(F); // struct V<F>(F);
// impl<F: FnMut(&Rc<ContainerNode>)> NodeVisitorBase for V<F> { // impl<F: FnMut(&Rc<ContainerNode>)> NodeVisitorBase for V<F> {

View file

@ -48,6 +48,18 @@ impl Node for WorkspaceNode {
&self.seat_state &self.seat_state
} }
fn visible(&self) -> bool {
self.visible.get()
}
fn set_visible(&self, visible: bool) {
self.visible.set(visible);
if let Some(container) = self.container.get() {
container.set_visible(visible);
}
self.seat_state.set_visible(self, visible);
}
fn destroy_node(&self, detach: bool) { fn destroy_node(&self, detach: bool) {
if detach { if detach {
self.output.get().remove_child(self); self.output.get().remove_child(self);

View file

@ -9,6 +9,8 @@ use {
}, },
}; };
const LINKED_NODE_REF_COUNT: usize = !(!0 >> 1);
pub struct LinkedList<T> { pub struct LinkedList<T> {
root: LinkedNode<T>, root: LinkedNode<T>,
} }
@ -28,7 +30,7 @@ impl<T> Default for LinkedList<T> {
impl<T> LinkedList<T> { impl<T> LinkedList<T> {
pub fn new() -> Self { pub fn new() -> Self {
let node = Box::into_raw(Box::new(NodeData { let node = Box::into_raw(Box::new(NodeData {
rc: NumCell::new(1), rc: NumCell::new(LINKED_NODE_REF_COUNT),
prev: Cell::new(NonNull::dangling()), prev: Cell::new(NonNull::dangling()),
next: Cell::new(NonNull::dangling()), next: Cell::new(NonNull::dangling()),
data: None, data: None,
@ -226,6 +228,14 @@ impl<T> NodeRef<T> {
unsafe { append(self.data, t) } unsafe { append(self.data, t) }
} }
pub fn prepend_existing(&self, t: &NodeRef<T>) {
unsafe { prepend_existing(self.data, t) }
}
pub fn append_existing(&self, t: &NodeRef<T>) {
unsafe { append_existing(self.data, t) }
}
fn peer<F>(&self, peer: F) -> Option<NodeRef<T>> fn peer<F>(&self, peer: F) -> Option<NodeRef<T>>
where where
F: FnOnce(&NodeData<T>) -> &Cell<NonNull<NodeData<T>>>, F: FnOnce(&NodeData<T>) -> &Cell<NonNull<NodeData<T>>>,
@ -249,6 +259,14 @@ impl<T> NodeRef<T> {
pub fn next(&self) -> Option<NodeRef<T>> { pub fn next(&self) -> Option<NodeRef<T>> {
self.peer(|d| &d.next) self.peer(|d| &d.next)
} }
unsafe fn detach(&self) {
let data = self.data.as_ref();
data.prev.get().as_ref().next.set(data.next.get());
data.next.get().as_ref().prev.set(data.prev.get());
data.prev.set(self.data);
data.next.set(self.data);
}
} }
struct NodeData<T> { struct NodeData<T> {
@ -267,27 +285,13 @@ unsafe fn dec_ref_count<T>(slf: NonNull<NodeData<T>>, n: usize) {
impl<T> Drop for LinkedNode<T> { impl<T> Drop for LinkedNode<T> {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
{ self.detach();
let data = self.data.as_ref(); dec_ref_count(self.data, LINKED_NODE_REF_COUNT);
data.prev.get().as_ref().next.set(data.next.get());
data.next.get().as_ref().prev.set(data.prev.get());
data.prev.set(self.data);
data.next.set(self.data);
}
dec_ref_count(self.data, 1);
} }
} }
} }
impl<T> LinkedNode<T> { impl<T> LinkedNode<T> {
pub fn prepend(&self, t: T) -> LinkedNode<T> {
unsafe { prepend(self.data, t) }
}
pub fn append(&self, t: T) -> LinkedNode<T> {
unsafe { append(self.data, t) }
}
pub fn to_ref(&self) -> NodeRef<T> { pub fn to_ref(&self) -> NodeRef<T> {
unsafe { unsafe {
self.data.as_ref().rc.fetch_add(1); self.data.as_ref().rc.fetch_add(1);
@ -296,10 +300,24 @@ impl<T> LinkedNode<T> {
} }
} }
unsafe fn prepend_existing<T>(data: NonNull<NodeData<T>>, t: &NodeRef<T>) {
let dref = data.as_ref();
let tref = t.data.as_ref();
if tref.rc.get() < LINKED_NODE_REF_COUNT {
log::error!("Trying to prepend a node whose linked node has already been dropped");
return;
}
t.detach();
tref.prev.set(dref.prev.get());
tref.next.set(data);
dref.prev.get().as_ref().next.set(t.data);
dref.prev.set(t.data);
}
unsafe fn prepend<T>(data: NonNull<NodeData<T>>, t: T) -> LinkedNode<T> { unsafe fn prepend<T>(data: NonNull<NodeData<T>>, t: T) -> LinkedNode<T> {
let dref = data.as_ref(); let dref = data.as_ref();
let node = NonNull::new_unchecked(Box::into_raw(Box::new(NodeData { let node = NonNull::new_unchecked(Box::into_raw(Box::new(NodeData {
rc: NumCell::new(1), rc: NumCell::new(LINKED_NODE_REF_COUNT),
prev: Cell::new(dref.prev.get()), prev: Cell::new(dref.prev.get()),
next: Cell::new(data), next: Cell::new(data),
data: Some(t), data: Some(t),
@ -309,10 +327,24 @@ unsafe fn prepend<T>(data: NonNull<NodeData<T>>, t: T) -> LinkedNode<T> {
LinkedNode { data: node } LinkedNode { data: node }
} }
unsafe fn append_existing<T>(data: NonNull<NodeData<T>>, t: &NodeRef<T>) {
let dref = data.as_ref();
let tref = t.data.as_ref();
if tref.rc.get() < LINKED_NODE_REF_COUNT {
log::error!("Trying to append a node whose linked node has already been dropped");
return;
}
t.detach();
tref.prev.set(data);
tref.next.set(dref.next.get());
dref.next.get().as_ref().prev.set(t.data);
dref.next.set(t.data);
}
unsafe fn append<T>(data: NonNull<NodeData<T>>, t: T) -> LinkedNode<T> { unsafe fn append<T>(data: NonNull<NodeData<T>>, t: T) -> LinkedNode<T> {
let dref = data.as_ref(); let dref = data.as_ref();
let node = NonNull::new_unchecked(Box::into_raw(Box::new(NodeData { let node = NonNull::new_unchecked(Box::into_raw(Box::new(NodeData {
rc: NumCell::new(1), rc: NumCell::new(LINKED_NODE_REF_COUNT),
prev: Cell::new(data), prev: Cell::new(data),
next: Cell::new(dref.next.get()), next: Cell::new(dref.next.get()),
data: Some(t), data: Some(t),

View file

@ -2,6 +2,7 @@ mod sys;
use { use {
crate::{ crate::{
utils::oserror::OsError,
video::drm::sys::{ video::drm::sys::{
create_lease, drm_event, drm_event_vblank, gem_close, get_cap, create_lease, drm_event, drm_event_vblank, gem_close, get_cap,
get_device_name_from_fd2, get_minor_name_from_fd, get_node_type_from_fd, get_nodes, get_device_name_from_fd2, get_minor_name_from_fd, get_node_type_from_fd, get_nodes,
@ -13,7 +14,6 @@ use {
DRM_MODE_OBJECT_CRTC, DRM_MODE_OBJECT_ENCODER, DRM_MODE_OBJECT_FB, DRM_MODE_OBJECT_CRTC, DRM_MODE_OBJECT_ENCODER, DRM_MODE_OBJECT_FB,
DRM_MODE_OBJECT_MODE, DRM_MODE_OBJECT_PLANE, DRM_MODE_OBJECT_PROPERTY, DRM_MODE_OBJECT_MODE, DRM_MODE_OBJECT_PLANE, DRM_MODE_OBJECT_PROPERTY,
}, },
utils::oserror::OsError,
}, },
ahash::AHashMap, ahash::AHashMap,
bstr::{BString, ByteSlice}, bstr::{BString, ByteSlice},
@ -31,8 +31,8 @@ use {
use crate::{ use crate::{
backend, backend,
video::{dma::DmaBuf, INVALID_MODIFIER},
utils::{errorfmt::ErrorFmt, stack::Stack, syncqueue::SyncQueue, vec_ext::VecExt}, utils::{errorfmt::ErrorFmt, stack::Stack, syncqueue::SyncQueue, vec_ext::VecExt},
video::{dma::DmaBuf, INVALID_MODIFIER},
}; };
pub use sys::{ pub use sys::{
drm_mode_modeinfo, DRM_CLIENT_CAP_ATOMIC, DRM_MODE_ATOMIC_ALLOW_MODESET, drm_mode_modeinfo, DRM_CLIENT_CAP_ATOMIC, DRM_MODE_ATOMIC_ALLOW_MODESET,

View file

@ -3,13 +3,13 @@
use { use {
crate::{ crate::{
utils::{bitflags::BitflagsExt, oserror::OsError, trim::AsciiTrim},
video::drm::{ video::drm::{
DrmBlob, DrmCardResources, DrmConnector, DrmConnectorInfo, DrmCrtc, DrmEncoder, DrmBlob, DrmCardResources, DrmConnector, DrmConnectorInfo, DrmCrtc, DrmEncoder,
DrmEncoderInfo, DrmError, DrmFb, DrmModeInfo, DrmPlane, DrmPlaneInfo, DrmProperty, DrmEncoderInfo, DrmError, DrmFb, DrmModeInfo, DrmPlane, DrmPlaneInfo, DrmProperty,
DrmPropertyDefinition, DrmPropertyEnumValue, DrmPropertyType, DrmPropertyValue, DrmPropertyDefinition, DrmPropertyEnumValue, DrmPropertyType, DrmPropertyValue,
NodeType, NodeType,
}, },
utils::{bitflags::BitflagsExt, oserror::OsError, trim::AsciiTrim},
}, },
ahash::AHashMap, ahash::AHashMap,
bstr::ByteSlice, bstr::ByteSlice,

View file

@ -1,11 +1,11 @@
use { use {
crate::{ crate::{
format::formats,
video::{ video::{
dma::{DmaBuf, DmaBufPlane}, dma::{DmaBuf, DmaBufPlane},
drm::{Drm, DrmError}, drm::{Drm, DrmError},
ModifiedFormat, INVALID_MODIFIER, ModifiedFormat, INVALID_MODIFIER,
}, },
format::formats,
}, },
std::{ std::{
fmt::{Debug, Formatter}, fmt::{Debug, Formatter},

View file

@ -271,4 +271,5 @@ pub enum XWaylandEvent {
SurfaceDestroyed(WlSurfaceId), SurfaceDestroyed(WlSurfaceId),
Configure(Rc<Xwindow>), Configure(Rc<Xwindow>),
Activate(Rc<XwindowData>), Activate(Rc<XwindowData>),
Close(Rc<XwindowData>),
} }

View file

@ -55,6 +55,7 @@ atoms! {
CLIPBOARD, CLIPBOARD,
CLIPBOARD_MANAGER, CLIPBOARD_MANAGER,
COMPOUND_TEXT,
DELETE, DELETE,
INCR, INCR,
_MOTIF_WM_HINTS, _MOTIF_WM_HINTS,
@ -370,6 +371,7 @@ impl Wm {
XWaylandEvent::Configure(event) => self.handle_xwayland_configure(event).await, XWaylandEvent::Configure(event) => self.handle_xwayland_configure(event).await,
XWaylandEvent::SurfaceDestroyed(event) => self.handle_xwayland_surface_destroyed(event), XWaylandEvent::SurfaceDestroyed(event) => self.handle_xwayland_surface_destroyed(event),
XWaylandEvent::Activate(window) => self.activate_window(Some(&window)).await, XWaylandEvent::Activate(window) => self.activate_window(Some(&window)).await,
XWaylandEvent::Close(window) => self.close_window(&window).await,
} }
} }
@ -534,7 +536,7 @@ impl Wm {
Ok(ty) if ty == ATOM_STRING => {} Ok(ty) if ty == ATOM_STRING => {}
Ok(ty) if ty == self.atoms.UTF8_STRING => {} Ok(ty) if ty == self.atoms.UTF8_STRING => {}
Ok(ty) => { Ok(ty) => {
log::error!("WM_WINDOW_ROLE property has unexpected type {}", ty); self.unexpected_type(data.window_id, "WM_WINDOW_ROLE", ty).await;
return; return;
} }
Err(XconError::PropertyUnavailable) => { Err(XconError::PropertyUnavailable) => {
@ -563,7 +565,7 @@ impl Wm {
Ok(ty) if ty == ATOM_STRING => {} Ok(ty) if ty == ATOM_STRING => {}
Ok(ty) if ty == self.atoms.UTF8_STRING => {} Ok(ty) if ty == self.atoms.UTF8_STRING => {}
Ok(ty) => { Ok(ty) => {
log::error!("WM_CLASS property has unexpected type {}", ty); self.unexpected_type(data.window_id, "WM_CLASS", ty).await;
return; return;
} }
Err(XconError::PropertyUnavailable) => { Err(XconError::PropertyUnavailable) => {
@ -590,11 +592,12 @@ impl Wm {
{ {
Ok(ty) if ty == ATOM_STRING && data.info.utf8_title.get() => return, Ok(ty) if ty == ATOM_STRING && data.info.utf8_title.get() => return,
Ok(ty) if ty == ATOM_STRING => {} Ok(ty) if ty == ATOM_STRING => {}
Ok(ty) if ty == self.atoms.COMPOUND_TEXT => {} // used by java. assume utf-8.
Ok(ty) if ty == self.atoms.UTF8_STRING => { Ok(ty) if ty == self.atoms.UTF8_STRING => {
data.info.utf8_title.set(true); data.info.utf8_title.set(true);
} }
Ok(ty) => { Ok(ty) => {
log::error!("{} property has unexpected type {}", name, ty); self.unexpected_type(data.window_id, name, ty).await;
return; return;
} }
Err(XconError::PropertyUnavailable) => return, Err(XconError::PropertyUnavailable) => return,
@ -607,6 +610,15 @@ impl Wm {
data.title_changed(); data.title_changed();
} }
async fn unexpected_type(&self, window: u32, prop: &str, ty: u32) {
let mut ty_name = "unknown".as_bytes().as_bstr();
let res = self.c.call(&GetAtomName { atom: ty }).await;
if let Ok(res) = &res {
ty_name = res.get().name;
}
log::error!("Property {} of window {} has unexpected type {} ({})", prop, window, ty_name, ty);
}
async fn load_window_wm_name(&self, data: &Rc<XwindowData>) { async fn load_window_wm_name(&self, data: &Rc<XwindowData>) {
self.load_window_wm_name2(data, ATOM_WM_NAME, "WM_NAME") self.load_window_wm_name2(data, ATOM_WM_NAME, "WM_NAME")
.await; .await;
@ -786,7 +798,7 @@ impl Wm {
Ok(ty) if ty == ATOM_STRING => {} Ok(ty) if ty == ATOM_STRING => {}
Ok(ty) if ty == self.atoms.UTF8_STRING => {} Ok(ty) if ty == self.atoms.UTF8_STRING => {}
Ok(ty) => { Ok(ty) => {
log::error!("_NET_STARTUP_ID property has unexpected type {}", ty); self.unexpected_type(data.window_id, "_NET_STARTUP_ID", ty).await;
return; return;
} }
Err(XconError::PropertyUnavailable) => return, Err(XconError::PropertyUnavailable) => return,