diff --git a/default-config/src/lib.rs b/default-config/src/lib.rs index addf85a2..8aa121cc 100644 --- a/default-config/src/lib.rs +++ b/default-config/src/lib.rs @@ -21,6 +21,7 @@ use jay_config::{ Command, Direction::{Down, Left, Right, Up}, }; +use jay_config::keyboard::syms::SYM_c; 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 | SHIFT | SYM_c, move || s.close()); + s.bind(MOD | SHIFT | SYM_f, move || s.toggle_floating()); s.bind(SYM_Super_L, || Command::new("alacritty").spawn()); diff --git a/jay-config/src/_private/client.rs b/jay-config/src/_private/client.rs index 2e635bf2..476465ce 100644 --- a/jay-config/src/_private/client.rs +++ b/jay-config/src/_private/client.rs @@ -296,6 +296,10 @@ impl Client { self.send(&ClientMessage::CreateSplit { seat, axis }); } + pub fn close(&self, seat: Seat) { + self.send(&ClientMessage::Close { seat }); + } + pub fn focus_parent(&self, seat: Seat) { self.send(&ClientMessage::FocusParent { seat }); } diff --git a/jay-config/src/_private/ipc.rs b/jay-config/src/_private/ipc.rs index 086cf591..94676499 100644 --- a/jay-config/src/_private/ipc.rs +++ b/jay-config/src/_private/ipc.rs @@ -146,6 +146,9 @@ pub enum ClientMessage<'a> { seat: Seat, axis: Axis, }, + Close { + seat: Seat, + }, FocusParent { seat: Seat, }, diff --git a/jay-config/src/input.rs b/jay-config/src/input.rs index 4aa3c71a..9d9b3218 100644 --- a/jay-config/src/input.rs +++ b/jay-config/src/input.rs @@ -117,6 +117,10 @@ impl Seat { get!().focus_parent(self); } + pub fn close(self) { + get!().close(self); + } + pub fn toggle_floating(self) { get!().toggle_floating(self); } diff --git a/jay-config/src/lib.rs b/jay-config/src/lib.rs index e914be9f..7403ac5f 100644 --- a/jay-config/src/lib.rs +++ b/jay-config/src/lib.rs @@ -25,6 +25,7 @@ pub enum LogLevel { #[derive(Encode, Decode, Copy, Clone, Debug, Eq, PartialEq)] pub enum Direction { + Unspecified, Left, Down, Up, diff --git a/src/backend.rs b/src/backend.rs index b9993356..f61becc7 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -1,5 +1,5 @@ use { - crate::{video::drm::ConnectorType, fixed::Fixed}, + crate::{fixed::Fixed, video::drm::ConnectorType}, std::{ fmt::{Debug, Display, Formatter}, rc::Rc, diff --git a/src/backends/metal.rs b/src/backends/metal.rs index e0248c81..d00e2f4b 100644 --- a/src/backends/metal.rs +++ b/src/backends/metal.rs @@ -11,7 +11,6 @@ use { }, backends::metal::video::{MetalDrmDevice, PendingDrmDevice}, dbus::DbusError, - video::{drm::DrmError, gbm::GbmError}, libinput::{ consts::{ AccelProfile, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE, @@ -35,6 +34,7 @@ use { smallmap::SmallMap, syncqueue::SyncQueue, }, + video::{drm::DrmError, gbm::GbmError}, }, std::{ cell::{Cell, RefCell}, diff --git a/src/backends/metal/monitor.rs b/src/backends/metal/monitor.rs index 00dd7f89..5bd8aee5 100644 --- a/src/backends/metal/monitor.rs +++ b/src/backends/metal/monitor.rs @@ -7,9 +7,9 @@ use { MetalBackend, MetalDevice, MetalError, MetalInputDevice, }, dbus::TRUE, - video::drm::DrmMaster, udev::UdevDevice, utils::{errorfmt::ErrorFmt, nonblock::set_nonblock}, + video::drm::DrmMaster, wire_dbus::org::freedesktop::login1::session::{PauseDevice, ResumeDevice}, }, bstr::ByteSlice, diff --git a/src/backends/metal/video.rs b/src/backends/metal/video.rs index fa94b097..8e36ba4b 100644 --- a/src/backends/metal/video.rs +++ b/src/backends/metal/video.rs @@ -5,6 +5,14 @@ use { BackendEvent, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId, MonitorInfo, }, 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::{ drm::{ drm_mode_modeinfo, Change, ConnectorStatus, ConnectorType, DrmBlob, DrmConnector, @@ -16,14 +24,6 @@ use { gbm::{GbmDevice, GBM_BO_USE_RENDERING, GBM_BO_USE_SCANOUT}, 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}, bstr::{BString, ByteSlice}, @@ -280,10 +280,10 @@ fn create_connector( if let Some(d) = descriptor { match d { Descriptor::DisplayProductSerialNumber(s) => { - serial_number = s.to_string(); + serial_number = s.clone(); } Descriptor::DisplayProductName(s) => { - name = s.to_string(); + name = s.clone(); } _ => {} } diff --git a/src/backends/x.rs b/src/backends/x.rs index 051d63b9..b8589b20 100644 --- a/src/backends/x.rs +++ b/src/backends/x.rs @@ -6,11 +6,6 @@ use { InputDevice, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId, InputEvent, KeyState, Mode, MonitorInfo, ScrollAxis, }, - video::{ - drm::{ConnectorType, Drm, DrmError}, - gbm::{GbmDevice, GbmError, GBM_BO_USE_RENDERING}, - ModifiedFormat, INVALID_MODIFIER, - }, fixed::Fixed, format::XRGB8888, render::{Framebuffer, RenderContext, RenderError}, @@ -19,6 +14,11 @@ use { clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell, queue::AsyncQueue, syncqueue::SyncQueue, }, + video::{ + drm::{ConnectorType, Drm, DrmError}, + gbm::{GbmDevice, GbmError, GBM_BO_USE_RENDERING}, + ModifiedFormat, INVALID_MODIFIER, + }, wire_xcon::{ ChangeProperty, ChangeWindowAttributes, ConfigureNotify, CreateCursor, CreatePixmap, CreateWindow, CreateWindowValues, DestroyNotify, Dri3Open, Dri3PixmapFromBuffer, diff --git a/src/config/handler.rs b/src/config/handler.rs index bdeb251d..2f1ea492 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -132,6 +132,12 @@ impl ConfigProxyHandler { 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> { let seat = self.get_seat(seat)?; seat.move_focus(direction); @@ -763,6 +769,9 @@ impl ConfigProxyHandler { ClientMessage::ConnectorSetPosition { connector, x, y } => self .handle_connector_set_position(connector, x, y) .wrn("connector_set_position")?, + ClientMessage::Close { seat } => self + .handle_close(seat) + .wrn("close")?, } Ok(()) } diff --git a/src/edid.rs b/src/edid.rs index d360c0d3..2a2094bf 100644 --- a/src/edid.rs +++ b/src/edid.rs @@ -347,9 +347,9 @@ pub struct DetailedTimingDescriptor { pub enum Descriptor { Unknown(u8), DetailedTimingDescriptor(DetailedTimingDescriptor), - DisplayProductSerialNumber(BString), - AlphanumericDataString(BString), - DisplayProductName(BString), + DisplayProductSerialNumber(String), + AlphanumericDataString(String), + DisplayProductName(String), DisplayRangeLimitsAndAdditionalTiming(DisplayRangeLimitsAndAdditionalTiming), EstablishedTimings3(EstablishedTimings3), ColorManagementData(ColorManagementData), @@ -880,11 +880,15 @@ impl<'a> EdidParser<'a> { let _ctx = self.push_ctx(EdidParseContext::Descriptor); let b = self.read_n::<18>()?; let str = || { - let s = &b[5..]; - match s.find_byte(b'\n') { - Some(n) => s[..n].as_bstr().to_owned(), - _ => s.as_bstr().to_owned(), + let mut s = &b[5..]; + if let Some(n) = s.find_byte(b'\n') { + s = &s[..n]; + }; + 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) { match b[3] { @@ -1079,3 +1083,20 @@ pub fn parse(data: &[u8]) -> Result { }; 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}", +]; diff --git a/src/ifs/wl_drm.rs b/src/ifs/wl_drm.rs index 48e06907..0bcfaa10 100644 --- a/src/ifs/wl_drm.rs +++ b/src/ifs/wl_drm.rs @@ -1,16 +1,16 @@ use { crate::{ client::{Client, ClientError}, - video::{ - dma::{DmaBuf, DmaBufPlane}, - INVALID_MODIFIER, - }, globals::{Global, GlobalName}, ifs::wl_buffer::WlBuffer, leaks::Tracker, object::Object, render::RenderError, utils::buffd::{MsgParser, MsgParserError}, + video::{ + dma::{DmaBuf, DmaBufPlane}, + INVALID_MODIFIER, + }, wire::{wl_drm::*, WlDrmId}, }, bstr::ByteSlice, diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index c27d5fd2..f09dfdff 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -274,6 +274,11 @@ impl WlSeatGlobal { } } + pub fn close(self: &Rc) { + let kb_node = self.keyboard_node.get(); + kb_node.close(); + } + pub fn move_focus(self: &Rc, direction: Direction) { let kb_node = self.keyboard_node.get(); kb_node.move_focus(self, direction); diff --git a/src/ifs/wl_seat/event_handling.rs b/src/ifs/wl_seat/event_handling.rs index 35615ccd..c75f0ecc 100644 --- a/src/ifs/wl_seat/event_handling.rs +++ b/src/ifs/wl_seat/event_handling.rs @@ -81,16 +81,32 @@ impl NodeSeatState { } 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() { seat.ungrab_kb(); seat.keyboard_node.set(seat.state.root.clone()); - if let Some(tl) = seat.toplevel_focus_history.last() { - seat.focus_node(tl.focus_surface(seat.id)); + if focus_last { + if let Some(tl) = seat.toplevel_focus_history.last() { + seat.focus_node(tl.focus_surface(seat.id)); + } } } } + pub fn for_each_kb_focus)>(&self, mut f: F) { + self.kb_foci.iter().for_each(|(_, s)| f(s)); + } + 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() { seat.pointer_owner.revert_to_default(&seat); } @@ -109,7 +125,16 @@ impl NodeSeatState { } 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); + } } } diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index 9c2e0671..8fb80662 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -84,6 +84,7 @@ pub struct WlSurface { pub id: WlSurfaceId, pub node_id: SurfaceNodeId, pub client: Rc, + visible: Cell, role: Cell, pending: PendingState, input_region: Cell>>, @@ -199,6 +200,7 @@ impl WlSurface { id, node_id: client.state.node_ids.next(), client: client.clone(), + visible: Cell::new(false), role: Cell::new(SurfaceRole::None), pending: Default::default(), input_region: Cell::new(None), @@ -624,6 +626,27 @@ impl Node for WlSurface { 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 { &self.seat_state } diff --git a/src/ifs/wl_surface/xdg_surface/xdg_popup.rs b/src/ifs/wl_surface/xdg_surface/xdg_popup.rs index a84a5fd0..3c50a29b 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_popup.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_popup.rs @@ -288,6 +288,15 @@ impl Node for XdgPopup { 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> { self.xdg.workspace.get() } diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs index 0ff7f99a..f5aaeec4 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs @@ -143,6 +143,12 @@ impl XdgToplevel { 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) { let states: Vec<_> = self.states.borrow().iter().copied().collect(); self.xdg.surface.client.event(Configure { @@ -384,6 +390,15 @@ impl Node for XdgToplevel { 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> { self.xdg.workspace.get() } @@ -508,6 +523,10 @@ impl ToplevelNode for XdgToplevel { self.map_floating(&ws); } } + + fn close(&self) { + self.send_close(); + } } impl XdgSurfaceExt for XdgToplevel { @@ -546,12 +565,12 @@ impl XdgSurfaceExt for XdgToplevel { } } } - { - let seats = surface.client.state.globals.lock_seats(); - for seat in seats.values() { - seat.focus_toplevel(self.clone()); - } - } + // { + // let seats = surface.client.state.globals.lock_seats(); + // for seat in seats.values() { + // seat.focus_toplevel(self.clone()); + // } + // } surface.client.state.tree_changed(); } } diff --git a/src/ifs/wl_surface/xwindow.rs b/src/ifs/wl_surface/xwindow.rs index 31419a77..43e60b61 100644 --- a/src/ifs/wl_surface/xwindow.rs +++ b/src/ifs/wl_surface/xwindow.rs @@ -1,4 +1,3 @@ -use std::ops::Not; use { crate::{ client::Client, @@ -27,7 +26,7 @@ use { jay_config::Direction, std::{ cell::{Cell, RefCell}, - ops::{Deref}, + ops::{Deref, Not}, rc::Rc, }, thiserror::Error, @@ -142,7 +141,6 @@ pub struct Xwindow { pub events: Rc>, pub workspace: CloneCell>>, pub display_link: RefCell>>>, - pub display_xlink: RefCell>>>, pub toplevel_data: ToplevelData, } @@ -219,7 +217,6 @@ impl Xwindow { events: events.clone(), workspace: Default::default(), display_link: Default::default(), - display_xlink: Default::default(), toplevel_data: Default::default(), } } @@ -279,8 +276,6 @@ impl Xwindow { Change::Map if self.data.info.override_redirect.get() => { *self.display_link.borrow_mut() = 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(); } Change::Map if self.data.info.wants_floating.get() => { @@ -334,13 +329,21 @@ impl Node for Xwindow { 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 { &self.seat_state } fn destroy_node(&self, _detach: bool) { self.toplevel_data.clear(); - self.display_xlink.borrow_mut().take(); self.display_link.borrow_mut().take(); self.workspace.take(); self.focus_history.clear(); @@ -449,7 +452,8 @@ impl ToplevelNode for Xwindow { } 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 { @@ -482,6 +486,10 @@ impl ToplevelNode for Xwindow { .map_floating(self.clone(), extents.width(), extents.height(), &ws); } } + + fn close(&self) { + self.events.push(XWaylandEvent::Close(self.data.clone())); + } } #[derive(Debug, Error)] diff --git a/src/ifs/wl_surface/zwlr_layer_surface_v1.rs b/src/ifs/wl_surface/zwlr_layer_surface_v1.rs index f8455aa6..0d6e5153 100644 --- a/src/ifs/wl_surface/zwlr_layer_surface_v1.rs +++ b/src/ifs/wl_surface/zwlr_layer_surface_v1.rs @@ -370,6 +370,10 @@ impl Node for ZwlrLayerSurfaceV1 { self.surface.clone().visit(visitor); } + fn visible(&self) -> bool { + true + } + fn absolute_position(&self) -> Rect { self.pos.get() } diff --git a/src/ifs/zwp_linux_buffer_params_v1.rs b/src/ifs/zwp_linux_buffer_params_v1.rs index 73da4b16..68aeba29 100644 --- a/src/ifs/zwp_linux_buffer_params_v1.rs +++ b/src/ifs/zwp_linux_buffer_params_v1.rs @@ -1,10 +1,6 @@ use { crate::{ client::ClientError, - video::{ - dma::{DmaBuf, DmaBufPlane}, - INVALID_MODIFIER, - }, ifs::{wl_buffer::WlBuffer, zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1}, leaks::Tracker, object::Object, @@ -13,6 +9,10 @@ use { buffd::{MsgParser, MsgParserError}, errorfmt::ErrorFmt, }, + video::{ + dma::{DmaBuf, DmaBufPlane}, + INVALID_MODIFIER, + }, wire::{zwp_linux_buffer_params_v1::*, WlBufferId, ZwpLinuxBufferParamsV1Id}, }, ahash::AHashMap, diff --git a/src/ifs/zwp_linux_dmabuf_v1.rs b/src/ifs/zwp_linux_dmabuf_v1.rs index 3019dc93..b35684b3 100644 --- a/src/ifs/zwp_linux_dmabuf_v1.rs +++ b/src/ifs/zwp_linux_dmabuf_v1.rs @@ -1,12 +1,12 @@ use { crate::{ client::{Client, ClientError}, - video::INVALID_MODIFIER, globals::{Global, GlobalName}, ifs::zwp_linux_buffer_params_v1::ZwpLinuxBufferParamsV1, leaks::Tracker, object::Object, utils::buffd::{MsgParser, MsgParserError}, + video::INVALID_MODIFIER, wire::{zwp_linux_dmabuf_v1::*, ZwpLinuxDmabufV1Id}, }, std::rc::Rc, diff --git a/src/main.rs b/src/main.rs index 73ce7e09..8a5c9c47 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,7 +45,6 @@ mod compositor; mod config; mod cursor; mod dbus; -mod video; mod edid; mod event_loop; mod fixed; @@ -70,6 +69,7 @@ mod tools; mod tree; mod udev; mod utils; +mod video; mod wheel; mod wire; mod wire_dbus; diff --git a/src/render/egl/display.rs b/src/render/egl/display.rs index 47e9e395..663a3f0f 100644 --- a/src/render/egl/display.rs +++ b/src/render/egl/display.rs @@ -1,6 +1,5 @@ use { crate::{ - video::{dma::DmaBuf, drm::Drm, gbm::GbmDevice, INVALID_MODIFIER}, format::{formats, Format}, render::{ egl::{ @@ -27,6 +26,7 @@ use { sys::{eglInitialize, EGL_PLATFORM_GBM_KHR}, RenderError, }, + video::{dma::DmaBuf, drm::Drm, gbm::GbmDevice, INVALID_MODIFIER}, }, ahash::AHashMap, std::{ptr, rc::Rc}, diff --git a/src/render/renderer/context.rs b/src/render/renderer/context.rs index d1a70076..61374582 100644 --- a/src/render/renderer/context.rs +++ b/src/render/renderer/context.rs @@ -1,9 +1,5 @@ use { crate::{ - video::{ - dma::DmaBuf, - drm::{Drm, NodeType}, - }, format::{Format, XRGB8888}, render::{ egl::{context::EglContext, display::EglDisplay}, @@ -13,6 +9,10 @@ use { renderer::{framebuffer::Framebuffer, image::Image}, RenderError, Texture, }, + video::{ + dma::DmaBuf, + drm::{Drm, NodeType}, + }, }, ahash::AHashMap, std::{ diff --git a/src/render/renderer/renderer.rs b/src/render/renderer/renderer.rs index 0a0b71a9..24d7a41f 100644 --- a/src/render/renderer/renderer.rs +++ b/src/render/renderer/renderer.rs @@ -25,7 +25,7 @@ use { }, state::State, theme::Color, - tree::{ContainerNode, FloatNode, Node, OutputNode, WorkspaceNode}, + tree::{ContainerNode, FloatNode, OutputNode, WorkspaceNode}, utils::rc_eq::rc_eq, }, std::{ops::Deref, rc::Rc}, @@ -70,23 +70,14 @@ impl Renderer<'_> { self.render_workspace(&ws, x, y + th); } for stacked in self.state.root.stacked.iter() { - if let Some(ws) = stacked.get_workspace() { - if ws.visible.get() { - let pos = stacked.absolute_position(); - if pos.intersects(&opos) { - let (x, y) = opos.translate(pos.x1(), pos.y1()); - stacked.render(self, x, y); - } + if stacked.visible() { + let pos = stacked.absolute_position(); + if pos.intersects(&opos) { + let (x, y) = opos.translate(pos.x1(), pos.y1()); + 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[3]); } diff --git a/src/tree.rs b/src/tree.rs index 51d63925..bf7ee157 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -74,6 +74,11 @@ pub trait Node { fn destroy_node(&self, detach: bool); fn visit(self: Rc, 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> { None @@ -134,6 +139,10 @@ pub trait Node { let _ = direction; } + fn close(&self) { + // nothing + } + fn move_focus(self: Rc, seat: &Rc, direction: Direction) { let _ = seat; let _ = direction; @@ -144,7 +153,7 @@ pub trait Node { } fn move_focus_from_child( - &self, + self: Rc, seat: &Rc, child: &dyn Node, direction: Direction, diff --git a/src/tree/container.rs b/src/tree/container.rs index a155e93a..e76416ee 100644 --- a/src/tree/container.rs +++ b/src/tree/container.rs @@ -31,6 +31,8 @@ use { rc::Rc, }, }; +use crate::tree::{generic_node_visitor}; +use crate::utils::smallmap::SmallMap; #[allow(dead_code)] #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -102,12 +104,14 @@ pub struct ContainerNode { compute_render_data_scheduled: Cell, num_children: NumCell, pub children: LinkedList, + focus_history: LinkedList>, child_nodes: RefCell>>, seat_state: NodeSeatState, workspace: CloneCell>, seats: RefCell>, state: Rc, pub render_data: RefCell, + visible: Cell, } impl Debug for ContainerNode { @@ -116,14 +120,17 @@ impl Debug for ContainerNode { } } -#[derive(Clone)] pub struct ContainerChild { pub node: Rc, pub active: Cell, + title: RefCell, + pub title_rect: Cell, + focus_history: Cell>>>, + + // fields below only valid in tabbed layout pub body: Cell, pub content: Cell, factor: Cell, - title: RefCell, } struct SeatState { @@ -166,11 +173,13 @@ impl ContainerNode { child.id(), children.add_last(ContainerChild { node: child.clone(), - active: Cell::new(false), - body: Cell::new(Default::default()), - content: Cell::new(Default::default()), + active: Default::default(), + body: Default::default(), + content: Default::default(), factor: Cell::new(1.0), title: Default::default(), + title_rect: Default::default(), + focus_history: Default::default(), }), ); let slf = Rc::new(Self { @@ -193,12 +202,14 @@ impl ContainerNode { compute_render_data_scheduled: Cell::new(false), num_children: NumCell::new(1), children, + focus_history: Default::default(), child_nodes: RefCell::new(child_nodes), seat_state: Default::default(), workspace: CloneCell::new(workspace.clone()), seats: RefCell::new(Default::default()), state: state.clone(), render_data: Default::default(), + visible: Cell::new(false), }); child.set_parent(slf.clone()); slf @@ -254,24 +265,26 @@ impl ContainerNode { where F: FnOnce(ContainerChild) -> LinkedNode, { - { + let new_ref = { let mut links = self.child_nodes.borrow_mut(); if links.contains_key(&new.id()) { log::error!("Tried to add a child to a container that already contains the child"); return; } - links.insert( - new.id(), - f(ContainerChild { - node: new.clone(), - active: Cell::new(false), - body: Default::default(), - content: Default::default(), - factor: Cell::new(0.0), - title: Default::default(), - }), - ); - } + let link = f(ContainerChild { + node: new.clone(), + active: Default::default(), + body: Default::default(), + content: Default::default(), + factor: Default::default(), + title: Default::default(), + title_rect: 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_parent(self.clone()); let num_children = self.num_children.fetch_add(1) + 1; @@ -288,6 +301,9 @@ impl ContainerNode { sum_factors += factor; } self.sum_factors.set(sum_factors); + if self.mono_child.get().is_some() { + self.activate_child(&new_ref); + } self.schedule_layout(); self.cancel_seat_ops(); } @@ -332,6 +348,25 @@ impl ContainerNode { .change_extents(&mb.move_(self.abs_x1.get(), self.abs_y1.get())); self.mono_content .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) { @@ -402,7 +437,17 @@ impl ContainerNode { } self.sum_factors.set(1.0); 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.position_content(); } @@ -567,77 +612,79 @@ impl ContainerNode { let font = theme.font.borrow_mut(); let cwidth = self.width.get(); let cheight = self.height.get(); - let num_children = self.num_children.get() as i32; let ctx = self.state.render_ctx.get(); rd.titles.clear(); rd.title_rects.clear(); rd.active_title_rects.clear(); rd.border_rects.clear(); rd.underline_rects.clear(); - let mut render_title = |title: &str, width: i32, x: i32, y: i32| { - if th == 0 || width == 0 || title.is_empty() { - return; + let mono = self.mono_child.get().is_some(); + let split = self.split.get(); + 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 { - match text::render(ctx, width, th, &font, title, Color::GREY) { - Ok(t) => rd.titles.push(ContainerTitle { x, y, tex: t }), - Err(e) => { - log::error!("Could not render title {}: {}", title, ErrorFmt(e)); + if child.active.get() { + rd.active_title_rects.push(rect); + } else { + rd.title_rects.push(rect); + } + 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() { - 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; - } + } + if mono { rd.underline_rects .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(); - if i > 0 { - let rect = if split == ContainerSplit::Horizontal { - Rect::new_sized(body.x1() - bw, 0, bw, cheight).unwrap() - } 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); + } + } + + fn activate_child(self: &Rc, child: &NodeRef) { + if let Some(mc) = self.mono_child.get() { + if mc.node.id() == child.node.id() { + return; } + let seats = SmallMap::, 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() } + 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 { &self.seat_state } @@ -771,11 +830,16 @@ impl Node for ContainerNode { let node = if let Some(cn) = self.mono_child.get() { Some(cn) } else { - match direction { - Direction::Left => self.children.last(), - Direction::Down => self.children.first(), - Direction::Up => self.children.last(), - Direction::Right => self.children.first(), + let split = self.split.get(); + match (direction, split) { + (Direction::Left, ContainerSplit::Horizontal) => self.children.last(), + (Direction::Down, ContainerSplit::Vertical) => 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 { @@ -798,7 +862,7 @@ impl Node for ContainerNode { } fn move_focus_from_child( - &self, + self: Rc, seat: &Rc, child: &dyn Node, direction: Direction, @@ -821,7 +885,7 @@ impl Node for ContainerNode { if !in_line { self.parent .get() - .move_focus_from_child(seat, self, direction); + .move_focus_from_child(seat, &*self, direction); return; } let prev = match direction { @@ -829,6 +893,7 @@ impl Node for ContainerNode { Direction::Down => false, Direction::Up => true, Direction::Right => false, + Direction::Unspecified => true, }; let sibling = match prev { true => child.prev(), @@ -839,21 +904,15 @@ impl Node for ContainerNode { None => { self.parent .get() - .move_focus_from_child(seat, self, direction); + .move_focus_from_child(seat, &*self, direction); return; } }; if mc.is_some() { - self.mono_child.set(Some(sibling.clone())); - let body = self.mono_body.get(); - self.mono_content - .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())); + self.activate_child(&sibling); + } else { + sibling.node.clone().do_focus(seat, direction); } - sibling.node.clone().do_focus(seat, direction); } // fn move_child(self: Rc, child: Rc, direction: Direction) { @@ -882,12 +941,10 @@ impl Node for ContainerNode { neighbor.node.clone().insert_child(child, direction); return; } - let cc = cc.deref().clone(); - let link = match prev { - true => neighbor.prepend(cc), - false => neighbor.append(cc), - }; - self.child_nodes.borrow_mut().insert(child.id(), link); + match prev { + true => neighbor.prepend_existing(&cc), + false => neighbor.append_existing(&cc), + } self.schedule_layout(); return; } @@ -932,7 +989,6 @@ impl Node for ContainerNode { if button != BTN_LEFT { return; } - let title_height = self.state.theme.title_height.get(); let mut seat_datas = self.seats.borrow_mut(); let seat_data = match seat_datas.get_mut(&seat.id()) { Some(s) => s, @@ -943,51 +999,38 @@ impl Node for ContainerNode { return; } let (kind, child) = 'res: { - if self.mono_child.get().is_some() { - let width_per_child = self.width.get() / self.num_children.get() as i32; - let mut width_per_child_rem = self.width.get() % self.num_children.get() as i32; - let mut pos = 0; - for child in self.children.iter() { - pos += width_per_child; - if width_per_child_rem > 0 { - pos += 1; - width_per_child_rem -= 1; - } - if pos > seat_data.x { - break 'res (SeatOpKind::Move, child); + let mono = self.mono_child.get().is_some(); + for child in self.children.iter() { + let rect = child.title_rect.get(); + if rect.contains(seat_data.x, seat_data.y) { + self.activate_child(&child); + break 'res (SeatOpKind::Move, child); + } else if !mono { + if self.split.get() == ContainerSplit::Horizontal { + if seat_data.x < rect.x1() { + break 'res ( + SeatOpKind::Resize { + 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; }; seat_data.op = Some(SeatOp { child, kind }) @@ -1049,6 +1092,7 @@ impl Node for ContainerNode { Some(c) => c, None => return, }; + node.focus_history.set(None); let link = node.append(ContainerChild { node: new.clone(), active: Cell::new(false), @@ -1056,6 +1100,8 @@ impl Node for ContainerNode { content: Cell::new(node.content.get()), factor: Cell::new(node.factor.get()), title: Default::default(), + title_rect: Cell::new(node.title_rect.get()), + focus_history: Cell::new(None), }); let body = link.body.get(); drop(node); @@ -1083,6 +1129,7 @@ impl Node for ContainerNode { } let node = { let node = node; + node.focus_history.set(None); node.to_ref() }; let num_children = self.num_children.fetch_sub(1) - 1; @@ -1137,6 +1184,7 @@ impl Node for ContainerNode { None => return, }; node.active.set(active); + node.focus_history.set(Some(self.focus_history.add_last(node.clone()))); self.schedule_compute_render_data(); } @@ -1242,5 +1290,6 @@ fn direction_to_split(dir: Direction) -> (ContainerSplit, bool) { Direction::Down => (ContainerSplit::Vertical, false), Direction::Up => (ContainerSplit::Vertical, true), Direction::Right => (ContainerSplit::Horizontal, false), + Direction::Unspecified => (ContainerSplit::Horizontal, true), } } diff --git a/src/tree/display.rs b/src/tree/display.rs index 993a6bc2..7fac3bee 100644 --- a/src/tree/display.rs +++ b/src/tree/display.rs @@ -4,7 +4,6 @@ use { cursor::KnownCursor, ifs::{ wl_seat::{NodeSeatState, WlSeatGlobal}, - wl_surface::xwindow::Xwindow, zwlr_layer_shell_v1::{OVERLAY, TOP}, }, tree::{walker::NodeVisitor, FindTreeResult, FoundNode, Node, NodeId, OutputNode}, @@ -17,7 +16,6 @@ pub struct DisplayNode { pub id: NodeId, pub outputs: CopyHashMap>, pub stacked: LinkedList>, - pub xstacked: LinkedList>, pub seat_state: NodeSeatState, } @@ -27,7 +25,6 @@ impl DisplayNode { id, outputs: Default::default(), stacked: Default::default(), - xstacked: Default::default(), seat_state: Default::default(), } } @@ -42,6 +39,10 @@ impl Node for DisplayNode { &self.seat_state } + fn visible(&self) -> bool { + true + } + fn destroy_node(&self, _detach: bool) { let mut outputs = self.outputs.lock(); for output in outputs.values() { @@ -79,7 +80,9 @@ impl Node for DisplayNode { x, 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; } tree.pop(); diff --git a/src/tree/float.rs b/src/tree/float.rs index 5ba18f7b..deb25e98 100644 --- a/src/tree/float.rs +++ b/src/tree/float.rs @@ -327,6 +327,18 @@ impl Node for FloatNode { &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) { let _v = self.display_link.take(); let _v = self.workspace_link.take(); diff --git a/src/tree/output.rs b/src/tree/output.rs index a55b6b46..58e77e9d 100644 --- a/src/tree/output.rs +++ b/src/tree/output.rs @@ -1,4 +1,3 @@ -use std::cell::Cell; use { crate::{ backend::Mode, @@ -8,6 +7,7 @@ use { wl_output::WlOutputGlobal, wl_seat::{NodeSeatState, WlSeatGlobal}, wl_surface::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, + zwlr_layer_shell_v1::{BACKGROUND, BOTTOM}, }, rect::Rect, render::{Renderer, Texture}, @@ -18,13 +18,12 @@ use { utils::{clonecell::CloneCell, errorfmt::ErrorFmt, linkedlist::LinkedList}, }, std::{ - cell::RefCell, + cell::{Cell, RefCell}, fmt::{Debug, Formatter}, ops::{Deref, Sub}, rc::Rc, }, }; -use crate::ifs::zwlr_layer_shell_v1::{BACKGROUND, BOTTOM}; tree_id!(OutputNodeId); pub struct OutputNode { @@ -119,12 +118,13 @@ impl OutputNode { } pub fn show_workspace(&self, ws: &Rc) { - ws.visible.set(true); if let Some(old) = self.workspace.set(Some(ws.clone())) { - if old.id != ws.id { - old.visible.set(false); + if old.id == ws.id { + return; } + old.visible.set(false); } + ws.visible.set(true); ws.clone().change_extents(&self.workspace_rect()); } @@ -172,7 +172,13 @@ impl OutputNode { self.global.send_mode(); } - pub fn find_layer_surface_at(&self, x: i32, y: i32, layers: &[u32], tree: &mut Vec) -> FindTreeResult { + pub fn find_layer_surface_at( + &self, + x: i32, + y: i32, + layers: &[u32], + tree: &mut Vec, + ) -> FindTreeResult { let len = tree.len(); for layer in layers.iter().copied() { for surface in self.layers[layer as usize].rev_iter() { @@ -218,6 +224,10 @@ impl Node for OutputNode { &self.seat_state } + fn visible(&self) -> bool { + true + } + fn destroy_node(&self, detach: bool) { if detach { self.state.root.clone().remove_child(self); diff --git a/src/tree/toplevel.rs b/src/tree/toplevel.rs index a756826a..019d6a84 100644 --- a/src/tree/toplevel.rs +++ b/src/tree/toplevel.rs @@ -18,6 +18,7 @@ pub trait ToplevelNode { fn set_active(&self, active: bool); fn activate(&self); fn toggle_floating(self: Rc); + fn close(&self); } #[derive(Default)] diff --git a/src/tree/walker.rs b/src/tree/walker.rs index f1a2f9a8..0d547480 100644 --- a/src/tree/walker.rs +++ b/src/tree/walker.rs @@ -108,6 +108,68 @@ impl NodeVisitor for T { } } +pub struct GenericNodeVisitor { + f: F, +} + +pub fn generic_node_visitor)>(f: F) -> GenericNodeVisitor { + GenericNodeVisitor { + f, + } +} + +impl)> NodeVisitor for GenericNodeVisitor { + fn visit_surface(&mut self, node: &Rc) { + (self.f)(node.clone()); + node.visit_children(self); + } + + fn visit_container(&mut self, node: &Rc) { + (self.f)(node.clone()); + node.visit_children(self); + } + + fn visit_toplevel(&mut self, node: &Rc) { + (self.f)(node.clone()); + node.visit_children(self); + } + + fn visit_popup(&mut self, node: &Rc) { + (self.f)(node.clone()); + node.visit_children(self); + } + + fn visit_display(&mut self, node: &Rc) { + (self.f)(node.clone()); + node.visit_children(self); + } + + fn visit_output(&mut self, node: &Rc) { + (self.f)(node.clone()); + node.visit_children(self); + } + + fn visit_float(&mut self, node: &Rc) { + (self.f)(node.clone()); + node.visit_children(self); + } + + fn visit_workspace(&mut self, node: &Rc) { + (self.f)(node.clone()); + node.visit_children(self); + } + + fn visit_layer_surface(&mut self, node: &Rc) { + (self.f)(node.clone()); + node.visit_children(self); + } + + fn visit_xwindow(&mut self, node: &Rc) { + (self.f)(node.clone()); + node.visit_children(self); + } +} + // pub fn visit_containers)>(f: F) -> impl NodeVisitor { // struct V(F); // impl)> NodeVisitorBase for V { diff --git a/src/tree/workspace.rs b/src/tree/workspace.rs index 7ba0d2c8..fcd7b9d1 100644 --- a/src/tree/workspace.rs +++ b/src/tree/workspace.rs @@ -48,6 +48,18 @@ impl Node for WorkspaceNode { &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) { if detach { self.output.get().remove_child(self); diff --git a/src/utils/linkedlist.rs b/src/utils/linkedlist.rs index 0a95aa22..9abecf6c 100644 --- a/src/utils/linkedlist.rs +++ b/src/utils/linkedlist.rs @@ -9,6 +9,8 @@ use { }, }; +const LINKED_NODE_REF_COUNT: usize = !(!0 >> 1); + pub struct LinkedList { root: LinkedNode, } @@ -28,7 +30,7 @@ impl Default for LinkedList { impl LinkedList { pub fn new() -> Self { let node = Box::into_raw(Box::new(NodeData { - rc: NumCell::new(1), + rc: NumCell::new(LINKED_NODE_REF_COUNT), prev: Cell::new(NonNull::dangling()), next: Cell::new(NonNull::dangling()), data: None, @@ -226,6 +228,14 @@ impl NodeRef { unsafe { append(self.data, t) } } + pub fn prepend_existing(&self, t: &NodeRef) { + unsafe { prepend_existing(self.data, t) } + } + + pub fn append_existing(&self, t: &NodeRef) { + unsafe { append_existing(self.data, t) } + } + fn peer(&self, peer: F) -> Option> where F: FnOnce(&NodeData) -> &Cell>>, @@ -249,6 +259,14 @@ impl NodeRef { pub fn next(&self) -> Option> { 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 { @@ -267,27 +285,13 @@ unsafe fn dec_ref_count(slf: NonNull>, n: usize) { impl Drop for LinkedNode { fn drop(&mut self) { unsafe { - { - 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); - } - dec_ref_count(self.data, 1); + self.detach(); + dec_ref_count(self.data, LINKED_NODE_REF_COUNT); } } } impl LinkedNode { - pub fn prepend(&self, t: T) -> LinkedNode { - unsafe { prepend(self.data, t) } - } - - pub fn append(&self, t: T) -> LinkedNode { - unsafe { append(self.data, t) } - } - pub fn to_ref(&self) -> NodeRef { unsafe { self.data.as_ref().rc.fetch_add(1); @@ -296,10 +300,24 @@ impl LinkedNode { } } +unsafe fn prepend_existing(data: NonNull>, t: &NodeRef) { + 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(data: NonNull>, t: T) -> LinkedNode { let dref = data.as_ref(); 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()), next: Cell::new(data), data: Some(t), @@ -309,10 +327,24 @@ unsafe fn prepend(data: NonNull>, t: T) -> LinkedNode { LinkedNode { data: node } } +unsafe fn append_existing(data: NonNull>, t: &NodeRef) { + 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(data: NonNull>, t: T) -> LinkedNode { let dref = data.as_ref(); 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), next: Cell::new(dref.next.get()), data: Some(t), diff --git a/src/video/drm.rs b/src/video/drm.rs index ff3f45ac..80771d37 100644 --- a/src/video/drm.rs +++ b/src/video/drm.rs @@ -2,6 +2,7 @@ mod sys; use { crate::{ + utils::oserror::OsError, video::drm::sys::{ 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, @@ -13,7 +14,6 @@ use { DRM_MODE_OBJECT_CRTC, DRM_MODE_OBJECT_ENCODER, DRM_MODE_OBJECT_FB, DRM_MODE_OBJECT_MODE, DRM_MODE_OBJECT_PLANE, DRM_MODE_OBJECT_PROPERTY, }, - utils::oserror::OsError, }, ahash::AHashMap, bstr::{BString, ByteSlice}, @@ -31,8 +31,8 @@ use { use crate::{ backend, - video::{dma::DmaBuf, INVALID_MODIFIER}, utils::{errorfmt::ErrorFmt, stack::Stack, syncqueue::SyncQueue, vec_ext::VecExt}, + video::{dma::DmaBuf, INVALID_MODIFIER}, }; pub use sys::{ drm_mode_modeinfo, DRM_CLIENT_CAP_ATOMIC, DRM_MODE_ATOMIC_ALLOW_MODESET, diff --git a/src/video/drm/sys.rs b/src/video/drm/sys.rs index b61e810d..c014e74a 100644 --- a/src/video/drm/sys.rs +++ b/src/video/drm/sys.rs @@ -3,13 +3,13 @@ use { crate::{ + utils::{bitflags::BitflagsExt, oserror::OsError, trim::AsciiTrim}, video::drm::{ DrmBlob, DrmCardResources, DrmConnector, DrmConnectorInfo, DrmCrtc, DrmEncoder, DrmEncoderInfo, DrmError, DrmFb, DrmModeInfo, DrmPlane, DrmPlaneInfo, DrmProperty, DrmPropertyDefinition, DrmPropertyEnumValue, DrmPropertyType, DrmPropertyValue, NodeType, }, - utils::{bitflags::BitflagsExt, oserror::OsError, trim::AsciiTrim}, }, ahash::AHashMap, bstr::ByteSlice, diff --git a/src/video/gbm.rs b/src/video/gbm.rs index 45fad1ec..45db93fe 100644 --- a/src/video/gbm.rs +++ b/src/video/gbm.rs @@ -1,11 +1,11 @@ use { crate::{ + format::formats, video::{ dma::{DmaBuf, DmaBufPlane}, drm::{Drm, DrmError}, ModifiedFormat, INVALID_MODIFIER, }, - format::formats, }, std::{ fmt::{Debug, Formatter}, diff --git a/src/xwayland.rs b/src/xwayland.rs index bfa7bac8..24d04f0a 100644 --- a/src/xwayland.rs +++ b/src/xwayland.rs @@ -271,4 +271,5 @@ pub enum XWaylandEvent { SurfaceDestroyed(WlSurfaceId), Configure(Rc), Activate(Rc), + Close(Rc), } diff --git a/src/xwayland/xwm.rs b/src/xwayland/xwm.rs index cb18daf6..caad89ef 100644 --- a/src/xwayland/xwm.rs +++ b/src/xwayland/xwm.rs @@ -55,6 +55,7 @@ atoms! { CLIPBOARD, CLIPBOARD_MANAGER, + COMPOUND_TEXT, DELETE, INCR, _MOTIF_WM_HINTS, @@ -370,6 +371,7 @@ impl Wm { XWaylandEvent::Configure(event) => self.handle_xwayland_configure(event).await, XWaylandEvent::SurfaceDestroyed(event) => self.handle_xwayland_surface_destroyed(event), 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 == self.atoms.UTF8_STRING => {} Ok(ty) => { - log::error!("WM_WINDOW_ROLE property has unexpected type {}", ty); + self.unexpected_type(data.window_id, "WM_WINDOW_ROLE", ty).await; return; } Err(XconError::PropertyUnavailable) => { @@ -563,7 +565,7 @@ impl Wm { Ok(ty) if ty == ATOM_STRING => {} Ok(ty) if ty == self.atoms.UTF8_STRING => {} Ok(ty) => { - log::error!("WM_CLASS property has unexpected type {}", ty); + self.unexpected_type(data.window_id, "WM_CLASS", ty).await; return; } 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 => {} + Ok(ty) if ty == self.atoms.COMPOUND_TEXT => {} // used by java. assume utf-8. Ok(ty) if ty == self.atoms.UTF8_STRING => { data.info.utf8_title.set(true); } Ok(ty) => { - log::error!("{} property has unexpected type {}", name, ty); + self.unexpected_type(data.window_id, name, ty).await; return; } Err(XconError::PropertyUnavailable) => return, @@ -607,6 +610,15 @@ impl Wm { 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) { self.load_window_wm_name2(data, ATOM_WM_NAME, "WM_NAME") .await; @@ -786,7 +798,7 @@ impl Wm { Ok(ty) if ty == ATOM_STRING => {} Ok(ty) if ty == self.atoms.UTF8_STRING => {} Ok(ty) => { - log::error!("_NET_STARTUP_ID property has unexpected type {}", ty); + self.unexpected_type(data.window_id, "_NET_STARTUP_ID", ty).await; return; } Err(XconError::PropertyUnavailable) => return,