1
0
Fork 0
forked from wry/wry

autocommit 2022-04-02 00:31:30 CEST

This commit is contained in:
Julian Orth 2022-04-02 00:31:30 +02:00
parent 2dd433aa04
commit 6ad6d83b7e
34 changed files with 446 additions and 161 deletions

View file

@ -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);

View file

@ -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};

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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<f64>,
name: CloneCell<Rc<String>>,
// state
pressed_keys: SmallMap<u32, (), 5>,
pressed_buttons: SmallMap<u32, (), 2>,
// config
left_handed: Cell<Option<bool>>,
accel_profile: Cell<Option<AccelProfile>>,
@ -205,6 +209,14 @@ struct MetalInputDevice {
transform_matrix: Cell<Option<[[f64; 2]; 2]>>,
}
impl Drop for MetalInputDevice {
fn drop(&mut self) {
if let Some(fd) = self.fd.take() {
mem::forget(fd);
}
}
}
#[derive(Clone)]
enum MetalDevice {
Input(Rc<MetalInputDevice>),
@ -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 {

View file

@ -93,8 +93,14 @@ impl MetalBackend {
fn handle_keyboard_key(self: &Rc<Self>, 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<Self>, 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));

View file

@ -119,6 +119,7 @@ impl MetalBackend {
}
fn handle_input_device_removed(self: &Rc<Self>, dev: &Rc<MetalInputDevice>) {
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<Self>, dev: &Rc<MetalInputDevice>) {
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(),

View file

@ -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),
}
}

28
src/cli/set_log_level.rs Normal file
View file

@ -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<ToolClient>,
args: SetLogArgs,
}
async fn run(log: Rc<Log>) {
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;
}

View file

@ -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<Logger>, _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<Logger>, _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);

View file

@ -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<Rc<String>, 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(())
}

View file

@ -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<ClientError>),
}
@ -138,3 +162,12 @@ pub enum QuitError {
MsgParserError(#[source] Box<MsgParserError>),
}
efrom!(QuitError, MsgParserError);
#[derive(Debug, Error)]
pub enum SetLogLevelError {
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
#[error("Unknown log level {0}")]
UnknownLogLevel(u32),
}
efrom!(SetLogLevelError, MsgParserError);

View file

@ -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<Self>, output: &Rc<OutputNode>) {
self.kb_owner.workspace_changed(self, output);
}
fn bind_(
self: Rc<Self>,
id: WlSeatId,

View file

@ -192,8 +192,14 @@ impl WlSeatGlobal {
}
pub fn last_tiled_keyboard_toplevel(&self, new: &dyn Node) -> Option<Rc<dyn ToplevelNode>> {
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,

View file

@ -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<WlSeatGlobal>, node: Rc<dyn Node>) {
self.owner.get().set_kb_node(seat, node);
}
pub fn workspace_changed(&self, seat: &Rc<WlSeatGlobal>, output: &Rc<OutputNode>) {
self.owner.get().workspace_changed(seat, output);
}
}
struct DefaultKbOwner;
@ -39,6 +44,7 @@ trait KbOwner {
fn grab(&self, seat: &Rc<WlSeatGlobal>, node: Rc<dyn Node>) -> bool;
fn ungrab(&self, seat: &Rc<WlSeatGlobal>);
fn set_kb_node(&self, seat: &Rc<WlSeatGlobal>, node: Rc<dyn Node>);
fn workspace_changed(&self, seat: &Rc<WlSeatGlobal>, output: &Rc<OutputNode>);
}
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<WlSeatGlobal>, output: &Rc<OutputNode>) {
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<WlSeatGlobal>, _node: Rc<dyn Node>) {
// nothing
}
fn workspace_changed(&self, _seat: &Rc<WlSeatGlobal>, _output: &Rc<OutputNode>) {
// nothing
}
}

View file

@ -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<Rc<WorkspaceNode>> {
if let Some(tl) = self.toplevel.get() {
return tl.as_node().get_workspace();
}
None
}
fn get_parent_mono(&self) -> Option<bool> {
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,
};

View file

@ -289,6 +289,10 @@ impl SurfaceExt for WlSubsurface {
fn into_subsurface(self: Rc<Self>) -> Option<Rc<WlSubsurface>> {
Some(self)
}
fn accepts_kb_focus(&self) -> bool {
self.parent.accepts_kb_focus()
}
}
#[derive(Debug, Error)]

View file

@ -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)]

View file

@ -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<Rc<WorkspaceNode>> {
self.xdg.workspace.get()
}
fn absolute_position(&self) -> Rect {
self.xdg.absolute_desired_extents.get()
}

View file

@ -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<Rc<WorkspaceNode>> {
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<Rc<WorkspaceNode>> {
self.xdg.workspace.get()
}
fn as_node(&self) -> &dyn Node {
self
}

View file

@ -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<Rc<WorkspaceNode>> {
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<Rc<WorkspaceNode>> {
self.workspace.get()
}
fn as_node(&self) -> &dyn Node {
self
}

View file

@ -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<Self>, _rect: &Rect) {
self.compute_position();
}

View file

@ -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 ] };
};
};

View file

@ -136,7 +136,7 @@ impl State {
pub fn map_tiled(self: &Rc<Self>, node: Rc<dyn Node>) {
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<WlSeatGlobal>, 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);
}
}
}

View file

@ -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);

View file

@ -74,6 +74,10 @@ pub trait Node {
fn visit(self: Rc<Self>, visitor: &mut dyn NodeVisitor);
fn visit_children(&self, visitor: &mut dyn NodeVisitor);
fn get_workspace(&self) -> Option<Rc<WorkspaceNode>> {
None
}
fn is_contained_in(&self, other: NodeId) -> bool {
let _ = other;
false

View file

@ -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<Rc<WorkspaceNode>> {
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<Self>, 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();

View file

@ -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<Rc<WorkspaceNode>> {
Some(self.workspace.get())
}
fn child_title_changed(self: Rc<Self>, _child: &dyn Node, title: &str) {
let mut t = self.title.borrow_mut();
if t.deref() != title {

View file

@ -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<Rect>,
pub global: Rc<WlOutputGlobal>,
pub workspaces: RefCell<Vec<Rc<WorkspaceNode>>>,
pub workspaces: LinkedList<Rc<WorkspaceNode>>,
pub workspace: CloneCell<Option<Rc<WorkspaceNode>>>,
pub seat_state: NodeSeatState,
pub layers: [LinkedList<Rc<ZwlrLayerSurfaceV1>>; 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<WorkspaceNode>) {
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<Self>, seat: &Rc<WlSeatGlobal>, _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<FoundNode>) -> 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<FoundNode>) -> 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<Self>, _child: &dyn Node) {
self.workspace.set(None);
unimplemented!();
}
fn leave(&self, seat: &WlSeatGlobal) {
seat.leave_output();
}
fn pointer_enter(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, _x: Fixed, _y: Fixed) {
seat.enter_output(&self)
}
fn pointer_focus(&self, seat: &Rc<WlSeatGlobal>) {
@ -180,17 +200,9 @@ impl Node for OutputNode {
}
fn change_extents(self: Rc<Self>, 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() {

View file

@ -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<Rc<dyn Node>>;
fn workspace(&self) -> Option<Rc<WorkspaceNode>>;
fn as_node(&self) -> &dyn Node;
fn into_node(self: Rc<Self>) -> Rc<dyn Node>;
fn accepts_keyboard_focus(&self) -> bool;

View file

@ -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<Rc<OutputNode>>,
pub position: Cell<Rect>,
pub container: CloneCell<Option<Rc<ContainerNode>>>,
pub stacked: LinkedList<Rc<dyn Node>>,
pub seat_state: NodeSeatState,
pub name: String,
pub output_link: Cell<Option<LinkedNode<Rc<WorkspaceNode>>>>,
}
impl WorkspaceNode {
pub fn set_container(self: &Rc<Self>, container: &Rc<ContainerNode>) {
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<Self>, 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<FoundNode>) -> 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<Self>, rect: &Rect) {
self.position.set(*rect);
if let Some(c) = self.container.get() {
c.change_extents(rect);
}

View file

@ -10,3 +10,7 @@ msg get_log_file = 1 {
msg quit = 2 {
}
msg set_log_level = 3 {
level: u32,
}