From 6ad6d83b7ee4069e8e46118e6afd9d7eef3fd0f1 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 2 Apr 2022 00:31:30 +0200 Subject: [PATCH] autocommit 2022-04-02 00:31:30 CEST --- default-config/src/lib.rs | 5 +- jay-config/src/_private/client.rs | 4 +- jay-config/src/_private/ipc.rs | 4 +- jay-config/src/input.rs | 22 ++--- jay-config/src/input/acceleration.rs | 7 ++ jay-config/src/input/capability.rs | 12 +++ src/backends/metal.rs | 27 +++++- src/backends/metal/input.rs | 12 +++ src/backends/metal/monitor.rs | 4 + src/cli.rs | 11 +++ src/cli/set_log_level.rs | 28 ++++++ src/compositor.rs | 32 ++++--- src/config/handler.rs | 45 +++------- src/ifs/jay_compositor.rs | 35 +++++++- src/ifs/wl_seat.rs | 6 +- src/ifs/wl_seat/event_handling.rs | 6 ++ src/ifs/wl_seat/kb_owner.rs | 37 +++++++- src/ifs/wl_surface.rs | 11 ++- src/ifs/wl_surface/wl_subsurface.rs | 4 + src/ifs/wl_surface/xdg_surface.rs | 4 + src/ifs/wl_surface/xdg_surface/xdg_popup.rs | 6 +- .../wl_surface/xdg_surface/xdg_toplevel.rs | 10 +-- src/ifs/wl_surface/xwindow.rs | 10 +-- src/ifs/wl_surface/zwlr_layer_surface_v1.rs | 10 +-- src/keymap.xkb | 11 +++ src/state.rs | 89 ++++++++++++++----- src/tasks/output.rs | 10 ++- src/tree.rs | 4 + src/tree/container.rs | 25 +++++- src/tree/float.rs | 6 +- src/tree/output.rs | 82 +++++++++-------- src/tree/toplevel.rs | 3 +- src/tree/workspace.rs | 21 +++-- wire/jay_compositor.txt | 4 + 34 files changed, 446 insertions(+), 161 deletions(-) create mode 100644 jay-config/src/input/acceleration.rs create mode 100644 jay-config/src/input/capability.rs create mode 100644 src/cli/set_log_level.rs diff --git a/default-config/src/lib.rs b/default-config/src/lib.rs index ff7a6a34..0ff7591a 100644 --- a/default-config/src/lib.rs +++ b/default-config/src/lib.rs @@ -1,5 +1,6 @@ use jay_config::embedded::grab_input_device; -use jay_config::input::{InputDevice, CAP_KEYBOARD, CAP_POINTER}; +use jay_config::input::capability::{CAP_KEYBOARD, CAP_POINTER}; +use jay_config::input::InputDevice; use jay_config::keyboard::mods::{Modifiers, ALT, CTRL, SHIFT}; use jay_config::keyboard::syms::{ SYM_Super_L, SYM_b, SYM_d, SYM_f, SYM_h, SYM_j, SYM_k, SYM_l, SYM_m, SYM_p, SYM_q, SYM_t, @@ -40,7 +41,7 @@ fn configure_seat(s: Seat) { s.bind(SYM_Super_L, || Command::new("alacritty").spawn()); - s.bind(MOD | SYM_p, || Command::new("xeyes").spawn()); + s.bind(MOD | SYM_p, || Command::new("bemenu-run").spawn()); s.bind(MOD | SYM_q, quit); diff --git a/jay-config/src/_private/client.rs b/jay-config/src/_private/client.rs index 7660f029..ab1048ac 100644 --- a/jay-config/src/_private/client.rs +++ b/jay-config/src/_private/client.rs @@ -2,7 +2,9 @@ use crate::_private::ipc::{ClientMessage, InitMessage, Response, ServerMessage}; use crate::_private::{bincode_ops, logging, Config, ConfigEntry, ConfigEntryGen, VERSION}; -use crate::input::{AccelProfile, Capability, InputDevice}; +use crate::input::acceleration::AccelProfile; +use crate::input::capability::Capability; +use crate::input::InputDevice; use crate::keyboard::keymap::Keymap; use crate::theme::Color; use crate::{Axis, Command, Direction, LogLevel, ModifiedKeySym, Seat, Workspace}; diff --git a/jay-config/src/_private/ipc.rs b/jay-config/src/_private/ipc.rs index a7cfa5ff..90a53148 100644 --- a/jay-config/src/_private/ipc.rs +++ b/jay-config/src/_private/ipc.rs @@ -1,4 +1,6 @@ -use crate::input::{AccelProfile, Capability, InputDevice}; +use crate::input::acceleration::AccelProfile; +use crate::input::capability::Capability; +use crate::input::InputDevice; use crate::keyboard::keymap::Keymap; use crate::keyboard::mods::Modifiers; use crate::keyboard::syms::KeySym; diff --git a/jay-config/src/input.rs b/jay-config/src/input.rs index d1ea63fe..822772f8 100644 --- a/jay-config/src/input.rs +++ b/jay-config/src/input.rs @@ -1,3 +1,8 @@ +pub mod acceleration; +pub mod capability; + +use crate::input::acceleration::AccelProfile; +use crate::input::capability::Capability; use crate::Seat; use bincode::{Decode, Encode}; @@ -33,20 +38,3 @@ impl InputDevice { get!(String::new()).device_name(self) } } - -#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)] -pub struct Capability(pub u32); - -pub const CAP_KEYBOARD: Capability = Capability(0); -pub const CAP_POINTER: Capability = Capability(1); -pub const CAP_TOUCH: Capability = Capability(2); -pub const CAP_TABLET_TOOL: Capability = Capability(3); -pub const CAP_TABLET_PAD: Capability = Capability(4); -pub const CAP_GESTURE: Capability = Capability(5); -pub const CAP_SWITCH: Capability = Capability(6); - -#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)] -pub struct AccelProfile(pub u32); - -pub const ACCEL_PROFILE_FLAT: AccelProfile = AccelProfile(1 << 0); -pub const ACCEL_PROFILE_ADAPTIVE: AccelProfile = AccelProfile(1 << 1); diff --git a/jay-config/src/input/acceleration.rs b/jay-config/src/input/acceleration.rs new file mode 100644 index 00000000..345d915f --- /dev/null +++ b/jay-config/src/input/acceleration.rs @@ -0,0 +1,7 @@ +use bincode::{Decode, Encode}; + +#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)] +pub struct AccelProfile(pub u32); + +pub const ACCEL_PROFILE_FLAT: AccelProfile = AccelProfile(1 << 0); +pub const ACCEL_PROFILE_ADAPTIVE: AccelProfile = AccelProfile(1 << 1); diff --git a/jay-config/src/input/capability.rs b/jay-config/src/input/capability.rs new file mode 100644 index 00000000..fe5b3929 --- /dev/null +++ b/jay-config/src/input/capability.rs @@ -0,0 +1,12 @@ +use bincode::{Decode, Encode}; + +#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)] +pub struct Capability(pub u32); + +pub const CAP_KEYBOARD: Capability = Capability(0); +pub const CAP_POINTER: Capability = Capability(1); +pub const CAP_TOUCH: Capability = Capability(2); +pub const CAP_TABLET_TOOL: Capability = Capability(3); +pub const CAP_TABLET_PAD: Capability = Capability(4); +pub const CAP_GESTURE: Capability = Capability(5); +pub const CAP_SWITCH: Capability = Capability(6); diff --git a/src/backends/metal.rs b/src/backends/metal.rs index 926d27da..55995de2 100644 --- a/src/backends/metal.rs +++ b/src/backends/metal.rs @@ -3,9 +3,7 @@ mod monitor; mod video; use crate::async_engine::{AsyncError, AsyncFd}; -use crate::backend::{ - Backend, InputDevice, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId, InputEvent, -}; +use crate::backend::{Backend, InputDevice, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId, InputEvent, KeyState}; use crate::backends::metal::video::{MetalDrmDevice, PendingDrmDevice}; use crate::dbus::DbusError; use crate::drm::drm::DrmError; @@ -30,9 +28,11 @@ use crate::utils::syncqueue::SyncQueue; use std::cell::{Cell, RefCell}; use std::ffi::{CStr, CString}; use std::future::pending; +use std::mem; use std::rc::Rc; use thiserror::Error; use uapi::{c, OwnedFd}; +use crate::utils::smallmap::SmallMap; #[derive(Debug, Error)] pub enum MetalError { @@ -198,6 +198,10 @@ struct MetalInputDevice { vscroll: Cell, name: CloneCell>, + // state + pressed_keys: SmallMap, + pressed_buttons: SmallMap, + // config left_handed: Cell>, accel_profile: Cell>, @@ -205,6 +209,14 @@ struct MetalInputDevice { transform_matrix: Cell>, } +impl Drop for MetalInputDevice { + fn drop(&mut self) { + if let Some(fd) = self.fd.take() { + mem::forget(fd); + } + } +} + #[derive(Clone)] enum MetalDevice { Input(Rc), @@ -250,6 +262,15 @@ impl MetalInputDevice { dev.device().set_accel_speed(speed); } } + + fn pre_pause(&self) { + for (key, _) in self.pressed_keys.take() { + self.event(InputEvent::Key(key, KeyState::Released)); + } + for (button, _) in self.pressed_buttons.take() { + self.event(InputEvent::Button(button, KeyState::Released)); + } + } } impl InputDevice for MetalInputDevice { diff --git a/src/backends/metal/input.rs b/src/backends/metal/input.rs index 63a7c434..94c169c8 100644 --- a/src/backends/metal/input.rs +++ b/src/backends/metal/input.rs @@ -93,8 +93,14 @@ impl MetalBackend { fn handle_keyboard_key(self: &Rc, event: LibInputEvent) { let (event, dev) = unpack!(self, event, keyboard_event); let state = if event.key_state() == LIBINPUT_KEY_STATE_PRESSED { + if dev.pressed_keys.insert(event.key(), ()).is_some() { + return; + } KeyState::Pressed } else { + if dev.pressed_keys.remove(&event.key()).is_none() { + return; + } KeyState::Released }; dev.event(InputEvent::Key(event.key(), state)); @@ -132,8 +138,14 @@ impl MetalBackend { fn handle_pointer_button(self: &Rc, event: LibInputEvent) { let (event, dev) = unpack!(self, event, pointer_event); let state = if event.button_state() == LIBINPUT_BUTTON_STATE_PRESSED { + if dev.pressed_buttons.insert(event.button(), ()).is_some() { + return; + } KeyState::Pressed } else { + if dev.pressed_buttons.remove(&event.button()).is_none() { + return; + } KeyState::Released }; dev.event(InputEvent::Button(event.button(), state)); diff --git a/src/backends/metal/monitor.rs b/src/backends/metal/monitor.rs index 963d1661..a6223347 100644 --- a/src/backends/metal/monitor.rs +++ b/src/backends/metal/monitor.rs @@ -119,6 +119,7 @@ impl MetalBackend { } fn handle_input_device_removed(self: &Rc, dev: &Rc) { + dev.pre_pause(); log::info!("Device removed: {}", dev.devnode.to_bytes().as_bstr()); self.device_holder.input_devices.borrow_mut()[dev.slot] = None; dev.fd.set(None); @@ -148,6 +149,7 @@ impl MetalBackend { fn handle_input_device_paused(self: &Rc, dev: &Rc) { log::info!("Device paused: {}", dev.devnode.to_bytes().as_bstr()); + dev.pre_pause(); if let Some(rd) = dev.inputdev.take() { rd.device().unset_slot(); } @@ -282,6 +284,8 @@ impl MetalBackend { hscroll: Cell::new(0.0), vscroll: Cell::new(0.0), name: Default::default(), + pressed_keys: Default::default(), + pressed_buttons: Default::default(), left_handed: Default::default(), accel_profile: Default::default(), accel_speed: Default::default(), diff --git a/src/cli.rs b/src/cli.rs index 1b93ab60..1f62795c 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,6 +1,7 @@ mod generate; mod log; mod quit; +mod set_log_level; use crate::compositor::start_compositor; use ::log::Level; @@ -31,6 +32,8 @@ pub enum Cmd { GenerateCompletion(GenerateArgs), /// Open the log file. Log(LogArgs), + /// Sets the log level. + SetLogLevel(SetLogArgs), /// Stop the compositor. Quit, } @@ -61,6 +64,13 @@ pub struct LogArgs { pager_end: bool, } +#[derive(Args, Debug)] +pub struct SetLogArgs { + /// The new log level. + #[clap(arg_enum)] + level: CliLogLevel, +} + #[derive(ArgEnum, Debug, Copy, Clone, Hash)] pub enum CliBackend { X11, @@ -108,5 +118,6 @@ pub fn main() { Cmd::GenerateCompletion(g) => generate::main(g), Cmd::Log(a) => log::main(cli.global, a), Cmd::Quit => quit::main(cli.global), + Cmd::SetLogLevel(a) => set_log_level::main(cli.global, a), } } diff --git a/src/cli/set_log_level.rs b/src/cli/set_log_level.rs new file mode 100644 index 00000000..672008ba --- /dev/null +++ b/src/cli/set_log_level.rs @@ -0,0 +1,28 @@ +use std::rc::Rc; +use crate::cli::{GlobalArgs, SetLogArgs}; +use crate::tools::tool_client::ToolClient; +use crate::wire::jay_compositor::SetLogLevel; + +pub fn main(global: GlobalArgs, args: SetLogArgs) { + let tc = ToolClient::new(global.log_level.into()); + let logger = Rc::new(Log { + tc: tc.clone(), + args, + }); + tc.run(run(logger)); +} + +struct Log { + tc: Rc, + args: SetLogArgs, +} + +async fn run(log: Rc) { + let tc = &log.tc; + let comp = tc.jay_compositor().await; + tc.send(SetLogLevel { + self_id: comp, + level: log.args.level as u32, + }); + tc.round_trip().await; +} diff --git a/src/compositor.rs b/src/compositor.rs index 4fca3114..906dcd79 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -1,5 +1,6 @@ use crate::acceptor::{Acceptor, AcceptorError}; use crate::async_engine::{AsyncEngine, AsyncError, Phase}; +use crate::backends::dummy::DummyOutput; use crate::cli::{GlobalArgs, RunArgs}; use crate::client::Clients; use crate::clientmem::ClientMemError; @@ -8,12 +9,17 @@ use crate::dbus::Dbus; use crate::event_loop::{EventLoop, EventLoopError}; use crate::forker::ForkerError; use crate::globals::Globals; +use crate::ifs::wl_output::WlOutputGlobal; use crate::ifs::wl_surface::NoneSurfaceExt; use crate::logger::Logger; use crate::render::RenderError; use crate::sighand::SighandError; use crate::state::State; -use crate::tree::{container_layout, container_render_data, float_layout, float_titles, DisplayNode, NodeIds, OutputNode, WorkspaceNode}; +use crate::tree::{ + container_layout, container_render_data, float_layout, float_titles, DisplayNode, NodeIds, + OutputNode, WorkspaceNode, +}; +use crate::utils::clonecell::CloneCell; use crate::utils::errorfmt::ErrorFmt; use crate::utils::fdcloser::FdCloser; use crate::utils::numcell::NumCell; @@ -23,14 +29,11 @@ use crate::wheel::{Wheel, WheelError}; use crate::xkbcommon::XkbContext; use crate::{clientmem, forker, leaks, render, sighand, tasks, xwayland}; use forker::ForkerProxy; -use std::cell::{Cell}; +use std::cell::Cell; use std::ops::Deref; use std::rc::Rc; use std::sync::Arc; use thiserror::Error; -use crate::backends::dummy::DummyOutput; -use crate::ifs::wl_output::WlOutputGlobal; -use crate::utils::clonecell::CloneCell; pub fn start_compositor(global: GlobalArgs, args: RunArgs) { let logger = Logger::install_compositor(global.log_level.into()); @@ -118,9 +121,12 @@ fn main_(logger: Arc, _args: &RunArgs) -> Result<(), MainError> { let dummy_output = Rc::new(OutputNode { id: state.node_ids.next(), position: Default::default(), - global: Rc::new(WlOutputGlobal::new(state.globals.name(), Rc::new(DummyOutput { - id: state.output_ids.next(), - }))), + global: Rc::new(WlOutputGlobal::new( + state.globals.name(), + Rc::new(DummyOutput { + id: state.output_ids.next(), + }), + )), workspaces: Default::default(), workspace: Default::default(), seat_state: Default::default(), @@ -132,13 +138,17 @@ fn main_(logger: Arc, _args: &RunArgs) -> Result<(), MainError> { let dummy_workspace = Rc::new(WorkspaceNode { id: state.node_ids.next(), output: CloneCell::new(dummy_output.clone()), + position: Default::default(), container: Default::default(), stacked: Default::default(), seat_state: Default::default(), - name: "dummy".to_string() + name: "dummy".to_string(), + output_link: Default::default(), }); - dummy_output.workspace.set(Some(dummy_workspace.clone())); - dummy_output.workspaces.borrow_mut().push(dummy_workspace); + dummy_workspace.output_link.set(Some( + dummy_output.workspaces.add_last(dummy_workspace.clone()), + )); + dummy_output.show_workspace(&dummy_workspace); state.dummy_output.set(Some(dummy_output)); } forker.install(&state); diff --git a/src/config/handler.rs b/src/config/handler.rs index 31a88c79..361ec426 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -3,7 +3,7 @@ use crate::backend::{InputDeviceAccelProfile, InputDeviceCapability, InputDevice use crate::ifs::wl_seat::{SeatId, WlSeatGlobal}; use crate::state::{DeviceHandlerData, State}; use crate::tree::walker::NodeVisitorBase; -use crate::tree::{ContainerNode, ContainerSplit, FloatNode, Node, WorkspaceNode}; +use crate::tree::{ContainerNode, ContainerSplit, FloatNode, Node}; use crate::utils::copyhashmap::CopyHashMap; use crate::utils::debug_fn::debug_fn; use crate::utils::errorfmt::ErrorFmt; @@ -13,9 +13,13 @@ use crate::xkbcommon::XkbKeymap; use bincode::error::DecodeError; use jay_config::_private::bincode_ops; use jay_config::_private::ipc::{ClientMessage, Response, ServerMessage}; +use jay_config::input::acceleration::{AccelProfile, ACCEL_PROFILE_ADAPTIVE, ACCEL_PROFILE_FLAT}; +use jay_config::input::capability::{ + Capability, CAP_GESTURE, CAP_KEYBOARD, CAP_POINTER, CAP_SWITCH, CAP_TABLET_PAD, + CAP_TABLET_TOOL, CAP_TOUCH, +}; use jay_config::input::{ - AccelProfile, Capability, InputDevice, ACCEL_PROFILE_ADAPTIVE, ACCEL_PROFILE_FLAT, CAP_GESTURE, - CAP_KEYBOARD, CAP_POINTER, CAP_SWITCH, CAP_TABLET_PAD, CAP_TABLET_TOOL, CAP_TOUCH, + InputDevice, }; use jay_config::keyboard::keymap::Keymap; use jay_config::keyboard::mods::Modifiers; @@ -26,7 +30,6 @@ use log::Level; use std::cell::Cell; use std::rc::Rc; use thiserror::Error; -use crate::utils::clonecell::CloneCell; pub(super) struct ConfigProxyHandler { pub client_data: Cell<*const u8>, @@ -163,7 +166,7 @@ impl ConfigProxyHandler { fn get_workspace(&self, ws: Workspace) -> Result, CphError> { match self.workspaces_by_id.get(&ws.0) { Some(ws) => Ok(ws), - _ => Err(CphError::WorkspaceDoesNotExist(ws)) + _ => Err(CphError::WorkspaceDoesNotExist(ws)), } } @@ -283,33 +286,7 @@ impl ConfigProxyHandler { fn handle_show_workspace(&self, seat: Seat, ws: Workspace) -> Result<(), ShowWorkspaceError> { let seat = self.get_seat(seat)?; let name = self.get_workspace(ws)?; - let output = match self.state.workspaces.get(name.as_str()) { - Some(ws) => { - let output = ws.output.get(); - output.workspace.set(Some(ws.clone())); - output - } - None => { - let output = seat.get_output(); - if output.is_dummy { - return Ok(()); - } - let ws = Rc::new(WorkspaceNode { - id: self.state.node_ids.next(), - output: CloneCell::new(output.clone()), - container: Default::default(), - stacked: Default::default(), - seat_state: Default::default(), - name: name.to_string(), - }); - output.workspaces.borrow_mut().push(ws.clone()); - output.workspace.set(Some(ws.clone())); - self.state.workspaces.set(name.to_string(), ws); - output - } - }; - output.update_render_data(); - self.state.tree_changed(); + self.state.show_workspace(&seat, &name); Ok(()) } @@ -653,7 +630,9 @@ impl ConfigProxyHandler { } ClientMessage::GetDeviceName { device } => self.handle_get_device_name(device)?, ClientMessage::GetWorkspace { name } => self.handle_get_workspace(name), - ClientMessage::ShowWorkspace { seat, workspace } => self.handle_show_workspace(seat, workspace)?, + ClientMessage::ShowWorkspace { seat, workspace } => { + self.handle_show_workspace(seat, workspace)? + } } Ok(()) } diff --git a/src/ifs/jay_compositor.rs b/src/ifs/jay_compositor.rs index c3e99066..4ed23efb 100644 --- a/src/ifs/jay_compositor.rs +++ b/src/ifs/jay_compositor.rs @@ -7,7 +7,9 @@ use crate::utils::buffd::{MsgParser, MsgParserError}; use crate::wire::jay_compositor::*; use crate::wire::JayCompositorId; use std::rc::Rc; +use log::Level; use thiserror::Error; +use crate::cli::CliLogLevel; pub struct JayCompositorGlobal { name: GlobalName, @@ -81,6 +83,25 @@ impl JayCompositor { self.client.state.el.stop(); Ok(()) } + + fn set_log_level(&self, parser: MsgParser<'_, '_>) -> Result<(), SetLogLevelError> { + let req: SetLogLevel = self.client.parse(self, parser)?; + const ERROR: u32 = CliLogLevel::Error as u32; + const WARN: u32 = CliLogLevel::Warn as u32; + const INFO: u32 = CliLogLevel::Info as u32; + const DEBUG: u32 = CliLogLevel::Debug as u32; + const TRACE: u32 = CliLogLevel::Trace as u32; + let level = match req.level { + ERROR => Level::Error, + WARN => Level::Warn, + INFO => Level::Info, + DEBUG => Level::Debug, + TRACE => Level::Trace, + _ => return Err(SetLogLevelError::UnknownLogLevel(req.level)), + }; + self.client.state.logger.set_level(level); + Ok(()) + } } object_base! { @@ -89,11 +110,12 @@ object_base! { DESTROY => destroy, GET_LOG_FILE => get_log_file, QUIT => quit, + SET_LOG_LEVEL => set_log_level, } impl Object for JayCompositor { fn num_requests(&self) -> u32 { - QUIT + 1 + SET_LOG_LEVEL + 1 } } @@ -107,6 +129,8 @@ pub enum JayCompositorError { GetLogFileError(#[from] GetLogFileError), #[error("Could not process a `quit` request")] QuitError(#[from] QuitError), + #[error("Could not process a `set_log_level` request")] + SetLogLevelError(#[from] SetLogLevelError), #[error(transparent)] ClientError(Box), } @@ -138,3 +162,12 @@ pub enum QuitError { MsgParserError(#[source] Box), } efrom!(QuitError, MsgParserError); + +#[derive(Debug, Error)] +pub enum SetLogLevelError { + #[error("Parsing failed")] + MsgParserError(#[source] Box), + #[error("Unknown log level {0}")] + UnknownLogLevel(u32), +} +efrom!(SetLogLevelError, MsgParserError); diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index 16472ea4..606c40c4 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -48,7 +48,7 @@ use jay_config::Direction; use std::cell::{Cell, RefCell}; use std::collections::hash_map::Entry; use std::mem; -use std::ops::{DerefMut}; +use std::ops::DerefMut; use std::rc::Rc; use thiserror::Error; use uapi::{c, Errno, OwnedFd}; @@ -373,6 +373,10 @@ impl WlSeatGlobal { self.id } + pub fn workspace_changed(self: &Rc, output: &Rc) { + self.kb_owner.workspace_changed(self, output); + } + fn bind_( self: Rc, id: WlSeatId, diff --git a/src/ifs/wl_seat/event_handling.rs b/src/ifs/wl_seat/event_handling.rs index 2f8c5132..2671cae4 100644 --- a/src/ifs/wl_seat/event_handling.rs +++ b/src/ifs/wl_seat/event_handling.rs @@ -192,8 +192,14 @@ impl WlSeatGlobal { } pub fn last_tiled_keyboard_toplevel(&self, new: &dyn Node) -> Option> { + let output = self.output.get(); + let workspace = output.workspace.get().unwrap(); let is_container = new.is_container(); for tl in self.toplevel_focus_history.rev_iter() { + match tl.as_node().get_workspace() { + Some(ws) if ws.id == workspace.id => { }, + _ => continue, + }; let parent_is_float = match tl.parent() { Some(pn) => pn.is_float(), _ => false, diff --git a/src/ifs/wl_seat/kb_owner.rs b/src/ifs/wl_seat/kb_owner.rs index b22739ac..8148212d 100644 --- a/src/ifs/wl_seat/kb_owner.rs +++ b/src/ifs/wl_seat/kb_owner.rs @@ -1,5 +1,6 @@ +use std::ops::Deref; use crate::ifs::wl_seat::WlSeatGlobal; -use crate::tree::Node; +use crate::tree::{Node, OutputNode}; use crate::utils::clonecell::CloneCell; use std::rc::Rc; @@ -29,6 +30,10 @@ impl KbOwnerHolder { pub fn set_kb_node(&self, seat: &Rc, node: Rc) { self.owner.get().set_kb_node(seat, node); } + + pub fn workspace_changed(&self, seat: &Rc, output: &Rc) { + self.owner.get().workspace_changed(seat, output); + } } struct DefaultKbOwner; @@ -39,6 +44,7 @@ trait KbOwner { fn grab(&self, seat: &Rc, node: Rc) -> bool; fn ungrab(&self, seat: &Rc); fn set_kb_node(&self, seat: &Rc, node: Rc); + fn workspace_changed(&self, seat: &Rc, output: &Rc); } impl KbOwner for DefaultKbOwner { @@ -68,6 +74,31 @@ impl KbOwner for DefaultKbOwner { node.clone().focus(seat); seat.keyboard_node.set(node.clone()); } + + fn workspace_changed(&self, seat: &Rc, output: &Rc) { + let new_ws = match output.workspace.get() { + Some(ws) => ws, + _ => return, + }; + let node = seat.keyboard_node.get(); + let ws = match node.get_workspace() { + None => return, + Some(ws) => ws, + }; + let ws_output = ws.output.get(); + if ws_output.id != output.id { + return; + } + for tl in seat.toplevel_focus_history.rev_iter() { + if let Some(tl_ws) = tl.as_node().get_workspace() { + if tl_ws.id == new_ws.id { + self.set_kb_node(seat, tl.deref().clone().into_node()); + return; + } + } + } + self.set_kb_node(seat, seat.state.root.clone()); + } } impl KbOwner for GrabKbOwner { @@ -82,4 +113,8 @@ impl KbOwner for GrabKbOwner { fn set_kb_node(&self, _seat: &Rc, _node: Rc) { // nothing } + + fn workspace_changed(&self, _seat: &Rc, _output: &Rc) { + // nothing + } } diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index f108f31e..e6cb0fd5 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -21,7 +21,7 @@ use crate::rect::Rect; use crate::render::Renderer; use crate::tree::toplevel::ToplevelNode; use crate::tree::walker::NodeVisitor; -use crate::tree::{ContainerNode, ContainerSplit, Node, NodeId}; +use crate::tree::{ContainerNode, ContainerSplit, Node, NodeId, WorkspaceNode}; use crate::utils::buffd::{MsgParser, MsgParserError}; use crate::utils::clonecell::CloneCell; use crate::utils::linkedlist::LinkedList; @@ -643,6 +643,13 @@ impl Node for WlSurface { } } + fn get_workspace(&self) -> Option> { + if let Some(tl) = self.toplevel.get() { + return tl.as_node().get_workspace(); + } + None + } + fn get_parent_mono(&self) -> Option { self.toplevel .get() @@ -679,7 +686,7 @@ impl Node for WlSurface { Some(tl) => tl, _ => return, }; - let ws = match tl.workspace() { + let ws = match tl.as_node().get_workspace() { Some(ws) => ws, _ => return, }; diff --git a/src/ifs/wl_surface/wl_subsurface.rs b/src/ifs/wl_surface/wl_subsurface.rs index db6b1754..28968f63 100644 --- a/src/ifs/wl_surface/wl_subsurface.rs +++ b/src/ifs/wl_surface/wl_subsurface.rs @@ -289,6 +289,10 @@ impl SurfaceExt for WlSubsurface { fn into_subsurface(self: Rc) -> Option> { Some(self) } + + fn accepts_kb_focus(&self) -> bool { + self.parent.accepts_kb_focus() + } } #[derive(Debug, Error)] diff --git a/src/ifs/wl_surface/xdg_surface.rs b/src/ifs/wl_surface/xdg_surface.rs index fc5cda1e..5705a0be 100644 --- a/src/ifs/wl_surface/xdg_surface.rs +++ b/src/ifs/wl_surface/xdg_surface.rs @@ -356,6 +356,10 @@ impl SurfaceExt for XdgSurface { fn extents_changed(&self) { self.update_extents(); } + + fn accepts_kb_focus(&self) -> bool { + self.role.get() == XdgSurfaceRole::XdgToplevel + } } #[derive(Debug, Error)] diff --git a/src/ifs/wl_surface/xdg_surface/xdg_popup.rs b/src/ifs/wl_surface/xdg_surface/xdg_popup.rs index 6b9dd7f7..ef06358a 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_popup.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_popup.rs @@ -1,7 +1,7 @@ use crate::client::{Client, ClientError}; use crate::cursor::KnownCursor; use crate::fixed::Fixed; -use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal}; +use crate::ifs::wl_seat::{ NodeSeatState, WlSeatGlobal}; use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceError, XdgSurfaceExt}; use crate::ifs::xdg_positioner::{XdgPositioned, XdgPositioner, CA}; use crate::leaks::Tracker; @@ -281,6 +281,10 @@ impl Node for XdgPopup { visitor.visit_surface(&self.xdg.surface); } + fn get_workspace(&self) -> Option> { + self.xdg.workspace.get() + } + fn absolute_position(&self) -> Rect { self.xdg.absolute_desired_extents.get() } diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs index 4743b44d..8929684d 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs @@ -12,7 +12,7 @@ use crate::rect::Rect; use crate::render::Renderer; use crate::tree::toplevel::{ToplevelData, ToplevelNode}; use crate::tree::walker::NodeVisitor; -use crate::tree::FindTreeResult; +use crate::tree::{FindTreeResult}; use crate::tree::{FoundNode, Node, NodeId, ToplevelNodeId, WorkspaceNode}; use crate::utils::buffd::MsgParser; use crate::utils::buffd::MsgParserError; @@ -374,6 +374,10 @@ impl Node for XdgToplevel { visitor.visit_surface(&self.xdg.surface); } + fn get_workspace(&self) -> Option> { + self.xdg.workspace.get() + } + fn is_contained_in(&self, other: NodeId) -> bool { if let Some(parent) = self.parent_node.get() { if parent.id() == other { @@ -443,10 +447,6 @@ impl ToplevelNode for XdgToplevel { self.parent_node.get() } - fn workspace(&self) -> Option> { - self.xdg.workspace.get() - } - fn as_node(&self) -> &dyn Node { self } diff --git a/src/ifs/wl_surface/xwindow.rs b/src/ifs/wl_surface/xwindow.rs index 2e407639..fec84891 100644 --- a/src/ifs/wl_surface/xwindow.rs +++ b/src/ifs/wl_surface/xwindow.rs @@ -1,4 +1,4 @@ -use crate::client::Client; +use crate::client::{Client}; use crate::cursor::KnownCursor; use crate::fixed::Fixed; use crate::ifs::wl_seat::{NodeSeatState, SeatId, WlSeatGlobal}; @@ -353,6 +353,10 @@ impl Node for Xwindow { visitor.visit_surface(&self.surface); } + fn get_workspace(&self) -> Option> { + self.workspace.get() + } + fn is_contained_in(&self, other: NodeId) -> bool { if let Some(parent) = self.parent_node.get() { if parent.id() == other { @@ -429,10 +433,6 @@ impl ToplevelNode for Xwindow { self.parent_node.get() } - fn workspace(&self) -> Option> { - self.workspace.get() - } - fn as_node(&self) -> &dyn Node { self } diff --git a/src/ifs/wl_surface/zwlr_layer_surface_v1.rs b/src/ifs/wl_surface/zwlr_layer_surface_v1.rs index 13e52c52..8f59a57e 100644 --- a/src/ifs/wl_surface/zwlr_layer_surface_v1.rs +++ b/src/ifs/wl_surface/zwlr_layer_surface_v1.rs @@ -1,5 +1,5 @@ use crate::client::{Client, ClientError}; -use crate::ifs::wl_seat::NodeSeatState; +use crate::ifs::wl_seat::{NodeSeatState}; use crate::ifs::wl_surface::{ CommitAction, CommitContext, SurfaceExt, SurfaceRole, WlSurface, WlSurfaceError, }; @@ -359,10 +359,6 @@ impl Node for ZwlrLayerSurfaceV1 { self.surface.clone().visit(visitor); } - fn render(&self, renderer: &mut Renderer, x: i32, y: i32) { - renderer.render_layer_surface(self, x, y); - } - fn absolute_position(&self) -> Rect { self.pos.get() } @@ -376,6 +372,10 @@ impl Node for ZwlrLayerSurfaceV1 { self.surface.find_tree_at(x, y, tree) } + fn render(&self, renderer: &mut Renderer, x: i32, y: i32) { + renderer.render_layer_surface(self, x, y); + } + fn change_extents(self: Rc, _rect: &Rect) { self.compute_position(); } diff --git a/src/keymap.xkb b/src/keymap.xkb index 57f852a4..eb016915 100644 --- a/src/keymap.xkb +++ b/src/keymap.xkb @@ -87,6 +87,10 @@ xkb_keymap { <83> = 91; # KPDOT <87> = 95; # F11 <88> = 96; # F12 + <89> = 97; # RO + <92> = 100; # HENKAN + <93> = 101; # KATAKANAHIRAGANA + <94> = 102; # MUHENKAN <96> = 104; # KPENTER <97> = 105; # RIGHTCTRL <98> = 106; # KPSLASH @@ -103,6 +107,7 @@ xkb_keymap { <111> = 119; # DELETE <117> = 125; # KPEQUAL <119> = 127; # PAUSE + <124> = 132; # YEN <125> = 133; # LEFTMETA <126> = 134; # RIGHTMETA <139> = 147; # MENU @@ -311,6 +316,12 @@ xkb_keymap { key <9> { [ 8, asterisk ] }; key <10> { [ 9, parenleft ] }; key <11> { [ 0, parenright ] }; + + key <89> { [ dollar , asciitilde ] }; + key <93> { [ ampersand , percent ] }; + key <94> { [ equal , asterisk ] }; + key <124> { [ at , asciicircum ] }; + key <92> { [ numbersign , grave ] }; }; }; diff --git a/src/state.rs b/src/state.rs index 2333eaa5..902e318c 100644 --- a/src/state.rs +++ b/src/state.rs @@ -136,7 +136,7 @@ impl State { pub fn map_tiled(self: &Rc, node: Rc) { let seat = self.seat_queue.last(); - if let Some(seat) = seat { + if let Some(seat) = &seat { if let Some(prev) = seat.last_tiled_keyboard_toplevel(&*node) { if let Some(container) = prev.parent() { if let Some(container) = container.into_container() { @@ -146,28 +146,31 @@ impl State { } } } - let output = { + let mut output = seat.map(|s| s.get_output()); + if output.is_none() { let outputs = self.root.outputs.lock(); - outputs.values().next().cloned() - }; - if let Some(output) = output { - if let Some(workspace) = output.workspace.get() { - if let Some(container) = workspace.container.get() { - container.append_child(node); - } else { - let container = ContainerNode::new( - self, - &workspace, - workspace.clone(), - node, - ContainerSplit::Horizontal, - ); - workspace.set_container(&container); - }; - return; - } + output = outputs.values().next().cloned(); } - todo!("map_tiled"); + let output = match output { + Some(output) => output, + _ => self.dummy_output.get().unwrap(), + }; + if let Some(workspace) = output.workspace.get() { + if let Some(container) = workspace.container.get() { + container.append_child(node); + } else { + let container = ContainerNode::new( + self, + &workspace, + workspace.clone(), + node, + ContainerSplit::Horizontal, + ); + workspace.set_container(&container); + }; + return; + } + log::warn!("Output has no workspace set"); } pub fn map_floating( @@ -199,4 +202,48 @@ impl State { }; FloatNode::new(self, workspace, position, node); } + + pub fn show_workspace(&self, seat: &Rc, name: &str) { + let output = match self.workspaces.get(name) { + Some(ws) => { + let output = ws.output.get(); + if let Some(old) = output.workspace.get() { + if old.id == ws.id { + return; + } + } + output.show_workspace(&ws); + output + } + _ => { + let output = seat.get_output(); + if output.is_dummy { + log::warn!("Not showing workspace because seat is on dummy output"); + return; + } + let workspace = Rc::new(WorkspaceNode { + id: self.node_ids.next(), + output: CloneCell::new(output.clone()), + position: Cell::new(Default::default()), + container: Default::default(), + stacked: Default::default(), + seat_state: Default::default(), + name: name.to_string(), + output_link: Cell::new(None), + }); + workspace + .output_link + .set(Some(output.workspaces.add_last(workspace.clone()))); + output.show_workspace(&workspace); + self.workspaces.set(name.to_string(), workspace); + output + } + }; + output.update_render_data(); + self.tree_changed(); + let seats = self.globals.seats.lock(); + for seat in seats.values() { + seat.workspace_changed(&output); + } + } } diff --git a/src/tasks/output.rs b/src/tasks/output.rs index c199f5fb..f4e56d6b 100644 --- a/src/tasks/output.rs +++ b/src/tasks/output.rs @@ -24,7 +24,7 @@ impl OutputHandler { let global = Rc::new(WlOutputGlobal::new(name, self.output.clone())); let on = Rc::new(OutputNode { id: self.state.node_ids.next(), - workspaces: RefCell::new(vec![]), + workspaces: Default::default(), position: Cell::new(Default::default()), workspace: CloneCell::new(None), seat_state: Default::default(), @@ -51,14 +51,18 @@ impl OutputHandler { let workspace = Rc::new(WorkspaceNode { id: self.state.node_ids.next(), output: CloneCell::new(on.clone()), + position: Cell::new(Default::default()), container: Default::default(), stacked: Default::default(), seat_state: Default::default(), name: name.clone(), + output_link: Default::default(), }); self.state.workspaces.set(name, workspace.clone()); - on.workspaces.borrow_mut().push(workspace.clone()); - on.workspace.set(Some(workspace)); + workspace + .output_link + .set(Some(on.workspaces.add_last(workspace.clone()))); + on.show_workspace(&workspace); on.update_render_data(); self.state.root.outputs.set(self.output.id(), on.clone()); self.state.add_global(&global); diff --git a/src/tree.rs b/src/tree.rs index 4e6fb9fe..061e043c 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -74,6 +74,10 @@ pub trait Node { fn visit(self: Rc, visitor: &mut dyn NodeVisitor); fn visit_children(&self, visitor: &mut dyn NodeVisitor); + fn get_workspace(&self) -> Option> { + None + } + fn is_contained_in(&self, other: NodeId) -> bool { let _ = other; false diff --git a/src/tree/container.rs b/src/tree/container.rs index 76424f6b..f0f1c54e 100644 --- a/src/tree/container.rs +++ b/src/tree/container.rs @@ -1,4 +1,4 @@ -use crate::backend::KeyState; +use crate::backend::{KeyState}; use crate::cursor::KnownCursor; use crate::fixed::Fixed; use crate::ifs::wl_seat::{NodeSeatState, SeatId, WlSeatGlobal, BTN_LEFT}; @@ -693,6 +693,10 @@ impl Node for ContainerNode { } } + fn get_workspace(&self) -> Option> { + Some(self.workspace.get()) + } + fn is_contained_in(&self, other: NodeId) -> bool { let parent = self.parent.get(); if parent.id() == other { @@ -1055,9 +1059,23 @@ impl Node for ContainerNode { fn remove_child(self: Rc, child: &dyn Node) { let node = match self.child_nodes.borrow_mut().remove(&child.id()) { - Some(c) => c.to_ref(), + Some(c) => c, None => return, }; + let mut mono_child = None; + if let Some(mono) = self.mono_child.get() { + if mono.node.id() == child.id() { + self.mono_child.take(); + mono_child = node.next(); + if mono_child.is_none() { + mono_child = node.prev(); + } + } + } + let node = { + let node = node; + node.to_ref() + }; let num_children = self.num_children.fetch_sub(1) - 1; if num_children == 0 { self.seats.borrow_mut().clear(); @@ -1080,6 +1098,9 @@ impl Node for ContainerNode { sum += factor; } } + if mono_child.is_some() { + self.mono_child.set(mono_child); + } self.sum_factors.set(sum); self.update_title(); self.schedule_layout(); diff --git a/src/tree/float.rs b/src/tree/float.rs index 3dff23ab..3f1ba115 100644 --- a/src/tree/float.rs +++ b/src/tree/float.rs @@ -1,4 +1,4 @@ -use crate::backend::KeyState; +use crate::backend::{KeyState}; use crate::cursor::KnownCursor; use crate::fixed::Fixed; use crate::ifs::wl_seat::{NodeSeatState, SeatId, WlSeatGlobal, BTN_LEFT}; @@ -343,6 +343,10 @@ impl Node for FloatNode { } } + fn get_workspace(&self) -> Option> { + Some(self.workspace.get()) + } + fn child_title_changed(self: Rc, _child: &dyn Node, title: &str) { let mut t = self.title.borrow_mut(); if t.deref() != title { diff --git a/src/tree/output.rs b/src/tree/output.rs index 7ca23e58..fd32657c 100644 --- a/src/tree/output.rs +++ b/src/tree/output.rs @@ -1,4 +1,5 @@ use crate::cursor::KnownCursor; +use crate::fixed::Fixed; use crate::ifs::wl_output::WlOutputGlobal; use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal}; use crate::ifs::wl_surface::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1; @@ -16,14 +17,13 @@ use std::cell::{Cell, RefCell}; use std::fmt::{Debug, Formatter}; use std::ops::{Deref, Sub}; use std::rc::Rc; -use crate::fixed::Fixed; tree_id!(OutputNodeId); pub struct OutputNode { pub id: OutputNodeId, pub position: Cell, pub global: Rc, - pub workspaces: RefCell>>, + pub workspaces: LinkedList>, pub workspace: CloneCell>>, pub seat_state: NodeSeatState, pub layers: [LinkedList>; 4], @@ -37,12 +37,11 @@ impl OutputNode { let mut rd = self.render_data.borrow_mut(); rd.titles.clear(); rd.inactive_workspaces.clear(); - let workspaces = self.workspaces.borrow_mut(); let mut pos = 0; let font = self.state.theme.font.borrow_mut(); let th = self.state.theme.title_height.get(); let active_id = self.workspace.get().map(|w| w.id); - for ws in workspaces.deref() { + for ws in self.workspaces.iter() { let mut title_width = th; 'create_texture: { if let Some(ctx) = self.state.render_ctx.get() { @@ -78,6 +77,23 @@ impl OutputNode { pos += title_width; } } + + pub fn show_workspace(&self, ws: &Rc) { + self.workspace.set(Some(ws.clone())); + ws.clone().change_extents(&self.workspace_rect()); + } + + fn workspace_rect(&self) -> Rect { + let rect = self.position.get(); + let th = self.state.theme.title_height.get(); + Rect::new_sized( + rect.x1(), + rect.y1() + th, + rect.width(), + rect.height().sub(th).max(0), + ) + .unwrap() + } } pub struct OutputTitle { @@ -100,14 +116,6 @@ impl Debug for OutputNode { } impl Node for OutputNode { - fn pointer_enter(self: Rc, seat: &Rc, _x: Fixed, _y: Fixed) { - seat.enter_output(&self) - } - - fn leave(&self, seat: &WlSeatGlobal) { - seat.leave_output(); - } - fn id(&self) -> NodeId { self.id.into() } @@ -120,8 +128,9 @@ impl Node for OutputNode { if detach { self.state.root.clone().remove_child(self); } - let mut workspaces = self.workspaces.borrow_mut(); - for workspace in workspaces.drain(..) { + self.workspace.set(None); + let workspaces: Vec<_> = self.workspaces.iter().map(|e| e.deref().clone()).collect(); + for workspace in workspaces { workspace.destroy_node(false); } self.seat_state.destroy_node(self); @@ -132,9 +141,8 @@ impl Node for OutputNode { } fn visit_children(&self, visitor: &mut dyn NodeVisitor) { - let ws = self.workspaces.borrow_mut(); - for ws in ws.deref() { - visitor.visit_workspace(ws); + for ws in self.workspaces.iter() { + visitor.visit_workspace(ws.deref()); } for layers in &self.layers { for surface in layers.iter() { @@ -147,20 +155,32 @@ impl Node for OutputNode { self.position.get() } - fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec) -> FindTreeResult { - if let Some(ws) = self.workspace.get() { - tree.push(FoundNode { - node: ws.clone(), - x, - y, - }); - ws.find_tree_at(x, y, tree); + fn find_tree_at(&self, x: i32, mut y: i32, tree: &mut Vec) -> FindTreeResult { + let th = self.state.theme.title_height.get(); + if y > th { + y -= th; + if let Some(ws) = self.workspace.get() { + tree.push(FoundNode { + node: ws.clone(), + x, + y, + }); + ws.find_tree_at(x, y, tree); + } } FindTreeResult::AcceptsInput } fn remove_child(self: Rc, _child: &dyn Node) { - self.workspace.set(None); + unimplemented!(); + } + + fn leave(&self, seat: &WlSeatGlobal) { + seat.leave_output(); + } + + fn pointer_enter(self: Rc, seat: &Rc, _x: Fixed, _y: Fixed) { + seat.enter_output(&self) } fn pointer_focus(&self, seat: &Rc) { @@ -180,17 +200,9 @@ impl Node for OutputNode { } fn change_extents(self: Rc, rect: &Rect) { - let th = self.state.theme.title_height.get(); self.position.set(*rect); if let Some(c) = self.workspace.get() { - let wrect = Rect::new_sized( - rect.x1(), - rect.y1() + th, - rect.width(), - rect.height().sub(th).max(0), - ) - .unwrap(); - c.change_extents(&wrect); + c.change_extents(&self.workspace_rect()); } for layer in &self.layers { for surface in layer.iter() { diff --git a/src/tree/toplevel.rs b/src/tree/toplevel.rs index 782d4d8e..41da67ad 100644 --- a/src/tree/toplevel.rs +++ b/src/tree/toplevel.rs @@ -1,6 +1,6 @@ use crate::ifs::wl_seat::SeatId; use crate::ifs::wl_surface::WlSurface; -use crate::tree::{Node, WorkspaceNode}; +use crate::tree::{Node}; use crate::utils::linkedlist::LinkedNode; use crate::utils::numcell::NumCell; use crate::utils::smallmap::SmallMap; @@ -9,7 +9,6 @@ use std::rc::Rc; pub trait ToplevelNode { fn data(&self) -> &ToplevelData; fn parent(&self) -> Option>; - fn workspace(&self) -> Option>; fn as_node(&self) -> &dyn Node; fn into_node(self: Rc) -> Rc; fn accepts_keyboard_focus(&self) -> bool; diff --git a/src/tree/workspace.rs b/src/tree/workspace.rs index a1d77e82..f58e6196 100644 --- a/src/tree/workspace.rs +++ b/src/tree/workspace.rs @@ -6,7 +6,8 @@ use crate::tree::container::ContainerNode; use crate::tree::walker::NodeVisitor; use crate::tree::{FindTreeResult, FoundNode, Node, NodeId, OutputNode}; use crate::utils::clonecell::CloneCell; -use crate::utils::linkedlist::LinkedList; +use crate::utils::linkedlist::{LinkedList, LinkedNode}; +use std::cell::Cell; use std::fmt::Debug; use std::rc::Rc; @@ -15,16 +16,18 @@ tree_id!(WorkspaceNodeId); pub struct WorkspaceNode { pub id: WorkspaceNodeId, pub output: CloneCell>, + pub position: Cell, pub container: CloneCell>>, pub stacked: LinkedList>, pub seat_state: NodeSeatState, pub name: String, + pub output_link: Cell>>>, } impl WorkspaceNode { pub fn set_container(self: &Rc, container: &Rc) { - let output = self.output.get().position.get(); - container.clone().change_extents(&output); + let pos = self.position.get(); + container.clone().change_extents(&pos); container.clone().set_workspace(self); self.container.set(Some(container.clone())); } @@ -43,16 +46,13 @@ impl Node for WorkspaceNode { if detach { self.output.get().remove_child(self); } + self.output_link.set(None); if let Some(container) = self.container.take() { container.destroy_node(false); } self.seat_state.destroy_node(self); } - fn accepts_child(&self, node: &dyn Node) -> bool { - node.is_container() - } - fn visit(self: Rc, visitor: &mut dyn NodeVisitor) { visitor.visit_workspace(&self); } @@ -64,7 +64,7 @@ impl Node for WorkspaceNode { } fn absolute_position(&self) -> Rect { - self.output.get().position.get() + self.position.get() } fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec) -> FindTreeResult { @@ -91,11 +91,16 @@ impl Node for WorkspaceNode { renderer.render_workspace(self, x, y); } + fn accepts_child(&self, node: &dyn Node) -> bool { + node.is_container() + } + fn is_workspace(&self) -> bool { true } fn change_extents(self: Rc, rect: &Rect) { + self.position.set(*rect); if let Some(c) = self.container.get() { c.change_extents(rect); } diff --git a/wire/jay_compositor.txt b/wire/jay_compositor.txt index 71cef375..86f80afe 100644 --- a/wire/jay_compositor.txt +++ b/wire/jay_compositor.txt @@ -10,3 +10,7 @@ msg get_log_file = 1 { msg quit = 2 { } + +msg set_log_level = 3 { + level: u32, +}