Fix x11 windows not removing when destroyed

This commit is contained in:
Ottatop 2023-07-25 10:23:34 -05:00
parent f92153eb04
commit c2190f2e0c
5 changed files with 190 additions and 196 deletions

View file

@ -76,63 +76,63 @@ require("pinnacle").setup(function(pinnacle)
end
print("----------------------")
local op = output.get_focused() --[[@as Output]]
print("res: " .. (op:res() and (op:res().w .. ", " .. op:res().h) or "nil"))
print("loc: " .. (op:loc() and (op:loc().x .. ", " .. op:loc().y) or "nil"))
print("rr: " .. (op:refresh_rate() or "nil"))
print("make: " .. (op:make() or "nil"))
print("model: " .. (op:model() or "nil"))
print("focused: " .. (tostring(op:focused())))
print("----------------------")
local wins = window.get_by_class("Alacritty")
for _, win in pairs(wins) do
print("loc: " .. (win:loc() and win:loc().x or "nil") .. ", " .. (win:loc() and win:loc().y or "nil"))
print("size: " .. (win:size() and win:size().w or "nil") .. ", " .. (win:size() and win:size().h or "nil"))
print("class: " .. (win:class() or "nil"))
print("title: " .. (win:title() or "nil"))
print("float: " .. tostring(win:floating()))
end
print("----------------------")
local wins = window.get_by_title("~/p/pinnacle")
for _, win in pairs(wins) do
print("loc: " .. (win:loc() and win:loc().x or "nil") .. ", " .. (win:loc() and win:loc().y or "nil"))
print("size: " .. (win:size() and win:size().w or "nil") .. ", " .. (win:size() and win:size().h or "nil"))
print("class: " .. (win:class() or "nil"))
print("title: " .. (win:title() or "nil"))
print("float: " .. tostring(win:floating()))
end
print("----------------------")
local tags = tag.get_on_output(output.get_focused() --[[@as Output]])
for _, tg in pairs(tags) do
print(tg:name())
print((tg:output() and tg:output():name()) or "nil output")
print(tg:active())
end
print("----------------------")
local tags = tag.get_by_name("2")
for _, tg in pairs(tags) do
print(tg:name())
print((tg:output() and tg:output():name()) or "nil output")
print(tg:active())
end
print("----------------------")
local tags = tag.get_all()
for _, tg in pairs(tags) do
print(tg:name())
print((tg:output() and tg:output():name()) or "nil output")
print(tg:active())
end
--
-- local op = output.get_focused() --[[@as Output]]
-- print("res: " .. (op:res() and (op:res().w .. ", " .. op:res().h) or "nil"))
-- print("loc: " .. (op:loc() and (op:loc().x .. ", " .. op:loc().y) or "nil"))
-- print("rr: " .. (op:refresh_rate() or "nil"))
-- print("make: " .. (op:make() or "nil"))
-- print("model: " .. (op:model() or "nil"))
-- print("focused: " .. (tostring(op:focused())))
--
-- print("----------------------")
--
-- local wins = window.get_by_class("Alacritty")
-- for _, win in pairs(wins) do
-- print("loc: " .. (win:loc() and win:loc().x or "nil") .. ", " .. (win:loc() and win:loc().y or "nil"))
-- print("size: " .. (win:size() and win:size().w or "nil") .. ", " .. (win:size() and win:size().h or "nil"))
-- print("class: " .. (win:class() or "nil"))
-- print("title: " .. (win:title() or "nil"))
-- print("float: " .. tostring(win:floating()))
-- end
--
-- print("----------------------")
--
-- local wins = window.get_by_title("~/p/pinnacle")
-- for _, win in pairs(wins) do
-- print("loc: " .. (win:loc() and win:loc().x or "nil") .. ", " .. (win:loc() and win:loc().y or "nil"))
-- print("size: " .. (win:size() and win:size().w or "nil") .. ", " .. (win:size() and win:size().h or "nil"))
-- print("class: " .. (win:class() or "nil"))
-- print("title: " .. (win:title() or "nil"))
-- print("float: " .. tostring(win:floating()))
-- end
--
-- print("----------------------")
--
-- local tags = tag.get_on_output(output.get_focused() --[[@as Output]])
-- for _, tg in pairs(tags) do
-- print(tg:name())
-- print((tg:output() and tg:output():name()) or "nil output")
-- print(tg:active())
-- end
--
-- print("----------------------")
--
-- local tags = tag.get_by_name("2")
-- for _, tg in pairs(tags) do
-- print(tg:name())
-- print((tg:output() and tg:output():name()) or "nil output")
-- print(tg:active())
-- end
--
-- print("----------------------")
--
-- local tags = tag.get_all()
-- for _, tg in pairs(tags) do
-- print(tg:name())
-- print((tg:output() and tg:output():name()) or "nil output")
-- print(tg:active())
-- end
end)
-- Tags ---------------------------------------------------------------------------
@ -211,146 +211,67 @@ require("pinnacle").setup(function(pinnacle)
end)
input.keybind({ mod_key }, keys.KEY_1, function()
for _, t in pairs(tag.get_by_name("1")) do
if t:output() and t:output():focused() then
t:switch_to()
end
end
tag.switch_to("1")
end)
input.keybind({ mod_key }, keys.KEY_2, function()
for _, t in pairs(tag.get_by_name("2")) do
if t:output() and t:output():focused() then
t:switch_to()
end
end
tag.switch_to("2")
end)
input.keybind({ mod_key }, keys.KEY_3, function()
for _, t in pairs(tag.get_by_name("3")) do
if t:output() and t:output():focused() then
t:switch_to()
end
end
tag.switch_to("3")
end)
input.keybind({ mod_key }, keys.KEY_4, function()
for _, t in pairs(tag.get_by_name("4")) do
if t:output() and t:output():focused() then
t:switch_to()
end
end
tag.switch_to("4")
end)
input.keybind({ mod_key }, keys.KEY_5, function()
for _, t in pairs(tag.get_by_name("5")) do
if t:output() and t:output():focused() then
t:switch_to()
end
end
tag.switch_to("5")
end)
input.keybind({ mod_key, "Shift" }, keys.KEY_1, function()
for _, t in pairs(tag.get_by_name("1")) do
if t:output() and t:output():focused() then
t:toggle()
end
end
tag.toggle("1")
end)
input.keybind({ mod_key, "Shift" }, keys.KEY_2, function()
for _, t in pairs(tag.get_by_name("2")) do
if t:output() and t:output():focused() then
t:toggle()
end
end
tag.toggle("2")
end)
input.keybind({ mod_key, "Shift" }, keys.KEY_3, function()
for _, t in pairs(tag.get_by_name("3")) do
if t:output() and t:output():focused() then
t:toggle()
end
end
tag.toggle("3")
end)
input.keybind({ mod_key, "Shift" }, keys.KEY_4, function()
for _, t in pairs(tag.get_by_name("4")) do
if t:output() and t:output():focused() then
t:toggle()
end
end
tag.toggle("4")
end)
input.keybind({ mod_key, "Shift" }, keys.KEY_5, function()
for _, t in pairs(tag.get_by_name("5")) do
if t:output() and t:output():focused() then
t:toggle()
end
end
tag.toggle("5")
end)
-- I check for nil this way because I don't want stylua to take up like 80 lines on `if win ~= nil`
input.keybind({ mod_key, "Alt" }, keys.KEY_1, function()
for _, t in pairs(tag.get_by_name("1")) do
if t:output() and t:output():focused() then
window.get_focused():move_to_tag(t)
end
end
local _ = window.get_focused() and window:get_focused():move_to_tag("1")
end)
input.keybind({ mod_key, "Alt" }, keys.KEY_2, function()
for _, t in pairs(tag.get_by_name("2")) do
if t:output() and t:output():focused() then
window.get_focused():move_to_tag(t)
end
end
local _ = window.get_focused() and window:get_focused():move_to_tag("2")
end)
input.keybind({ mod_key, "Alt" }, keys.KEY_3, function()
for _, t in pairs(tag.get_by_name("3")) do
if t:output() and t:output():focused() then
window.get_focused():move_to_tag(t)
end
end
local _ = window.get_focused() and window:get_focused():move_to_tag("3")
end)
input.keybind({ mod_key, "Alt" }, keys.KEY_4, function()
for _, t in pairs(tag.get_by_name("4")) do
if t:output() and t:output():focused() then
window.get_focused():move_to_tag(t)
end
end
local _ = window.get_focused() and window:get_focused():move_to_tag("4")
end)
input.keybind({ mod_key, "Alt" }, keys.KEY_5, function()
for _, t in pairs(tag.get_by_name("5")) do
if t:output() and t:output():focused() then
window.get_focused():move_to_tag(t)
end
end
local _ = window.get_focused() and window:get_focused():move_to_tag("5")
end)
input.keybind({ mod_key, "Shift", "Alt" }, keys.KEY_1, function()
for _, t in pairs(tag.get_by_name("1")) do
if t:output() and t:output():focused() then
window.get_focused():toggle_tag(t)
end
end
local _ = window.get_focused() and window.get_focused():toggle_tag("1")
end)
input.keybind({ mod_key, "Shift", "Alt" }, keys.KEY_2, function()
for _, t in pairs(tag.get_by_name("2")) do
if t:output() and t:output():focused() then
window.get_focused():toggle_tag(t)
end
end
local _ = window.get_focused() and window.get_focused():toggle_tag("2")
end)
input.keybind({ mod_key, "Shift", "Alt" }, keys.KEY_3, function()
for _, t in pairs(tag.get_by_name("3")) do
if t:output() and t:output():focused() then
window.get_focused():toggle_tag(t)
end
end
local _ = window.get_focused() and window.get_focused():toggle_tag("3")
end)
input.keybind({ mod_key, "Shift", "Alt" }, keys.KEY_4, function()
for _, t in pairs(tag.get_by_name("4")) do
if t:output() and t:output():focused() then
window.get_focused():toggle_tag(t)
end
end
local _ = window.get_focused() and window.get_focused():toggle_tag("4")
end)
input.keybind({ mod_key, "Shift", "Alt" }, keys.KEY_5, function()
for _, t in pairs(tag.get_by_name("5")) do
if t:output() and t:output():focused() then
window.get_focused():toggle_tag(t)
end
end
local _ = window.get_focused() and window.get_focused():toggle_tag("5")
end)
end)

View file

@ -8,9 +8,12 @@ use smithay::{
desktop::space::SpaceElement,
input::pointer::Focus,
reexports::wayland_server::Resource,
utils::{Rectangle, SERIAL_COUNTER},
utils::{Logical, Rectangle, SERIAL_COUNTER},
wayland::compositor::{self, CompositorHandler},
xwayland::{xwm::XwmId, X11Wm, XwmHandler},
xwayland::{
xwm::{Reorder, XwmId},
X11Surface, X11Wm, XwmHandler,
},
};
use crate::{
@ -25,11 +28,11 @@ impl<B: Backend> XwmHandler for CalloopData<B> {
self.state.xwm.as_mut().expect("xwm not in state")
}
fn new_window(&mut self, xwm: XwmId, window: smithay::xwayland::X11Surface) {}
fn new_window(&mut self, xwm: XwmId, window: X11Surface) {}
fn new_override_redirect_window(&mut self, xwm: XwmId, window: smithay::xwayland::X11Surface) {}
fn new_override_redirect_window(&mut self, xwm: XwmId, window: X11Surface) {}
fn map_window_request(&mut self, xwm: XwmId, window: smithay::xwayland::X11Surface) {
fn map_window_request(&mut self, xwm: XwmId, window: X11Surface) {
tracing::debug!("new x11 window from map_window_request");
window.set_mapped(true).expect("failed to map x11 window");
let window = WindowElement::X11(window);
@ -149,17 +152,14 @@ impl<B: Backend> XwmHandler for CalloopData<B> {
}
}
fn mapped_override_redirect_window(
&mut self,
xwm: XwmId,
window: smithay::xwayland::X11Surface,
) {
fn mapped_override_redirect_window(&mut self, xwm: XwmId, window: X11Surface) {
let loc = window.geometry().loc;
let window = WindowElement::X11(window);
self.state.space.map_element(window, loc, true);
}
fn unmapped_window(&mut self, xwm: XwmId, window: smithay::xwayland::X11Surface) {
fn unmapped_window(&mut self, xwm: XwmId, window: X11Surface) {
tracing::debug!("unmapped x11 window");
let win = self
.state
.space
@ -168,23 +168,50 @@ impl<B: Backend> XwmHandler for CalloopData<B> {
.cloned();
if let Some(win) = win {
self.state.space.unmap_elem(&win);
// self.state.windows.retain(|elem| &win != elem);
if win.with_state(|state| state.floating.is_tiled()) {
if let Some(output) = win.output(&self.state) {
self.state.re_layout(&output);
}
}
}
if !window.is_override_redirect() {
window.set_mapped(false).expect("failed to unmap x11 win");
}
}
fn destroyed_window(&mut self, xwm: XwmId, window: smithay::xwayland::X11Surface) {}
fn destroyed_window(&mut self, xwm: XwmId, window: X11Surface) {
let win = self
.state
.windows
.iter()
.find(|elem| {
matches!(elem,
WindowElement::X11(surface) if surface.wl_surface() == window.wl_surface())
})
.cloned();
tracing::debug!("{win:?}");
if let Some(win) = win {
tracing::debug!("removing x11 window from windows");
self.state.windows.retain(|elem| win.wl_surface() != elem.wl_surface());
if win.with_state(|state| state.floating.is_tiled()) {
if let Some(output) = win.output(&self.state) {
self.state.re_layout(&output);
}
}
}
tracing::debug!("destroyed x11 window");
}
fn configure_request(
&mut self,
xwm: XwmId,
window: smithay::xwayland::X11Surface,
window: X11Surface,
x: Option<i32>,
y: Option<i32>,
w: Option<u32>,
h: Option<u32>,
reorder: Option<smithay::xwayland::xwm::Reorder>,
reorder: Option<Reorder>,
) {
let mut geo = window.geometry();
if let Some(w) = w {
@ -201,8 +228,8 @@ impl<B: Backend> XwmHandler for CalloopData<B> {
fn configure_notify(
&mut self,
xwm: XwmId,
window: smithay::xwayland::X11Surface,
geometry: smithay::utils::Rectangle<i32, smithay::utils::Logical>,
window: X11Surface,
geometry: Rectangle<i32, Logical>,
above: Option<smithay::reexports::x11rb::protocol::xproto::Window>,
) {
let Some(win) = self
@ -229,7 +256,7 @@ impl<B: Backend> XwmHandler for CalloopData<B> {
fn resize_request(
&mut self,
xwm: XwmId,
window: smithay::xwayland::X11Surface,
window: X11Surface,
button: u32,
resize_edge: smithay::xwayland::xwm::ResizeEdge,
) {
@ -283,8 +310,8 @@ impl<B: Backend> XwmHandler for CalloopData<B> {
}
}
fn move_request(&mut self, xwm: XwmId, window: smithay::xwayland::X11Surface, button: u32) {
todo!()
fn move_request(&mut self, xwm: XwmId, window: X11Surface, button: u32) {
// TODO:
}
// TODO: allow_selection_access

View file

@ -47,7 +47,7 @@ use smithay::{
Display,
},
},
utils::{Clock, Logical, Monotonic, Point, Size},
utils::{Clock, IsAlive, Logical, Monotonic, Point, Size},
wayland::{
compositor::{self, CompositorClientState, CompositorState},
data_device::DataDeviceState,
@ -305,20 +305,24 @@ impl<B: Backend> State<B> {
.as_ref()
.and_then(|win| self.space.element_location(win))
.map(|loc| (loc.x, loc.y));
let (class, title) = window.as_ref().and_then(|win| win.wl_surface()).map_or(
(None, None),
|wl_surf| {
compositor::with_states(&wl_surf, |states| {
let lock = states
.data_map
.get::<XdgToplevelSurfaceData>()
.expect("XdgToplevelSurfaceData wasn't in surface's data map")
.lock()
.expect("failed to acquire lock");
(lock.app_id.clone(), lock.title.clone())
})
},
);
let (class, title) = window.as_ref().map_or((None, None), |win| match &win {
WindowElement::Wayland(_) => {
if let Some(wl_surf) = win.wl_surface() {
compositor::with_states(&wl_surf, |states| {
let lock = states
.data_map
.get::<XdgToplevelSurfaceData>()
.expect("XdgToplevelSurfaceData wasn't in surface's data map")
.lock()
.expect("failed to acquire lock");
(lock.app_id.clone(), lock.title.clone())
})
} else {
(None, None)
}
}
WindowElement::X11(surface) => (Some(surface.class()), Some(surface.title())),
});
let floating = window
.as_ref()
.map(|win| win.with_state(|state| state.floating.is_floating()));
@ -619,6 +623,11 @@ impl<B: Backend> State<B> {
.any(|tag| tag.output(self).is_some_and(|op| &op == output))
})
})
.filter(|win| match win {
WindowElement::Wayland(win) => !win.with_state(|state| state.minimized),
WindowElement::X11(surf) => !surf.is_minimized(),
})
.filter(|win| win.alive())
.cloned()
.collect::<Vec<_>>();
let (render, do_not_render) = output.with_state(|state| {

View file

@ -40,7 +40,7 @@ use crate::{
state::{State, WithState},
};
use self::window_state::{Float, WindowResizeState, WindowState};
use self::window_state::{Float, WindowElementState, WindowResizeState};
pub mod window_state;
@ -202,6 +202,13 @@ impl WindowElement {
}
}
}
/// Get the output this window is on.
///
/// This method gets the first tag the window has and returns its output.
pub fn output<B: Backend>(&self, state: &State<B>) -> Option<Output> {
self.with_state(|st| st.tags.first().and_then(|tag| tag.output(state)))
}
}
impl IsAlive for WindowElement {
@ -401,7 +408,7 @@ impl SpaceElement for WindowElement {
}
impl WithState for WindowElement {
type State = WindowState;
type State = WindowElementState;
fn with_state<F, T>(&self, mut func: F) -> T
where

View file

@ -1,11 +1,15 @@
// SPDX-License-Identifier: GPL-3.0-or-later
use std::{
cell::RefCell,
fmt,
sync::atomic::{AtomicU32, Ordering},
};
use smithay::utils::{Logical, Point, Serial, Size};
use smithay::{
desktop::Window,
utils::{Logical, Point, Serial, Size},
};
use crate::{
backend::Backend,
@ -35,7 +39,32 @@ impl WindowId {
}
}
#[derive(Debug, Default)]
pub struct WindowState {
pub minimized: bool,
}
impl WithState for Window {
type State = WindowState;
fn with_state<F, T>(&self, mut func: F) -> T
where
F: FnMut(&mut Self::State) -> T,
{
self.user_data()
.insert_if_missing(RefCell::<Self::State>::default);
let state = self
.user_data()
.get::<RefCell<Self::State>>()
.expect("RefCell not in data map");
func(&mut state.borrow_mut())
}
}
#[derive(Debug)]
pub struct WindowElementState {
/// The id of this window.
pub id: WindowId,
/// Whether the window is floating or tiled.
@ -95,6 +124,7 @@ impl fmt::Debug for WindowResizeState {
}
}
#[derive(Debug)]
pub enum Float {
/// The previous location and size of the window when it was floating, if any.
Tiled(Option<(Point<i32, Logical>, Size<i32, Logical>)>),
@ -119,14 +149,14 @@ impl Float {
}
}
impl WindowState {
impl WindowElementState {
#[allow(dead_code)]
pub fn new() -> Self {
Default::default()
}
}
impl Default for WindowState {
impl Default for WindowElementState {
fn default() -> Self {
Self {
// INFO: I think this will assign the id on use of the state, not on window spawn.