diff --git a/protocols.md b/protocols.md index e9366ddb..efe8d96f 100644 --- a/protocols.md +++ b/protocols.md @@ -1,6 +1,34 @@ +# implemented + +- wayland +- xdg-shell +- idle-inhibit +- linux-dma-buf +- primary-selection +- xdg-decoration +- xdg-output +- wlr-layer-shell +- kde-server-decoration +- mesa-drm + +# planned + +- presentation-time +- viewporter +- xdg-activation +- drm-lease +- session-lock +- linux-explicit-synchronization +- pointer-constraints +- relative-pointer +- tablet +- xwayland-keyboard-grabbing + +# todos + - wayland - wl_compositor - - todo: version 5 + - version 5 - wl_shm - support for more formats - wl_surface @@ -10,7 +38,9 @@ - scale - offset - wl_touch - - todo - xdg-shell - - oeuo.e + - xdg_positioner + - set_reactive + - xdg_toplevel + - diff --git a/src/compositor.rs b/src/compositor.rs index edd5149a..c22c0cc7 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -80,6 +80,12 @@ enum MainError { pub const WAYLAND_DISPLAY: &str = "WAYLAND_DISPLAY"; pub const DISPLAY: &str = "DISPLAY"; +const STATIC_VARS: &[(&str, &str)] = &[ + ("XDG_CURRENT_DESKTOP", "jay"), + ("XDG_SESSION_TYPE", "wayland"), + ("_JAVA_AWT_WM_NONREPARENTING", "1"), +]; + fn start_compositor2( forker: Rc, logger: Arc, @@ -157,7 +163,9 @@ fn start_compositor2( let socket_path = Acceptor::install(&state)?; forker.install(&state); forker.setenv(WAYLAND_DISPLAY.as_bytes(), socket_path.as_bytes()); - forker.setenv(b"_JAVA_AWT_WM_NONREPARENTING", b"1"); + for (key, val) in STATIC_VARS { + forker.setenv(key.as_bytes(), val.as_bytes()); + } let _compositor = engine.spawn(start_compositor3(state.clone())); el.run()?; state.xwayland.handler.borrow_mut().take(); @@ -183,6 +191,9 @@ async fn start_compositor3(state: Rc) { if backend.is_freestanding() { import_environment(&state, WAYLAND_DISPLAY, &state.socket_path.get()); + for (key, val) in STATIC_VARS { + import_environment(&state, key, val); + } } let config = ConfigProxy::default(&state); diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index 754e0550..64bcbdc8 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -32,16 +32,15 @@ use { leaks::Tracker, object::{Object, ObjectId}, state::State, - tree::{ - generic_node_visitor, ContainerSplit, FloatNode, FoundNode, Node, OutputNode, - }, + tree::{generic_node_visitor, ContainerSplit, FloatNode, FoundNode, Node, OutputNode}, utils::{ asyncevent::AsyncEvent, buffd::{MsgParser, MsgParserError}, clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, - linkedlist::{LinkedNode}, + linkedlist::LinkedNode, + numcell::NumCell, rc_eq::rc_eq, }, wire::{ @@ -137,8 +136,12 @@ pub struct WlSeatGlobal { tree_changed_handler: Cell>>, output: CloneCell>, desired_known_cursor: Cell>, + changes: NumCell, } +const CHANGE_CURSOR_MOVED: u32 = 1 << 0; +const CHANGE_TREE: u32 = 1 << 1; + impl WlSeatGlobal { pub fn new(name: GlobalName, seat_name: &str, state: &Rc) -> Rc { let slf = Rc::new(Self { @@ -174,13 +177,15 @@ impl WlSeatGlobal { tree_changed_handler: Cell::new(None), output: CloneCell::new(state.dummy_output.get().unwrap()), desired_known_cursor: Cell::new(None), + changes: NumCell::new(CHANGE_CURSOR_MOVED | CHANGE_TREE), }); let seat = slf.clone(); let future = state.eng.spawn(async move { loop { seat.tree_changed.triggered().await; seat.state.tree_changed_sent.set(false); - seat.tree_changed(); + seat.changes.or_assign(CHANGE_TREE); + seat.apply_changes(); } }); slf.tree_changed_handler.set(Some(future)); diff --git a/src/ifs/wl_seat/event_handling.rs b/src/ifs/wl_seat/event_handling.rs index cc8b2c58..c50dd8b6 100644 --- a/src/ifs/wl_seat/event_handling.rs +++ b/src/ifs/wl_seat/event_handling.rs @@ -16,13 +16,13 @@ use { AXIS_SOURCE_SINCE_VERSION, AXIS_STOP_SINCE_VERSION, POINTER_FRAME_SINCE_VERSION, WHEEL_TILT, WHEEL_TILT_SINCE_VERSION, }, - Dnd, SeatId, WlSeat, WlSeatGlobal, + Dnd, SeatId, WlSeat, WlSeatGlobal, CHANGE_CURSOR_MOVED, }, wl_surface::{xdg_surface::xdg_popup::XdgPopup, WlSurface}, }, object::ObjectId, tree::{FloatNode, Node, SizedNode, ToplevelNode}, - utils::{clonecell::CloneCell, smallmap::SmallMap}, + utils::{bitflags::BitflagsExt, clonecell::CloneCell, smallmap::SmallMap}, wire::WlDataOfferId, xkbcommon::{ModifierState, XKB_KEY_DOWN, XKB_KEY_UP}, }, @@ -400,7 +400,11 @@ impl WlSeatGlobal { fn set_new_position(self: &Rc, x: Fixed, y: Fixed) { self.pos.set((x, y)); - self.handle_new_position(true); + if let Some(cursor) = self.cursor.get() { + cursor.set_position(x.round_down(), y.round_down()); + } + self.changes.or_assign(CHANGE_CURSOR_MOVED); + self.apply_changes(); } pub fn add_shortcut(&self, mods: Modifiers, keysym: KeySym) { @@ -415,18 +419,9 @@ impl WlSeatGlobal { self.tree_changed.trigger(); } - pub(super) fn tree_changed(self: &Rc) { - self.handle_new_position(false); - } - - fn handle_new_position(self: &Rc, pos_changed: bool) { - let (x, y) = self.pos.get(); - if pos_changed { - if let Some(cursor) = self.cursor.get() { - cursor.set_position(x.round_down(), y.round_down()); - } - } - self.pointer_owner.handle_pointer_position(self); + pub(super) fn apply_changes(self: &Rc) { + self.pointer_owner.apply_changes(self); + self.changes.set(0); } } @@ -492,7 +487,7 @@ impl WlSeatGlobal { // Enter callbacks impl WlSeatGlobal { pub fn enter_toplevel(self: &Rc, n: Rc) { - if n.accepts_keyboard_focus() { + if n.accepts_keyboard_focus() && self.changes.get().contains(CHANGE_CURSOR_MOVED) { self.focus_toplevel(n); } } diff --git a/src/ifs/wl_seat/pointer_owner.rs b/src/ifs/wl_seat/pointer_owner.rs index 6be3c4ce..c88c51a9 100644 --- a/src/ifs/wl_seat/pointer_owner.rs +++ b/src/ifs/wl_seat/pointer_owner.rs @@ -58,8 +58,8 @@ impl PointerOwnerHolder { } } - pub fn handle_pointer_position(&self, seat: &Rc) { - self.owner.get().handle_pointer_position(seat) + pub fn apply_changes(&self, seat: &Rc) { + self.owner.get().apply_changes(seat) } pub fn start_drag( @@ -99,7 +99,7 @@ impl PointerOwnerHolder { trait PointerOwner { fn button(&self, seat: &Rc, button: u32, state: KeyState); fn axis_node(&self, seat: &Rc) -> Option>; - fn handle_pointer_position(&self, seat: &Rc); + fn apply_changes(&self, seat: &Rc); fn start_drag( &self, seat: &Rc, @@ -155,7 +155,7 @@ impl PointerOwner for DefaultPointerOwner { seat.pointer_node() } - fn handle_pointer_position(&self, seat: &Rc) { + fn apply_changes(&self, seat: &Rc) { let (x, y) = seat.pos.get(); let mut found_tree = seat.found_tree.borrow_mut(); let mut stack = seat.pointer_stack.borrow_mut(); @@ -278,7 +278,7 @@ impl PointerOwner for GrabPointerOwner { Some(self.node.clone()) } - fn handle_pointer_position(&self, seat: &Rc) { + fn apply_changes(&self, seat: &Rc) { let (x, y) = seat.pos.get(); let pos = self.node.node_absolute_position(); let (x_int, y_int) = pos.translate(x.round_down(), y.round_down()); @@ -341,7 +341,7 @@ impl PointerOwner for GrabPointerOwner { // old.unfocus(seat); // } seat.pointer_owner.owner.set(pointer_owner.clone()); - pointer_owner.handle_pointer_position(seat); + pointer_owner.apply_changes(seat); Ok(()) } @@ -405,7 +405,7 @@ impl PointerOwner for DndPointerOwner { None } - fn handle_pointer_position(&self, seat: &Rc) { + fn apply_changes(&self, seat: &Rc) { let (x, y) = seat.pos.get(); let (x_int, y_int) = (x.round_down(), y.round_down()); let (node, x_int, y_int) = { diff --git a/src/ifs/wl_surface/xdg_surface/xdg_popup.rs b/src/ifs/wl_surface/xdg_surface/xdg_popup.rs index 506fed84..d4a68388 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_popup.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_popup.rs @@ -293,7 +293,9 @@ impl SizedNode for XdgPopup { } fn parent(&self) -> Option> { - self.parent.get().and_then(|x| x.workspace.get().map(|w| w as Rc)) + self.parent + .get() + .and_then(|x| x.workspace.get().map(|w| w as Rc)) } fn set_visible(&self, visible: bool) { diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs index f2785093..aae07c05 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs @@ -319,9 +319,9 @@ impl XdgToplevel { } fn map_floating(self: &Rc, workspace: &Rc) { - let extents = self.xdg.extents.get(); + let (width, height) = self.toplevel_data.float_size(workspace); let state = &self.xdg.surface.client.state; - state.map_floating(self.clone(), extents.width(), extents.height(), workspace); + state.map_floating(self.clone(), width, height, workspace); } fn map_child(self: &Rc, parent: &XdgToplevel) { @@ -459,6 +459,10 @@ impl SizedNode for XdgToplevel { let nh = rect.height(); let de = self.xdg.absolute_desired_extents.get(); if de.width() != nw || de.height() != nh { + if self.toplevel_data.is_floating.get() { + self.toplevel_data.float_width.set(rect.width()); + self.toplevel_data.float_height.set(rect.height()); + } self.send_configure_checked(nw, nh); self.xdg.do_send_configure(); self.xdg.surface.client.flush(); @@ -471,6 +475,7 @@ impl SizedNode for XdgToplevel { } fn set_parent(self: &Rc, parent: Rc) { + self.toplevel_data.is_floating.set(parent.node_is_float()); self.parent_node.set(Some(parent)); self.notify_parent(); } diff --git a/src/ifs/wl_surface/xwindow.rs b/src/ifs/wl_surface/xwindow.rs index b589567a..438d8412 100644 --- a/src/ifs/wl_surface/xwindow.rs +++ b/src/ifs/wl_surface/xwindow.rs @@ -435,6 +435,10 @@ impl SizedNode for Xwindow { // log::info!("xwin {} change_extents {:?}", self.data.window_id, rect); let old = self.data.info.extents.replace(*rect); if old != *rect { + if self.toplevel_data.is_floating.get() { + self.toplevel_data.float_width.set(rect.width()); + self.toplevel_data.float_height.set(rect.height()); + } if !self.data.info.override_redirect.get() { self.data .state @@ -453,6 +457,7 @@ impl SizedNode for Xwindow { } fn set_parent(self: &Rc, parent: Rc) { + self.toplevel_data.is_floating.set(parent.node_is_float()); self.parent_node.set(Some(parent)); self.notify_parent(); } @@ -508,10 +513,10 @@ impl ToplevelNode for Xwindow { self.data.state.map_tiled(self.clone()); } else if let Some(ws) = self.workspace.get() { parent.node_remove_child(&*self); - let extents = self.data.info.extents.get(); + let (width, height) = self.toplevel_data.float_size(&ws); self.data .state - .map_floating(self.clone(), extents.width(), extents.height(), &ws); + .map_floating(self.clone(), width, height, &ws); } } diff --git a/src/logind.rs b/src/logind.rs index 31f96b66..aa2e796b 100644 --- a/src/logind.rs +++ b/src/logind.rs @@ -1,6 +1,7 @@ use { crate::{ dbus::{DbusError, DbusSocket, SignalHandler, FALSE}, + utils::errorfmt::ErrorFmt, wire_dbus::{ org, org::freedesktop::login1::{ @@ -81,10 +82,22 @@ impl Session { org::freedesktop::login1::session::TakeControl { force: FALSE }, ) .await; - match res { - Ok(_) => Ok(()), - Err(e) => Err(LogindError::TakeControl(e)), + if let Err(e) = res { + return Err(LogindError::TakeControl(e)); } + self.socket.call( + LOGIND_NAME, + &self.session_path, + org::freedesktop::login1::session::SetType { + ty: "wayland".into(), + }, + |res| { + if let Err(e) = res { + log::warn!("Could not change session type to wayland: {}", ErrorFmt(e)); + } + }, + ); + Ok(()) } pub fn get_device(&self, dev: c::dev_t, f: F) diff --git a/src/state.rs b/src/state.rs index 21032bb6..0ef2b2c6 100644 --- a/src/state.rs +++ b/src/state.rs @@ -209,9 +209,15 @@ impl State { } pub fn map_tiled(self: &Rc, node: Rc) { - let output = self - .seat_queue - .last() + let seat = self.seat_queue.last(); + self.do_map_tiled(seat.as_deref(), node.clone()); + if let Some(seat) = seat { + node.node_do_focus(&seat, Direction::Unspecified); + } + } + + fn do_map_tiled(self: &Rc, seat: Option<&Rc>, node: Rc) { + let output = seat .map(|s| s.get_output()) .or_else(|| self.root.outputs.lock().values().next().cloned()) .or_else(|| self.dummy_output.get()) diff --git a/src/tree/toplevel.rs b/src/tree/toplevel.rs index 81488929..0e7f8d9b 100644 --- a/src/tree/toplevel.rs +++ b/src/tree/toplevel.rs @@ -1,10 +1,10 @@ use { crate::{ ifs::{wl_seat::SeatId, wl_surface::WlSurface}, - tree::Node, + tree::{Node, WorkspaceNode}, utils::{numcell::NumCell, smallmap::SmallMap}, }, - std::rc::Rc, + std::{cell::Cell, rc::Rc}, }; tree_id!(ToplevelNodeId); @@ -24,12 +24,28 @@ pub trait ToplevelNode { pub struct ToplevelData { pub active_surfaces: NumCell, pub focus_surface: SmallMap, 1>, + pub is_floating: Cell, + pub float_width: Cell, + pub float_height: Cell, } impl ToplevelData { pub fn clear(&self) { self.focus_surface.clear(); } + + pub fn float_size(&self, ws: &WorkspaceNode) -> (i32, i32) { + let output = ws.output.get().global.pos.get(); + let mut width = self.float_width.get(); + let mut height = self.float_height.get(); + if width == 0 { + width = output.width() / 2; + } + if height == 0 { + height = output.height() / 2; + } + (width, height) + } } impl<'a> dyn ToplevelNode + 'a { diff --git a/wire-dbus/org.freedesktop.login1.Session.txt b/wire-dbus/org.freedesktop.login1.Session.txt index aa519210..43a8ec28 100644 --- a/wire-dbus/org.freedesktop.login1.Session.txt +++ b/wire-dbus/org.freedesktop.login1.Session.txt @@ -8,6 +8,9 @@ fn TakeDevice(major: u32, minor: u32) { fn PauseDeviceComplete(major: u32, minor: u32) { } +fn SetType(ty: string) { +} + prop Seat = struct(string, object_path) sig PauseDevice {