Remove space_elements!

so uh when you impl SpaceElement you gotta actually remember to impl the geometry fn, which is why Alacritty was 44 pixels off in the other attempt at this
This commit is contained in:
Ottatop 2024-02-29 20:10:23 -06:00
parent 16fff3f7e3
commit 48cd3d0df9
12 changed files with 379 additions and 733 deletions

View file

@ -34,11 +34,11 @@ use pinnacle_api_defs::pinnacle::{
}, },
}; };
use smithay::{ use smithay::{
desktop::space::SpaceElement, desktop::{space::SpaceElement, WindowSurface},
input::keyboard::XkbConfig, input::keyboard::XkbConfig,
reexports::{calloop, input as libinput, wayland_protocols::xdg::shell::server}, reexports::{calloop, input as libinput, wayland_protocols::xdg::shell::server},
utils::{Point, Rectangle, SERIAL_COUNTER}, utils::{Point, Rectangle, SERIAL_COUNTER},
wayland::{compositor, shell::xdg::XdgToplevelSurfaceData}, wayland::seat::WaylandFocus,
}; };
use sysinfo::ProcessRefreshKind; use sysinfo::ProcessRefreshKind;
use tokio::{ use tokio::{
@ -48,6 +48,7 @@ use tokio::{
}; };
use tokio_stream::{Stream, StreamExt}; use tokio_stream::{Stream, StreamExt};
use tonic::{Request, Response, Status, Streaming}; use tonic::{Request, Response, Status, Streaming};
use tracing::{error, warn};
use crate::{ use crate::{
config::ConnectorSavedState, config::ConnectorSavedState,
@ -56,7 +57,7 @@ use crate::{
output::OutputName, output::OutputName,
state::{State, WithState}, state::{State, WithState},
tag::{Tag, TagId}, tag::{Tag, TagId},
window::{window_state::WindowId, WindowElement}, window::window_state::WindowId,
}; };
type ResponseStream<T> = Pin<Box<dyn Stream<Item = Result<T, Status>> + Send>>; type ResponseStream<T> = Pin<Box<dyn Stream<Item = Result<T, Status>> + Send>>;
@ -316,7 +317,7 @@ impl input_service_server::InputService for InputService {
}; };
if let Some(kb) = state.seat.get_keyboard() { if let Some(kb) = state.seat.get_keyboard() {
if let Err(err) = kb.set_xkb_config(state, new_config) { if let Err(err) = kb.set_xkb_config(state, new_config) {
tracing::error!("Failed to set xkbconfig: {err}"); error!("Failed to set xkbconfig: {err}");
} }
} }
}) })
@ -557,7 +558,7 @@ impl process_service_server::ProcessService for ProcessService {
.args(command) .args(command)
.spawn() .spawn()
else { else {
tracing::warn!("Tried to run {arg0}, but it doesn't exist",); warn!("Tried to run {arg0}, but it doesn't exist",);
return; return;
}; };
@ -584,7 +585,7 @@ impl process_service_server::ProcessService for ProcessService {
match sender.send(response) { match sender.send(response) {
Ok(_) => (), Ok(_) => (),
Err(err) => { Err(err) => {
tracing::error!(err = ?err); error!(err = ?err);
break; break;
} }
} }
@ -608,7 +609,7 @@ impl process_service_server::ProcessService for ProcessService {
match sender.send(response) { match sender.send(response) {
Ok(_) => (), Ok(_) => (),
Err(err) => { Err(err) => {
tracing::error!(err = ?err); error!(err = ?err);
break; break;
} }
} }
@ -627,7 +628,7 @@ impl process_service_server::ProcessService for ProcessService {
// TODO: handle error // TODO: handle error
let _ = sender.send(response); let _ = sender.send(response);
} }
Err(err) => tracing::warn!("child wait() err: {err}"), Err(err) => warn!("child wait() err: {err}"),
} }
}); });
}) })
@ -1122,15 +1123,17 @@ impl window_service_server::WindowService for WindowService {
run_unary_no_response(&self.sender, move |state| { run_unary_no_response(&self.sender, move |state| {
let Some(window) = window_id.window(state) else { return }; let Some(window) = window_id.window(state) else { return };
match window { match window.underlying_surface() {
WindowElement::Wayland(window) => { WindowSurface::Wayland(toplevel) => toplevel.send_close(),
window.toplevel().expect("in wayland enum").send_close() WindowSurface::X11(surface) => {
if !surface.is_override_redirect() {
if let Err(err) = surface.close() {
error!("failed to close x11 window: {err}");
}
} else {
warn!("tried to close OR window");
}
} }
WindowElement::X11(surface) => surface.close().expect("failed to close x11 win"),
WindowElement::X11OverrideRedirect(_) => {
tracing::warn!("tried to close override redirect window");
}
_ => unreachable!(),
} }
}) })
.await .await
@ -1356,32 +1359,14 @@ impl window_service_server::WindowService for WindowService {
return; return;
}; };
if window.is_x11_override_redirect() {
return;
}
let Some(output) = window.output(state) else { let Some(output) = window.output(state) else {
return; return;
}; };
// if !matches!(
// &focus,
// FocusTarget::Window(WindowElement::X11OverrideRedirect(_))
// ) {
// keyboard.set_focus(self, Some(focus.clone()), serial);
// }
//
// self.space.elements().for_each(|window| {
// if let WindowElement::Wayland(window) = window {
// window.toplevel().send_configure();
// }
// });
// } else {
// self.space.elements().for_each(|window| {
// window.set_activate(false);
// if let WindowElement::Wayland(window) = window {
// window.toplevel().send_configure();
// }
// });
// keyboard.set_focus(self, None, serial);
// }
for win in state.space.elements() { for win in state.space.elements() {
win.set_activate(false); win.set_activate(false);
} }
@ -1432,8 +1417,8 @@ impl window_service_server::WindowService for WindowService {
} }
for window in state.space.elements() { for window in state.space.elements() {
if let WindowElement::Wayland(window) = window { if let Some(toplevel) = window.toplevel() {
window.toplevel().expect("in wayland enum").send_configure(); toplevel.send_configure();
} }
} }
@ -1677,27 +1662,8 @@ impl window_service_server::WindowService for WindowService {
}) })
}; };
let (class, title) = window.as_ref().map_or((None, None), |win| match &win { let class = window.as_ref().and_then(|win| win.class());
WindowElement::Wayland(_) => { let title = window.as_ref().and_then(|win| win.title());
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) | WindowElement::X11OverrideRedirect(surface) => {
(Some(surface.class()), Some(surface.title()))
}
_ => unreachable!(),
});
let focused = window.as_ref().and_then(|win| { let focused = window.as_ref().and_then(|win| {
state state

View file

@ -56,8 +56,8 @@ impl State {
if let Some(win) = &current_focus { if let Some(win) = &current_focus {
assert!(!win.is_x11_override_redirect()); assert!(!win.is_x11_override_redirect());
if let WindowElement::Wayland(w) = win { if let Some(toplevel) = win.toplevel() {
w.toplevel().expect("in wayland enum").send_configure(); toplevel.send_configure();
} }
} }
@ -437,13 +437,9 @@ impl WaylandFocus for FocusTarget {
object_id: &smithay::reexports::wayland_server::backend::ObjectId, object_id: &smithay::reexports::wayland_server::backend::ObjectId,
) -> bool { ) -> bool {
match self { match self {
FocusTarget::Window(WindowElement::Wayland(window)) => window.same_client_as(object_id), FocusTarget::Window(window) => window.same_client_as(object_id),
FocusTarget::Window(
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface),
) => surface.same_client_as(object_id),
FocusTarget::Popup(popup) => popup.wl_surface().id().same_client_as(object_id), FocusTarget::Popup(popup) => popup.wl_surface().id().same_client_as(object_id),
FocusTarget::LayerSurface(surf) => surf.wl_surface().id().same_client_as(object_id), FocusTarget::LayerSurface(surf) => surf.wl_surface().id().same_client_as(object_id),
_ => unreachable!(),
} }
} }
} }

View file

@ -51,13 +51,16 @@ impl PointerGrab<State> for MoveSurfaceGrab {
} }
state.space.raise_element(&self.window, false); state.space.raise_element(&self.window, false);
if let WindowElement::X11(surface) = &self.window { if let Some(surface) = self.window.x11_surface() {
state // INFO: can you raise OR windows or no idk
.xwm if !surface.is_override_redirect() {
.as_mut() state
.expect("no xwm") .xwm
.raise_window(surface) .as_mut()
.expect("failed to raise x11 win"); .expect("no xwm")
.raise_window(surface)
.expect("failed to raise x11 win");
}
} }
let is_tiled = self let is_tiled = self
@ -136,12 +139,14 @@ impl PointerGrab<State> for MoveSurfaceGrab {
} }
}); });
if let WindowElement::X11(surface) = &self.window { if let Some(surface) = self.window.x11_surface() {
let geo = surface.geometry(); if !surface.is_override_redirect() {
let new_geo = Rectangle::from_loc_and_size(new_loc, geo.size); let geo = surface.geometry();
surface let new_geo = Rectangle::from_loc_and_size(new_loc, geo.size);
.configure(new_geo) surface
.expect("failed to configure x11 win"); .configure(new_geo)
.expect("failed to configure x11 win");
}
} }
let outputs = state.space.outputs_for_element(&self.window); let outputs = state.space.outputs_for_element(&self.window);

View file

@ -1,17 +1,17 @@
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
use smithay::{ use smithay::{
desktop::space::SpaceElement, desktop::{space::SpaceElement, utils::bbox_from_surface_tree, WindowSurface},
input::{ input::{
pointer::{AxisFrame, ButtonEvent, Focus, GrabStartData, PointerGrab, PointerInnerHandle}, pointer::{AxisFrame, ButtonEvent, Focus, GrabStartData, PointerGrab, PointerInnerHandle},
Seat, SeatHandler, Seat, SeatHandler,
}, },
reexports::{ reexports::{
wayland_protocols::xdg::shell::server::xdg_toplevel::{self}, wayland_protocols::xdg::shell::server::xdg_toplevel,
wayland_server::protocol::wl_surface::WlSurface, wayland_server::protocol::wl_surface::WlSurface,
}, },
utils::{IsAlive, Logical, Point, Rectangle, Size}, utils::{IsAlive, Logical, Point, Rectangle, Size},
wayland::{compositor, shell::xdg::SurfaceCachedState}, wayland::{compositor, seat::WaylandFocus, shell::xdg::SurfaceCachedState},
xwayland, xwayland,
}; };
@ -158,28 +158,26 @@ impl PointerGrab<State> for ResizeSurfaceGrab {
new_window_height.clamp(min_height, max_height), new_window_height.clamp(min_height, max_height),
)); ));
match &self.window { match self.window.underlying_surface() {
WindowElement::Wayland(window) => { WindowSurface::Wayland(toplevel) => {
let toplevel_surface = window.toplevel().expect("in wayland enum"); toplevel.with_pending_state(|state| {
toplevel_surface.with_pending_state(|state| {
state.states.set(xdg_toplevel::State::Resizing); state.states.set(xdg_toplevel::State::Resizing);
state.size = Some(self.last_window_size); state.size = Some(self.last_window_size);
}); });
toplevel_surface.send_pending_configure(); toplevel.send_pending_configure();
} }
WindowElement::X11(surface) => { WindowSurface::X11(surface) => {
let loc = data if !surface.is_override_redirect() {
.space let loc = data
.element_location(&self.window) .space
.expect("failed to get x11 win loc"); .element_location(&self.window)
surface .expect("failed to get x11 win loc");
.configure(Rectangle::from_loc_and_size(loc, self.last_window_size)) surface
.expect("failed to configure x11 win"); .configure(Rectangle::from_loc_and_size(loc, self.last_window_size))
.expect("failed to configure x11 win");
}
} }
WindowElement::X11OverrideRedirect(_) => (),
_ => unreachable!(),
} }
} }
@ -208,17 +206,16 @@ impl PointerGrab<State> for ResizeSurfaceGrab {
return; return;
} }
match &self.window { match self.window.underlying_surface() {
WindowElement::Wayland(window) => { WindowSurface::Wayland(toplevel) => {
let toplevel_surface = window.toplevel().expect("in wayland enum"); toplevel.with_pending_state(|state| {
toplevel_surface.with_pending_state(|state| {
state.states.unset(xdg_toplevel::State::Resizing); state.states.unset(xdg_toplevel::State::Resizing);
state.size = Some(self.last_window_size); state.size = Some(self.last_window_size);
}); });
toplevel_surface.send_pending_configure(); toplevel.send_pending_configure();
toplevel_surface.wl_surface().with_state(|state| { toplevel.wl_surface().with_state(|state| {
// TODO: validate resize state // TODO: validate resize state
state.resize_state = ResizeSurfaceState::WaitingForLastCommit { state.resize_state = ResizeSurfaceState::WaitingForLastCommit {
edges: self.edges, edges: self.edges,
@ -226,7 +223,10 @@ impl PointerGrab<State> for ResizeSurfaceGrab {
}; };
}); });
} }
WindowElement::X11(surface) => { WindowSurface::X11(surface) => {
if surface.is_override_redirect() {
return;
}
let Some(surface) = surface.wl_surface() else { return }; let Some(surface) = surface.wl_surface() else { return };
surface.with_state(|state| { surface.with_state(|state| {
state.resize_state = ResizeSurfaceState::WaitingForLastCommit { state.resize_state = ResizeSurfaceState::WaitingForLastCommit {
@ -235,8 +235,6 @@ impl PointerGrab<State> for ResizeSurfaceGrab {
}; };
}); });
} }
WindowElement::X11OverrideRedirect(_) => (),
_ => unreachable!(),
} }
} }
} }
@ -418,12 +416,14 @@ pub fn handle_commit(state: &mut State, surface: &WlSurface) -> Option<()> {
if new_loc.x.is_some() || new_loc.y.is_some() { if new_loc.x.is_some() || new_loc.y.is_some() {
state.space.map_element(window.clone(), window_loc, false); state.space.map_element(window.clone(), window_loc, false);
if let WindowElement::X11(surface) = window { if let Some(surface) = window.x11_surface() {
let geo = surface.geometry(); if !surface.is_override_redirect() {
let new_geo = Rectangle::from_loc_and_size(window_loc, geo.size); let geo = surface.geometry();
surface let new_geo = Rectangle::from_loc_and_size(window_loc, geo.size);
.configure(new_geo) surface
.expect("failed to configure x11 win"); .configure(new_geo)
.expect("failed to configure x11 win");
}
} }
} }
@ -458,18 +458,14 @@ pub fn resize_request_client(
.expect("resize request called on unmapped window"); .expect("resize request called on unmapped window");
let initial_window_size = window.geometry().size; let initial_window_size = window.geometry().size;
if let Some(WindowElement::Wayland(window)) = state.window_for_surface(surface) { if let Some(window) = state.window_for_surface(surface) {
window if let Some(toplevel) = window.toplevel() {
.toplevel() toplevel.with_pending_state(|state| {
.expect("in wayland enum")
.with_pending_state(|state| {
state.states.set(xdg_toplevel::State::Resizing); state.states.set(xdg_toplevel::State::Resizing);
}); });
window toplevel.send_pending_configure();
.toplevel() }
.expect("in wayland enum")
.send_pending_configure();
} }
let grab = ResizeSurfaceGrab::start( let grab = ResizeSurfaceGrab::start(
@ -512,18 +508,14 @@ pub fn resize_request_server(
.expect("resize request called on unmapped window"); .expect("resize request called on unmapped window");
let initial_window_size = window.geometry().size; let initial_window_size = window.geometry().size;
if let Some(WindowElement::Wayland(window)) = state.window_for_surface(surface) { if let Some(window) = state.window_for_surface(surface) {
window if let Some(toplevel) = window.toplevel() {
.toplevel() toplevel.with_pending_state(|state| {
.expect("in wayland enum")
.with_pending_state(|state| {
state.states.set(xdg_toplevel::State::Resizing); state.states.set(xdg_toplevel::State::Resizing);
}); });
window toplevel.send_pending_configure();
.toplevel() }
.expect("in wayland enum")
.send_pending_configure();
} }
let start_data = smithay::input::pointer::GrabStartData { let start_data = smithay::input::pointer::GrabStartData {

View file

@ -60,7 +60,6 @@ use smithay::{
use crate::{ use crate::{
focus::FocusTarget, focus::FocusTarget,
state::{ClientState, State, WithState}, state::{ClientState, State, WithState},
window::WindowElement,
}; };
impl BufferHandler for State { impl BufferHandler for State {
@ -107,9 +106,10 @@ impl CompositorHandler for State {
fn commit(&mut self, surface: &WlSurface) { fn commit(&mut self, surface: &WlSurface) {
tracing::trace!("commit on surface {surface:?}"); tracing::trace!("commit on surface {surface:?}");
utils::on_commit_buffer_handler::<State>(surface);
X11Wm::commit_hook::<State>(surface); X11Wm::commit_hook::<State>(surface);
utils::on_commit_buffer_handler::<State>(surface);
self.backend.early_import(surface); self.backend.early_import(surface);
let mut root = surface.clone(); let mut root = surface.clone();
@ -118,10 +118,10 @@ impl CompositorHandler for State {
} }
if !compositor::is_sync_subsurface(surface) { if !compositor::is_sync_subsurface(surface) {
if let Some(win @ WindowElement::Wayland(window)) = &self.window_for_surface(&root) { if let Some(window) = self.window_for_surface(&root) {
window.on_commit(); window.on_commit();
if let Some(loc) = win.with_state(|state| state.target_loc.take()) { if let Some(loc) = window.with_state(|state| state.target_loc.take()) {
self.space.map_element(win.clone(), loc, false); self.space.map_element(window.clone(), loc, false);
} }
} }
}; };
@ -149,7 +149,7 @@ impl CompositorHandler for State {
self.output_focus_stack.current_focus(), self.output_focus_stack.current_focus(),
self.space.outputs().next(), self.space.outputs().next(),
) { ) {
tracing::debug!("PLACING TOPLEVEL"); tracing::debug!("Placing toplevel");
new_window.place_on_output(output); new_window.place_on_output(output);
output.with_state(|state| state.focus_stack.set_focus(new_window.clone())); output.with_state(|state| state.focus_stack.set_focus(new_window.clone()));
} }
@ -180,22 +180,9 @@ impl CompositorHandler for State {
SERIAL_COUNTER.next_serial(), SERIAL_COUNTER.next_serial(),
); );
}); });
} else if let WindowElement::Wayland(window) = &new_window { } else if new_window.toplevel().is_some() {
window.on_commit(); new_window.on_commit();
let initial_configure_sent = compositor::with_states(surface, |states| { ensure_initial_configure(surface, self);
states
.data_map
.get::<XdgToplevelSurfaceData>()
.expect("XdgToplevelSurfaceData wasn't in surface's data map")
.lock()
.expect("Failed to lock Mutex<XdgToplevelSurfaceData>")
.initial_configure_sent
});
if !initial_configure_sent {
tracing::debug!("Initial configure");
window.toplevel().expect("in wayland enum").send_configure();
}
} }
return; return;
@ -266,8 +253,11 @@ impl CompositorHandler for State {
delegate_compositor!(State); delegate_compositor!(State);
fn ensure_initial_configure(surface: &WlSurface, state: &mut State) { fn ensure_initial_configure(surface: &WlSurface, state: &mut State) {
if let Some(window) = state.window_for_surface(surface) { if let (Some(window), _) | (None, Some(window)) = (
if let WindowElement::Wayland(window) = &window { state.window_for_surface(surface),
state.new_window_for_surface(surface),
) {
if let Some(toplevel) = window.toplevel() {
let initial_configure_sent = compositor::with_states(surface, |states| { let initial_configure_sent = compositor::with_states(surface, |states| {
states states
.data_map .data_map
@ -280,7 +270,7 @@ fn ensure_initial_configure(surface: &WlSurface, state: &mut State) {
if !initial_configure_sent { if !initial_configure_sent {
tracing::debug!("Initial configure"); tracing::debug!("Initial configure");
window.toplevel().expect("in wayland enum").send_configure(); toplevel.send_configure();
} }
} }
return; return;

View file

@ -17,8 +17,11 @@ use smithay::{
}, },
}, },
utils::{Logical, Point, Rectangle, Serial, SERIAL_COUNTER}, utils::{Logical, Point, Rectangle, Serial, SERIAL_COUNTER},
wayland::shell::xdg::{ wayland::{
PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState, seat::WaylandFocus,
shell::xdg::{
PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState,
},
}, },
}; };
@ -41,65 +44,8 @@ impl XdgShellHandler for State {
state.states.set(xdg_toplevel::State::TiledRight); state.states.set(xdg_toplevel::State::TiledRight);
}); });
let window = WindowElement::Wayland(Window::new_wayland_window(surface.clone())); let window = WindowElement::new(Window::new_wayland_window(surface.clone()));
self.new_windows.push(window); self.new_windows.push(window);
// if let (Some(output), _) | (None, Some(output)) = (
// &self.focus_state.focused_output,
// self.space.outputs().next(),
// ) {
// tracing::debug!("PLACING TOPLEVEL");
// window.place_on_output(output);
// }
//
// // note to self: don't reorder this
// // TODO: fix it so that reordering this doesn't break stuff
// self.windows.push(window.clone());
//
// self.space.map_element(window.clone(), (0, 0), true);
//
// let win_clone = window.clone();
//
// // Let the initial configure happen before updating the windows
// self.schedule(
// move |_data| {
// if let WindowElement::Wayland(window) = &win_clone {
// let initial_configure_sent =
// compositor::with_states(window.toplevel().wl_surface(), |states| {
// states
// .data_map
// .get::<smithay::wayland::shell::xdg::XdgToplevelSurfaceData>()
// .expect("XdgToplevelSurfaceData wasn't in surface's data map")
// .lock()
// .expect("Failed to lock Mutex<XdgToplevelSurfaceData>")
// .initial_configure_sent
// });
//
// initial_configure_sent
// } else {
// true
// }
// },
// |data| {
// data.state.apply_window_rules(&window);
//
// if let Some(focused_output) = data.state.focus_state.focused_output.clone() {
// data.state.update_windows(&focused_output);
// }
//
// data.state.loop_handle.insert_idle(move |data| {
// data.state
// .seat
// .get_keyboard()
// .expect("Seat had no keyboard") // FIXME: actually handle error
// .set_focus(
// &mut data.state,
// Some(FocusTarget::Window(window)),
// SERIAL_COUNTER.next_serial(),
// );
// });
// },
// );
} }
fn toplevel_destroyed(&mut self, surface: ToplevelSurface) { fn toplevel_destroyed(&mut self, surface: ToplevelSurface) {
@ -138,8 +84,8 @@ impl XdgShellHandler for State {
// TODO: // TODO:
self.space.raise_element(win, true); self.space.raise_element(win, true);
self.z_index_stack.set_focus(win.clone()); self.z_index_stack.set_focus(win.clone());
if let WindowElement::Wayland(win) = &win { if let Some(toplevel) = win.toplevel() {
win.toplevel().expect("in wayland enum").send_configure(); toplevel.send_configure();
} }
} }
self.seat self.seat
@ -733,27 +679,6 @@ impl XdgShellHandler for State {
} }
} }
// fn ack_configure(&mut self, surface: WlSurface, configure: Configure) {
// if let Some(window) = self.window_for_surface(&surface) {
// if let LocationRequestState::Requested(serial, new_loc) =
// window.with_state(|state| state.loc_request_state.clone())
// {
// match &configure {
// Configure::Toplevel(configure) => {
// if configure.serial >= serial {
// tracing::debug!("acked configure, new loc is {:?}", new_loc);
// window.with_state(|state| {
// state.loc_request_state =
// LocationRequestState::Acknowledged(new_loc);
// });
// }
// }
// Configure::Popup(_) => todo!(),
// }
// }
// }
// }
fn fullscreen_request(&mut self, surface: ToplevelSurface, mut wl_output: Option<WlOutput>) { fn fullscreen_request(&mut self, surface: ToplevelSurface, mut wl_output: Option<WlOutput>) {
if !surface if !surface
.current_state() .current_state()

View file

@ -1,13 +1,15 @@
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
use smithay::{ use smithay::{
desktop::Window,
utils::{Logical, Point, Rectangle, SERIAL_COUNTER}, utils::{Logical, Point, Rectangle, SERIAL_COUNTER},
wayland::{ wayland::{
selection::data_device::{ seat::WaylandFocus,
clear_data_device_selection, current_data_device_selection_userdata,
request_data_device_client_selection, set_data_device_selection,
},
selection::{ selection::{
data_device::{
clear_data_device_selection, current_data_device_selection_userdata,
request_data_device_client_selection, set_data_device_selection,
},
primary_selection::{ primary_selection::{
clear_primary_selection, current_primary_selection_userdata, clear_primary_selection, current_primary_selection_userdata,
request_primary_client_selection, set_primary_selection, request_primary_client_selection, set_primary_selection,
@ -36,12 +38,12 @@ impl XwmHandler for State {
fn new_override_redirect_window(&mut self, _xwm: XwmId, _window: X11Surface) {} fn new_override_redirect_window(&mut self, _xwm: XwmId, _window: X11Surface) {}
fn map_window_request(&mut self, _xwm: XwmId, window: X11Surface) { fn map_window_request(&mut self, _xwm: XwmId, surface: X11Surface) {
tracing::trace!("map_window_request"); tracing::trace!("map_window_request");
assert!(!window.is_override_redirect()); assert!(!surface.is_override_redirect());
let window = WindowElement::X11(window); let window = WindowElement::new(Window::new_x11_window(surface));
self.space.map_element(window.clone(), (0, 0), true); self.space.map_element(window.clone(), (0, 0), true);
let bbox = self let bbox = self
.space .space
@ -70,7 +72,7 @@ impl XwmHandler for State {
) )
.into(); .into();
let WindowElement::X11(surface) = &window else { let Some(surface) = window.x11_surface() else {
unreachable!() unreachable!()
}; };
@ -122,14 +124,14 @@ impl XwmHandler for State {
}); });
} }
fn mapped_override_redirect_window(&mut self, _xwm: XwmId, window: X11Surface) { fn mapped_override_redirect_window(&mut self, _xwm: XwmId, surface: X11Surface) {
tracing::trace!("mapped_override_redirect_window"); tracing::trace!("mapped_override_redirect_window");
assert!(window.is_override_redirect()); assert!(surface.is_override_redirect());
let loc = window.geometry().loc; let loc = surface.geometry().loc;
let window = WindowElement::X11OverrideRedirect(window); let window = WindowElement::new(Window::new_x11_window(surface));
self.windows.push(window.clone()); self.windows.push(window.clone());
self.z_index_stack.set_focus(window.clone()); self.z_index_stack.set_focus(window.clone());
@ -139,18 +141,20 @@ impl XwmHandler for State {
self.space.outputs().next(), self.space.outputs().next(),
) { ) {
window.place_on_output(output); window.place_on_output(output);
// FIXME: setting focus here may possibly muck things up
// | or maybe they won't idk
output.with_state(|state| state.focus_stack.set_focus(window.clone())) output.with_state(|state| state.focus_stack.set_focus(window.clone()))
} }
self.space.map_element(window, loc, true); self.space.map_element(window, loc, true);
} }
fn unmapped_window(&mut self, _xwm: XwmId, window: X11Surface) { fn unmapped_window(&mut self, _xwm: XwmId, surface: X11Surface) {
for output in self.space.outputs() { for output in self.space.outputs() {
output.with_state(|state| { output.with_state(|state| {
state.focus_stack.stack.retain(|win| { state.focus_stack.stack.retain(|win| {
win.wl_surface() win.wl_surface()
.is_some_and(|surf| Some(surf) != window.wl_surface()) .is_some_and(|surf| Some(surf) != surface.wl_surface())
}) })
}); });
} }
@ -158,7 +162,7 @@ impl XwmHandler for State {
let win = self let win = self
.space .space
.elements() .elements()
.find(|elem| matches!(elem, WindowElement::X11(surface) if surface == &window)) .find(|elem| matches!(elem.x11_surface(), Some(surf) if surf == &surface))
.cloned(); .cloned();
if let Some(win) = win { if let Some(win) = win {
@ -178,8 +182,8 @@ impl XwmHandler for State {
if let Some(FocusTarget::Window(win)) = &focus { if let Some(FocusTarget::Window(win)) = &focus {
self.space.raise_element(win, true); self.space.raise_element(win, true);
self.z_index_stack.set_focus(win.clone()); self.z_index_stack.set_focus(win.clone());
if let WindowElement::Wayland(win) = &win { if let Some(toplevel) = win.toplevel() {
win.toplevel().expect("in wayland enum").send_configure(); toplevel.send_configure();
} }
} }
@ -192,18 +196,18 @@ impl XwmHandler for State {
} }
} }
if !window.is_override_redirect() { if !surface.is_override_redirect() {
tracing::debug!("set mapped to false"); tracing::debug!("set mapped to false");
window.set_mapped(false).expect("failed to unmap x11 win"); surface.set_mapped(false).expect("failed to unmap x11 win");
} }
} }
fn destroyed_window(&mut self, _xwm: XwmId, window: X11Surface) { fn destroyed_window(&mut self, _xwm: XwmId, surface: X11Surface) {
for output in self.space.outputs() { for output in self.space.outputs() {
output.with_state(|state| { output.with_state(|state| {
state.focus_stack.stack.retain(|win| { state.focus_stack.stack.retain(|win| {
win.wl_surface() win.wl_surface()
.is_some_and(|surf| Some(surf) != window.wl_surface()) .is_some_and(|surf| Some(surf) != surface.wl_surface())
}) })
}); });
} }
@ -213,10 +217,8 @@ impl XwmHandler for State {
.iter() .iter()
.find(|elem| { .find(|elem| {
matches!( matches!(
elem, elem.x11_surface(),
WindowElement::X11(surface) Some(surf) if surf.wl_surface() == surface.wl_surface()
| WindowElement::X11OverrideRedirect(surface)
if surface.wl_surface() == window.wl_surface()
) )
}) })
.cloned(); .cloned();
@ -241,8 +243,8 @@ impl XwmHandler for State {
if let Some(FocusTarget::Window(win)) = &focus { if let Some(FocusTarget::Window(win)) = &focus {
self.space.raise_element(win, true); self.space.raise_element(win, true);
self.z_index_stack.set_focus(win.clone()); self.z_index_stack.set_focus(win.clone());
if let WindowElement::Wayland(win) = &win { if let Some(toplevel) = win.toplevel() {
win.toplevel().expect("in wayland enum").send_configure(); toplevel.send_configure();
} }
} }
@ -283,14 +285,14 @@ impl XwmHandler for State {
fn configure_notify( fn configure_notify(
&mut self, &mut self,
_xwm: XwmId, _xwm: XwmId,
window: X11Surface, surface: X11Surface,
geometry: Rectangle<i32, Logical>, geometry: Rectangle<i32, Logical>,
_above: Option<smithay::reexports::x11rb::protocol::xproto::Window>, _above: Option<smithay::reexports::x11rb::protocol::xproto::Window>,
) { ) {
let Some(win) = self let Some(win) = self
.space .space
.elements() .elements()
.find(|elem| matches!(elem, WindowElement::X11(surface) if surface == &window)) .find(|elem| matches!(elem.x11_surface(), Some(surf) if surf == &surface))
.cloned() .cloned()
else { else {
return; return;
@ -409,11 +411,12 @@ impl XwmHandler for State {
.get_keyboard() .get_keyboard()
.and_then(|kb| kb.current_focus()) .and_then(|kb| kb.current_focus())
.is_some_and(|focus| { .is_some_and(|focus| {
if let FocusTarget::Window(WindowElement::X11(surface)) = focus { if let FocusTarget::Window(window) = focus {
surface.xwm_id().expect("x11surface had no xwm id") == xwm if let Some(surface) = window.x11_surface() {
} else { return surface.xwm_id().expect("x11surface had no xwm id") == xwm;
false }
} }
false
}) })
} }

View file

@ -4,7 +4,7 @@ pub mod libinput;
use std::{collections::HashMap, mem::Discriminant}; use std::{collections::HashMap, mem::Discriminant};
use crate::{focus::FocusTarget, state::WithState, window::WindowElement}; use crate::{focus::FocusTarget, state::WithState};
use pinnacle_api_defs::pinnacle::input::v0alpha1::{ use pinnacle_api_defs::pinnacle::input::v0alpha1::{
set_libinput_setting_request::Setting, set_mousebind_request, SetKeybindResponse, set_libinput_setting_request::Setting, set_mousebind_request, SetKeybindResponse,
SetMousebindResponse, SetMousebindResponse,
@ -351,14 +351,14 @@ impl State {
if !matches!( if !matches!(
&focus, &focus,
FocusTarget::Window(WindowElement::X11OverrideRedirect(_)) FocusTarget::Window(window) if window.is_x11_override_redirect()
) { ) {
keyboard.set_focus(self, Some(focus.clone()), serial); keyboard.set_focus(self, Some(focus.clone()), serial);
} }
for window in self.space.elements() { for window in self.space.elements() {
if let WindowElement::Wayland(window) = window { if let Some(toplevel) = window.toplevel() {
window.toplevel().expect("in wayland enum").send_configure(); toplevel.send_configure();
} }
} }
} else { } else {
@ -367,8 +367,8 @@ impl State {
state.focus_stack.unset_focus(); state.focus_stack.unset_focus();
for window in state.focus_stack.stack.iter() { for window in state.focus_stack.stack.iter() {
window.set_activate(false); window.set_activate(false);
if let WindowElement::Wayland(window) = window { if let Some(toplevel) = window.toplevel() {
window.toplevel().expect("in wayland enum").send_configure(); toplevel.send_configure();
} }
} }
}); });

View file

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
use smithay::{ use smithay::{
desktop::layer_map_for_output, desktop::{layer_map_for_output, WindowSurface},
output::Output, output::Output,
utils::{Logical, Point, Rectangle, Serial, Size}, utils::{Logical, Point, Rectangle, Serial, Size},
wayland::{compositor, shell::xdg::XdgToplevelSurfaceData}, wayland::{compositor, shell::xdg::XdgToplevelSurfaceData},
@ -115,26 +115,20 @@ impl State {
for win in windows_on_foc_tags.iter() { for win in windows_on_foc_tags.iter() {
if win.with_state(|state| state.target_loc.is_some()) { if win.with_state(|state| state.target_loc.is_some()) {
match win { match win.underlying_surface() {
WindowElement::Wayland(wl_win) => { WindowSurface::Wayland(toplevel) => {
let pending = compositor::with_states( let pending = compositor::with_states(toplevel.wl_surface(), |states| {
wl_win.toplevel().expect("in wayland enum").wl_surface(), states
|states| { .data_map
states .get::<XdgToplevelSurfaceData>()
.data_map .expect("XdgToplevelSurfaceData wasn't in surface's data map")
.get::<XdgToplevelSurfaceData>() .lock()
.expect("XdgToplevelSurfaceData wasn't in surface's data map") .expect("Failed to lock Mutex<XdgToplevelSurfaceData>")
.lock() .has_pending_changes()
.expect("Failed to lock Mutex<XdgToplevelSurfaceData>") });
.has_pending_changes()
},
);
if pending { if pending {
pending_wins.push(( pending_wins.push((win.clone(), toplevel.send_configure()))
win.clone(),
wl_win.toplevel().expect("in wayland enum").send_configure(),
))
} else { } else {
let loc = win.with_state(|state| state.target_loc.take()); let loc = win.with_state(|state| state.target_loc.take());
if let Some(loc) = loc { if let Some(loc) = loc {
@ -142,14 +136,12 @@ impl State {
} }
} }
} }
WindowElement::X11(_) => { WindowSurface::X11(_) => {
let loc = win.with_state(|state| state.target_loc.take()); let loc = win.with_state(|state| state.target_loc.take());
if let Some(loc) = loc { if let Some(loc) = loc {
self.space.map_element(win.clone(), loc, false); self.space.map_element(win.clone(), loc, false);
} }
} }
WindowElement::X11OverrideRedirect(_) => (),
_ => unreachable!(),
} }
} }
} }

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
use std::sync::Mutex; use std::{ops::Deref, sync::Mutex};
use smithay::{ use smithay::{
backend::renderer::{ backend::renderer::{
@ -71,18 +71,8 @@ where
scale: Scale<f64>, scale: Scale<f64>,
alpha: f32, alpha: f32,
) -> Vec<C> { ) -> Vec<C> {
match self { self.deref()
WindowElement::Wayland(window) => { .render_elements(renderer, location, scale, alpha)
window.render_elements(renderer, location, scale, alpha)
}
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
surface.render_elements(renderer, location, scale, alpha)
}
_ => unreachable!(),
}
.into_iter()
.map(C::from)
.collect()
} }
} }
@ -307,10 +297,8 @@ where
let top_fullscreen_window = windows.iter().rev().find(|win| { let top_fullscreen_window = windows.iter().rev().find(|win| {
let is_wayland_actually_fullscreen = { let is_wayland_actually_fullscreen = {
if let WindowElement::Wayland(window) = win { if let Some(toplevel) = win.toplevel() {
window toplevel
.toplevel()
.expect("in wayland enum")
.current_state() .current_state()
.states .states
.contains(xdg_toplevel::State::Fullscreen) .contains(xdg_toplevel::State::Fullscreen)

View file

@ -2,40 +2,23 @@
pub mod rules; pub mod rules;
use std::{cell::RefCell, time::Duration}; use std::{cell::RefCell, ops::Deref};
use pinnacle_api_defs::pinnacle::signal::v0alpha1::{ use pinnacle_api_defs::pinnacle::signal::v0alpha1::{
WindowPointerEnterResponse, WindowPointerLeaveResponse, WindowPointerEnterResponse, WindowPointerLeaveResponse,
}; };
use smithay::{ use smithay::{
backend::input::KeyState, backend::input::KeyState,
desktop::{ desktop::{space::SpaceElement, Window, WindowSurface},
utils::{
send_dmabuf_feedback_surface_tree, send_frames_surface_tree,
take_presentation_feedback_surface_tree, with_surfaces_surface_tree,
OutputPresentationFeedback,
},
Window,
},
input::{ input::{
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState}, keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
pointer::{AxisFrame, MotionEvent, PointerTarget}, pointer::{AxisFrame, MotionEvent, PointerTarget},
Seat, Seat,
}, },
output::Output, output::Output,
reexports::{ reexports::wayland_server::protocol::wl_surface::WlSurface,
wayland_protocols::wp::presentation_time::server::wp_presentation_feedback, utils::{IsAlive, Logical, Point, Rectangle, Serial},
wayland_server::protocol::wl_surface::WlSurface, wayland::{compositor, seat::WaylandFocus, shell::xdg::XdgToplevelSurfaceData},
},
space_elements,
utils::{user_data::UserDataMap, Logical, Rectangle, Serial},
wayland::{
compositor::{self, SurfaceData},
dmabuf::DmabufFeedback,
seat::WaylandFocus,
shell::xdg::XdgToplevelSurfaceData,
},
xwayland::X11Surface,
}; };
use crate::state::{State, WithState}; use crate::state::{State, WithState};
@ -44,143 +27,20 @@ use self::window_state::WindowElementState;
pub mod window_state; pub mod window_state;
space_elements! { #[derive(Debug, Clone, PartialEq)]
/// The different types of windows. pub struct WindowElement(Window);
#[derive(Debug, Clone, PartialEq)]
pub WindowElement; impl Deref for WindowElement {
/// This is a native Wayland window. type Target = Window;
Wayland = Window,
/// This is an Xwayland window. fn deref(&self) -> &Self::Target {
X11 = X11Surface, &self.0
/// This is an Xwayland override redirect window, which should not be messed with. }
X11OverrideRedirect = X11Surface,
} }
impl WindowElement { impl WindowElement {
pub fn with_surfaces<F>(&self, processor: F) pub fn new(window: Window) -> Self {
where Self(window)
F: FnMut(&WlSurface, &SurfaceData) + Copy,
{
match self {
WindowElement::Wayland(window) => window.with_surfaces(processor),
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
if let Some(surface) = surface.wl_surface() {
with_surfaces_surface_tree(&surface, processor);
}
}
_ => unreachable!(),
}
}
pub fn send_frame<T, F>(
&self,
output: &Output,
time: T,
throttle: Option<Duration>,
primary_scan_out_output: F,
) where
T: Into<Duration>,
F: FnMut(&WlSurface, &SurfaceData) -> Option<Output> + Copy,
{
match self {
WindowElement::Wayland(window) => {
window.send_frame(output, time, throttle, primary_scan_out_output)
}
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
if let Some(surface) = surface.wl_surface() {
send_frames_surface_tree(
&surface,
output,
time,
throttle,
primary_scan_out_output,
);
}
}
_ => unreachable!(),
}
}
pub fn send_dmabuf_feedback<'a, P, F>(
&self,
output: &Output,
primary_scan_out_output: P,
select_dmabuf_feedback: F,
) where
P: FnMut(&WlSurface, &SurfaceData) -> Option<Output> + Copy,
F: Fn(&WlSurface, &SurfaceData) -> &'a DmabufFeedback + Copy,
{
match self {
WindowElement::Wayland(window) => {
window.send_dmabuf_feedback(
output,
primary_scan_out_output,
select_dmabuf_feedback,
);
}
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
if let Some(surface) = surface.wl_surface() {
send_dmabuf_feedback_surface_tree(
&surface,
output,
primary_scan_out_output,
select_dmabuf_feedback,
);
}
}
_ => unreachable!(),
}
}
pub fn take_presentation_feedback<F1, F2>(
&self,
output_feedback: &mut OutputPresentationFeedback,
primary_scan_out_output: F1,
presentation_feedback_flags: F2,
) where
F1: FnMut(&WlSurface, &SurfaceData) -> Option<Output> + Copy,
F2: FnMut(&WlSurface, &SurfaceData) -> wp_presentation_feedback::Kind + Copy,
{
match self {
WindowElement::Wayland(window) => {
window.take_presentation_feedback(
output_feedback,
primary_scan_out_output,
presentation_feedback_flags,
);
}
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
if let Some(surface) = surface.wl_surface() {
take_presentation_feedback_surface_tree(
&surface,
output_feedback,
primary_scan_out_output,
presentation_feedback_flags,
);
}
}
_ => unreachable!(),
}
}
pub fn wl_surface(&self) -> Option<WlSurface> {
match self {
WindowElement::Wayland(window) => window.wl_surface(),
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
surface.wl_surface()
}
_ => unreachable!(),
}
}
pub fn user_data(&self) -> &UserDataMap {
match self {
WindowElement::Wayland(window) => window.user_data(),
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
surface.user_data()
}
_ => unreachable!(),
}
} }
/// Send a geometry change without mapping windows or sending /// Send a geometry change without mapping windows or sending
@ -191,16 +51,13 @@ impl WindowElement {
/// RefCell Safety: This method uses a [`RefCell`] on this window. /// RefCell Safety: This method uses a [`RefCell`] on this window.
// TODO: ^ does that make things flicker? // TODO: ^ does that make things flicker?
pub fn change_geometry(&self, new_geo: Rectangle<i32, Logical>) { pub fn change_geometry(&self, new_geo: Rectangle<i32, Logical>) {
match self { match self.0.underlying_surface() {
WindowElement::Wayland(window) => { WindowSurface::Wayland(toplevel) => {
window toplevel.with_pending_state(|state| {
.toplevel() state.size = Some(new_geo.size);
.expect("in wayland enum") });
.with_pending_state(|state| {
state.size = Some(new_geo.size);
});
} }
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { WindowSurface::X11(surface) => {
// TODO: maybe move this check elsewhere idk // TODO: maybe move this check elsewhere idk
if !surface.is_override_redirect() { if !surface.is_override_redirect() {
surface surface
@ -208,21 +65,16 @@ impl WindowElement {
.expect("failed to configure x11 win"); .expect("failed to configure x11 win");
} }
} }
_ => unreachable!(),
} }
self.with_state(|state| { self.with_state(|state| {
state.target_loc = Some(new_geo.loc); state.target_loc = Some(new_geo.loc);
}); });
// self.with_state(|state| {
// state.loc_request_state = LocationRequestState::Sent(new_geo.loc);
// });
} }
pub fn class(&self) -> Option<String> { pub fn class(&self) -> Option<String> {
match self { match self.0.underlying_surface() {
WindowElement::Wayland(window) => compositor::with_states( WindowSurface::Wayland(toplevel) => {
window.toplevel().expect("in wayland enum").wl_surface(), compositor::with_states(toplevel.wl_surface(), |states| {
|states| {
states states
.data_map .data_map
.get::<XdgToplevelSurfaceData>() .get::<XdgToplevelSurfaceData>()
@ -231,20 +83,16 @@ impl WindowElement {
.expect("Failed to lock Mutex<XdgToplevelSurfaceData>") .expect("Failed to lock Mutex<XdgToplevelSurfaceData>")
.app_id .app_id
.clone() .clone()
}, })
),
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
Some(surface.class())
} }
_ => unreachable!(), WindowSurface::X11(surface) => Some(surface.class()),
} }
} }
pub fn title(&self) -> Option<String> { pub fn title(&self) -> Option<String> {
match self { match self.0.underlying_surface() {
WindowElement::Wayland(window) => compositor::with_states( WindowSurface::Wayland(toplevel) => {
window.toplevel().expect("in wayland enum").wl_surface(), compositor::with_states(toplevel.wl_surface(), |states| {
|states| {
states states
.data_map .data_map
.get::<XdgToplevelSurfaceData>() .get::<XdgToplevelSurfaceData>()
@ -253,12 +101,9 @@ impl WindowElement {
.expect("Failed to lock Mutex<XdgToplevelSurfaceData>") .expect("Failed to lock Mutex<XdgToplevelSurfaceData>")
.title .title
.clone() .clone()
}, })
),
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
Some(surface.title())
} }
_ => unreachable!(), WindowSurface::X11(surface) => Some(surface.title()),
} }
} }
@ -312,58 +157,67 @@ impl WindowElement {
}); });
} }
/// Returns `true` if the window element is [`Wayland`].
///
/// [`Wayland`]: WindowElement::Wayland
#[must_use]
pub fn is_wayland(&self) -> bool {
matches!(self, Self::Wayland(..))
}
/// Returns `true` if the window element is [`X11`].
///
/// [`X11`]: WindowElement::X11
#[must_use]
pub fn is_x11(&self) -> bool {
matches!(self, Self::X11(..))
}
/// Returns `true` if the window element is [`X11OverrideRedirect`].
///
/// [`X11OverrideRedirect`]: WindowElement::X11OverrideRedirect
#[must_use]
pub fn is_x11_override_redirect(&self) -> bool { pub fn is_x11_override_redirect(&self) -> bool {
matches!(self, Self::X11OverrideRedirect(..)) matches!(self.x11_surface(), Some(surface) if surface.is_override_redirect())
}
}
impl SpaceElement for WindowElement {
fn bbox(&self) -> Rectangle<i32, Logical> {
self.0.bbox()
}
fn is_in_input_region(&self, point: &Point<f64, Logical>) -> bool {
self.0.is_in_input_region(point)
}
fn set_activate(&self, activated: bool) {
self.0.set_activate(activated)
}
fn output_enter(&self, output: &Output, overlap: Rectangle<i32, Logical>) {
self.0.output_enter(output, overlap)
}
fn output_leave(&self, output: &Output) {
self.0.output_leave(output)
}
fn geometry(&self) -> Rectangle<i32, Logical> {
self.0.geometry()
}
fn z_index(&self) -> u8 {
self.0.z_index()
}
fn refresh(&self) {
self.0.refresh();
}
}
impl IsAlive for WindowElement {
fn alive(&self) -> bool {
self.0.alive()
} }
} }
impl PointerTarget<State> for WindowElement { impl PointerTarget<State> for WindowElement {
fn frame(&self, seat: &Seat<State>, state: &mut State) { fn frame(&self, seat: &Seat<State>, state: &mut State) {
match self { match self.underlying_surface() {
WindowElement::Wayland(window) => window WindowSurface::Wayland(toplevel) => {
.wl_surface() PointerTarget::frame(toplevel.wl_surface(), seat, state);
.expect("in wayland enum")
.frame(seat, state),
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
surface.frame(seat, state)
} }
_ => unreachable!(), WindowSurface::X11(surface) => PointerTarget::frame(surface, seat, state),
} }
} }
fn enter(&self, seat: &Seat<State>, state: &mut State, event: &MotionEvent) { fn enter(&self, seat: &Seat<State>, state: &mut State, event: &MotionEvent) {
// TODO: ssd match self.underlying_surface() {
match self { WindowSurface::Wayland(toplevel) => {
WindowElement::Wayland(window) => PointerTarget::enter( PointerTarget::enter(toplevel.wl_surface(), seat, state, event);
&window.wl_surface().expect("in wayland enum"),
seat,
state,
event,
),
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
PointerTarget::enter(surface, seat, state, event)
} }
_ => unreachable!(), WindowSurface::X11(surface) => PointerTarget::enter(surface, seat, state, event),
} }
let window_id = Some(self.with_state(|state| state.id.0)); let window_id = Some(self.with_state(|state| state.id.0));
@ -375,18 +229,11 @@ impl PointerTarget<State> for WindowElement {
} }
fn motion(&self, seat: &Seat<State>, state: &mut State, event: &MotionEvent) { fn motion(&self, seat: &Seat<State>, state: &mut State, event: &MotionEvent) {
// TODO: ssd match self.underlying_surface() {
match self { WindowSurface::Wayland(toplevel) => {
WindowElement::Wayland(window) => PointerTarget::motion( PointerTarget::motion(toplevel.wl_surface(), seat, state, event);
&window.wl_surface().expect("in wayland enum"),
seat,
state,
event,
),
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
PointerTarget::motion(surface, seat, state, event)
} }
_ => unreachable!(), WindowSurface::X11(surface) => PointerTarget::motion(surface, seat, state, event),
} }
} }
@ -396,20 +243,13 @@ impl PointerTarget<State> for WindowElement {
state: &mut State, state: &mut State,
event: &smithay::input::pointer::RelativeMotionEvent, event: &smithay::input::pointer::RelativeMotionEvent,
) { ) {
// TODO: ssd match self.underlying_surface() {
match self { WindowSurface::Wayland(toplevel) => {
WindowElement::Wayland(window) => { PointerTarget::relative_motion(toplevel.wl_surface(), seat, state, event);
PointerTarget::relative_motion(
&window.wl_surface().expect("in wayland enum"),
seat,
state,
event,
);
} }
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { WindowSurface::X11(surface) => {
PointerTarget::relative_motion(surface, seat, state, event); PointerTarget::relative_motion(surface, seat, state, event);
} }
_ => unreachable!(),
} }
} }
@ -419,53 +259,29 @@ impl PointerTarget<State> for WindowElement {
state: &mut State, state: &mut State,
event: &smithay::input::pointer::ButtonEvent, event: &smithay::input::pointer::ButtonEvent,
) { ) {
// TODO: ssd match self.underlying_surface() {
match self { WindowSurface::Wayland(toplevel) => {
WindowElement::Wayland(window) => PointerTarget::button( PointerTarget::button(toplevel.wl_surface(), seat, state, event);
&window.wl_surface().expect("in wayland enum"),
seat,
state,
event,
),
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
PointerTarget::button(surface, seat, state, event)
} }
_ => unreachable!(), WindowSurface::X11(surface) => PointerTarget::button(surface, seat, state, event),
} }
} }
fn axis(&self, seat: &Seat<State>, state: &mut State, frame: AxisFrame) { fn axis(&self, seat: &Seat<State>, state: &mut State, frame: AxisFrame) {
// TODO: ssd match self.underlying_surface() {
match self { WindowSurface::Wayland(toplevel) => {
WindowElement::Wayland(window) => PointerTarget::axis( PointerTarget::axis(toplevel.wl_surface(), seat, state, frame);
&window.wl_surface().expect("in wayland enum"),
seat,
state,
frame,
),
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
PointerTarget::axis(surface, seat, state, frame)
} }
_ => unreachable!(), WindowSurface::X11(surface) => PointerTarget::axis(surface, seat, state, frame),
} }
} }
fn leave(&self, seat: &Seat<State>, state: &mut State, serial: Serial, time: u32) { fn leave(&self, seat: &Seat<State>, state: &mut State, serial: Serial, time: u32) {
// TODO: ssd match self.underlying_surface() {
match self { WindowSurface::Wayland(toplevel) => {
WindowElement::Wayland(window) => { PointerTarget::leave(toplevel.wl_surface(), seat, state, serial, time);
PointerTarget::leave(
&window.wl_surface().expect("in wayland enum"),
seat,
state,
serial,
time,
);
} }
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { WindowSurface::X11(surface) => PointerTarget::leave(surface, seat, state, serial, time),
PointerTarget::leave(surface, seat, state, serial, time)
}
_ => unreachable!(),
} }
let window_id = Some(self.with_state(|state| state.id.0)); let window_id = Some(self.with_state(|state| state.id.0));
@ -557,35 +373,22 @@ impl KeyboardTarget<State> for WindowElement {
keys: Vec<KeysymHandle<'_>>, keys: Vec<KeysymHandle<'_>>,
serial: Serial, serial: Serial,
) { ) {
match self { match self.underlying_surface() {
WindowElement::Wayland(window) => { WindowSurface::Wayland(toplevel) => {
KeyboardTarget::enter( KeyboardTarget::enter(toplevel.wl_surface(), seat, state, keys, serial);
&window.wl_surface().expect("in wayland enum"),
seat,
state,
keys,
serial,
);
} }
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { WindowSurface::X11(surface) => {
KeyboardTarget::enter(surface, seat, state, keys, serial) KeyboardTarget::enter(surface, seat, state, keys, serial);
} }
_ => unreachable!(),
} }
} }
fn leave(&self, seat: &Seat<State>, state: &mut State, serial: Serial) { fn leave(&self, seat: &Seat<State>, state: &mut State, serial: Serial) {
match self { match self.underlying_surface() {
WindowElement::Wayland(window) => KeyboardTarget::leave( WindowSurface::Wayland(toplevel) => {
&window.wl_surface().expect("in wayland enum"), KeyboardTarget::leave(toplevel.wl_surface(), seat, state, serial);
seat,
state,
serial,
),
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
KeyboardTarget::leave(surface, seat, state, serial)
} }
_ => unreachable!(), WindowSurface::X11(surface) => KeyboardTarget::leave(surface, seat, state, serial),
} }
} }
@ -598,10 +401,10 @@ impl KeyboardTarget<State> for WindowElement {
serial: Serial, serial: Serial,
time: u32, time: u32,
) { ) {
match self { match self.underlying_surface() {
WindowElement::Wayland(window) => { WindowSurface::Wayland(toplevel) => {
KeyboardTarget::key( KeyboardTarget::key(
&window.wl_surface().expect("in wayland enum"), toplevel.wl_surface(),
seat, seat,
state, state,
key, key,
@ -610,10 +413,9 @@ impl KeyboardTarget<State> for WindowElement {
time, time,
); );
} }
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { WindowSurface::X11(surface) => {
KeyboardTarget::key(surface, seat, state, key, key_state, serial, time); KeyboardTarget::key(surface, seat, state, key, key_state, serial, time);
} }
_ => unreachable!(),
} }
} }
@ -624,20 +426,13 @@ impl KeyboardTarget<State> for WindowElement {
modifiers: ModifiersState, modifiers: ModifiersState,
serial: Serial, serial: Serial,
) { ) {
match self { match self.underlying_surface() {
WindowElement::Wayland(window) => { WindowSurface::Wayland(toplevel) => {
KeyboardTarget::modifiers( KeyboardTarget::modifiers(toplevel.wl_surface(), seat, state, modifiers, serial);
&window.wl_surface().expect("in wayland enum"),
seat,
state,
modifiers,
serial,
);
} }
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { WindowSurface::X11(surface) => {
KeyboardTarget::modifiers(surface, seat, state, modifiers, serial); KeyboardTarget::modifiers(surface, seat, state, modifiers, serial);
} }
_ => unreachable!(),
} }
} }
} }
@ -663,12 +458,18 @@ impl State {
self.space self.space
.elements() .elements()
.find(|window| window.wl_surface().map(|s| s == *surface).unwrap_or(false)) .find(|window| window.wl_surface().map(|s| s == *surface).unwrap_or(false))
.cloned()
.or_else(|| { .or_else(|| {
self.windows self.windows
.iter() .iter()
.find(|&win| win.wl_surface().is_some_and(|surf| &surf == surface)) .find(|&win| win.wl_surface().is_some_and(|surf| &surf == surface))
.cloned()
}) })
.cloned()
}
pub fn new_window_for_surface(&self, surface: &WlSurface) -> Option<WindowElement> {
self.new_windows
.iter()
.find(|&win| win.wl_surface().is_some_and(|surf| &surf == surface))
.cloned()
} }
} }

View file

@ -3,7 +3,7 @@
use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::atomic::{AtomicU32, Ordering};
use smithay::{ use smithay::{
desktop::space::SpaceElement, desktop::{space::SpaceElement, WindowSurface},
reexports::wayland_protocols::xdg::shell::server::xdg_toplevel, reexports::wayland_protocols::xdg::shell::server::xdg_toplevel,
utils::{Logical, Point, Rectangle}, utils::{Logical, Point, Rectangle},
}; };
@ -81,30 +81,27 @@ impl WindowElement {
state.fullscreen_or_maximized = FullscreenOrMaximized::Fullscreen; state.fullscreen_or_maximized = FullscreenOrMaximized::Fullscreen;
}); });
match self { match self.underlying_surface() {
WindowElement::Wayland(window) => { WindowSurface::Wayland(toplevel) => {
window toplevel.with_pending_state(|state| {
.toplevel() state.states.unset(xdg_toplevel::State::Maximized);
.expect("in wayland enum") state.states.set(xdg_toplevel::State::Fullscreen);
.with_pending_state(|state| { state.states.set(xdg_toplevel::State::TiledTop);
state.states.unset(xdg_toplevel::State::Maximized); state.states.set(xdg_toplevel::State::TiledLeft);
state.states.set(xdg_toplevel::State::Fullscreen); state.states.set(xdg_toplevel::State::TiledBottom);
state.states.set(xdg_toplevel::State::TiledTop); state.states.set(xdg_toplevel::State::TiledRight);
state.states.set(xdg_toplevel::State::TiledLeft); });
state.states.set(xdg_toplevel::State::TiledBottom);
state.states.set(xdg_toplevel::State::TiledRight);
});
} }
WindowElement::X11(surface) => { WindowSurface::X11(surface) => {
surface if !surface.is_override_redirect() {
.set_maximized(false) surface
.expect("failed to set x11 win to maximized"); .set_maximized(false)
surface .expect("failed to set x11 win to maximized");
.set_fullscreen(true) surface
.expect("failed to set x11 win to not fullscreen"); .set_fullscreen(true)
.expect("failed to set x11 win to not fullscreen");
}
} }
WindowElement::X11OverrideRedirect(_) => (),
_ => unreachable!(),
} }
} }
FullscreenOrMaximized::Fullscreen => { FullscreenOrMaximized::Fullscreen => {
@ -131,30 +128,27 @@ impl WindowElement {
state.fullscreen_or_maximized = FullscreenOrMaximized::Maximized; state.fullscreen_or_maximized = FullscreenOrMaximized::Maximized;
}); });
match self { match self.underlying_surface() {
WindowElement::Wayland(window) => { WindowSurface::Wayland(toplevel) => {
window toplevel.with_pending_state(|state| {
.toplevel() state.states.set(xdg_toplevel::State::Maximized);
.expect("in wayland enum") state.states.unset(xdg_toplevel::State::Fullscreen);
.with_pending_state(|state| { state.states.set(xdg_toplevel::State::TiledTop);
state.states.set(xdg_toplevel::State::Maximized); state.states.set(xdg_toplevel::State::TiledLeft);
state.states.unset(xdg_toplevel::State::Fullscreen); state.states.set(xdg_toplevel::State::TiledBottom);
state.states.set(xdg_toplevel::State::TiledTop); state.states.set(xdg_toplevel::State::TiledRight);
state.states.set(xdg_toplevel::State::TiledLeft); });
state.states.set(xdg_toplevel::State::TiledBottom);
state.states.set(xdg_toplevel::State::TiledRight);
});
} }
WindowElement::X11(surface) => { WindowSurface::X11(surface) => {
surface if !surface.is_override_redirect() {
.set_maximized(true) surface
.expect("failed to set x11 win to maximized"); .set_maximized(true)
surface .expect("failed to set x11 win to maximized");
.set_fullscreen(false) surface
.expect("failed to set x11 win to not fullscreen"); .set_fullscreen(false)
.expect("failed to set x11 win to not fullscreen");
}
} }
WindowElement::X11OverrideRedirect(_) => (),
_ => unreachable!(),
} }
} }
FullscreenOrMaximized::Maximized => { FullscreenOrMaximized::Maximized => {
@ -176,60 +170,54 @@ impl WindowElement {
/// Unsets maximized and fullscreen states for both wayland and xwayland windows /// Unsets maximized and fullscreen states for both wayland and xwayland windows
/// and unsets tiled states for wayland windows. /// and unsets tiled states for wayland windows.
fn set_floating_states(&self) { fn set_floating_states(&self) {
match self { match self.underlying_surface() {
WindowElement::Wayland(window) => { WindowSurface::Wayland(toplevel) => {
window toplevel.with_pending_state(|state| {
.toplevel() state.states.unset(xdg_toplevel::State::Maximized);
.expect("in wayland enum") state.states.unset(xdg_toplevel::State::Fullscreen);
.with_pending_state(|state| { state.states.unset(xdg_toplevel::State::TiledTop);
state.states.unset(xdg_toplevel::State::Maximized); state.states.unset(xdg_toplevel::State::TiledLeft);
state.states.unset(xdg_toplevel::State::Fullscreen); state.states.unset(xdg_toplevel::State::TiledBottom);
state.states.unset(xdg_toplevel::State::TiledTop); state.states.unset(xdg_toplevel::State::TiledRight);
state.states.unset(xdg_toplevel::State::TiledLeft); });
state.states.unset(xdg_toplevel::State::TiledBottom);
state.states.unset(xdg_toplevel::State::TiledRight);
});
} }
WindowElement::X11(surface) => { WindowSurface::X11(surface) => {
surface if !surface.is_override_redirect() {
.set_maximized(false) surface
.expect("failed to set x11 win to maximized"); .set_maximized(false)
surface .expect("failed to set x11 win to maximized");
.set_fullscreen(false) surface
.expect("failed to set x11 win to not fullscreen"); .set_fullscreen(false)
.expect("failed to set x11 win to not fullscreen");
}
} }
WindowElement::X11OverrideRedirect(_) => (),
_ => unreachable!(),
} }
} }
/// Unsets maximized and fullscreen states for both wayland and xwayland windows /// Unsets maximized and fullscreen states for both wayland and xwayland windows
/// and sets tiled states for wayland windows. /// and sets tiled states for wayland windows.
fn set_tiled_states(&self) { fn set_tiled_states(&self) {
match self { match self.underlying_surface() {
WindowElement::Wayland(window) => { WindowSurface::Wayland(toplevel) => {
window toplevel.with_pending_state(|state| {
.toplevel() state.states.unset(xdg_toplevel::State::Maximized);
.expect("in wayland enum") state.states.unset(xdg_toplevel::State::Fullscreen);
.with_pending_state(|state| { state.states.set(xdg_toplevel::State::TiledTop);
state.states.unset(xdg_toplevel::State::Maximized); state.states.set(xdg_toplevel::State::TiledLeft);
state.states.unset(xdg_toplevel::State::Fullscreen); state.states.set(xdg_toplevel::State::TiledBottom);
state.states.set(xdg_toplevel::State::TiledTop); state.states.set(xdg_toplevel::State::TiledRight);
state.states.set(xdg_toplevel::State::TiledLeft); });
state.states.set(xdg_toplevel::State::TiledBottom);
state.states.set(xdg_toplevel::State::TiledRight);
});
} }
WindowElement::X11(surface) => { WindowSurface::X11(surface) => {
surface if !surface.is_override_redirect() {
.set_maximized(false) surface
.expect("failed to set x11 win to maximized"); .set_maximized(false)
surface .expect("failed to set x11 win to maximized");
.set_fullscreen(false) surface
.expect("failed to set x11 win to not fullscreen"); .set_fullscreen(false)
.expect("failed to set x11 win to not fullscreen");
}
} }
WindowElement::X11OverrideRedirect(_) => (),
_ => unreachable!(),
} }
} }
} }