2023-06-25 17:18:50 -05:00
|
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
2023-06-25 17:49:06 -05:00
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
2023-06-25 17:18:50 -05:00
|
|
|
|
2023-07-16 20:44:18 -05:00
|
|
|
use std::sync::atomic::AtomicU32;
|
|
|
|
|
2023-06-18 19:30:52 -05:00
|
|
|
use smithay::{
|
2023-07-12 18:50:41 -05:00
|
|
|
desktop::Window,
|
|
|
|
reexports::{
|
|
|
|
wayland_protocols::xdg::shell::server::xdg_toplevel,
|
|
|
|
wayland_server::protocol::wl_surface::WlSurface,
|
|
|
|
},
|
2023-07-16 20:44:18 -05:00
|
|
|
wayland::{
|
|
|
|
compositor::{Blocker, BlockerState},
|
|
|
|
seat::WaylandFocus,
|
|
|
|
},
|
2023-06-18 19:30:52 -05:00
|
|
|
};
|
2023-05-28 19:14:30 -05:00
|
|
|
|
2023-07-10 17:14:37 -05:00
|
|
|
use crate::{
|
|
|
|
backend::Backend,
|
|
|
|
state::{State, WithState},
|
|
|
|
};
|
2023-05-28 19:14:30 -05:00
|
|
|
|
2023-07-18 15:12:23 -05:00
|
|
|
use self::window_state::Float;
|
2023-05-28 19:14:30 -05:00
|
|
|
|
|
|
|
pub mod window_state;
|
|
|
|
|
2023-06-21 21:49:20 -05:00
|
|
|
impl<B: Backend> State<B> {
|
|
|
|
/// Returns the [Window] associated with a given [WlSurface].
|
|
|
|
pub fn window_for_surface(&self, surface: &WlSurface) -> Option<Window> {
|
|
|
|
self.space
|
|
|
|
.elements()
|
|
|
|
.find(|window| window.wl_surface().map(|s| s == *surface).unwrap_or(false))
|
|
|
|
.cloned()
|
2023-06-30 21:34:07 -05:00
|
|
|
.or_else(|| {
|
|
|
|
self.windows
|
|
|
|
.iter()
|
|
|
|
.find(|&win| win.toplevel().wl_surface() == surface)
|
|
|
|
.cloned()
|
|
|
|
})
|
2023-06-21 21:49:20 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-23 15:43:40 -05:00
|
|
|
/// Toggle a window's floating status.
|
2023-06-18 19:30:52 -05:00
|
|
|
pub fn toggle_floating<B: Backend>(state: &mut State<B>, window: &Window) {
|
2023-07-10 17:14:37 -05:00
|
|
|
window.with_state(|window_state| {
|
2023-05-28 19:14:30 -05:00
|
|
|
match window_state.floating {
|
2023-06-18 19:30:52 -05:00
|
|
|
Float::Tiled(prev_loc_and_size) => {
|
2023-05-28 19:14:30 -05:00
|
|
|
if let Some((prev_loc, prev_size)) = prev_loc_and_size {
|
|
|
|
window.toplevel().with_pending_state(|state| {
|
|
|
|
state.size = Some(prev_size);
|
|
|
|
});
|
|
|
|
|
|
|
|
window.toplevel().send_pending_configure();
|
|
|
|
|
2023-07-12 18:50:41 -05:00
|
|
|
state.space.map_element(window.clone(), prev_loc, false);
|
|
|
|
// TODO: should it activate?
|
2023-05-28 19:14:30 -05:00
|
|
|
}
|
|
|
|
|
2023-06-18 19:30:52 -05:00
|
|
|
window_state.floating = Float::Floating;
|
2023-07-12 18:50:41 -05:00
|
|
|
window.toplevel().with_pending_state(|tl_state| {
|
|
|
|
tl_state.states.unset(xdg_toplevel::State::TiledTop);
|
|
|
|
tl_state.states.unset(xdg_toplevel::State::TiledBottom);
|
|
|
|
tl_state.states.unset(xdg_toplevel::State::TiledLeft);
|
|
|
|
tl_state.states.unset(xdg_toplevel::State::TiledRight);
|
|
|
|
});
|
2023-05-28 19:14:30 -05:00
|
|
|
}
|
|
|
|
Float::Floating => {
|
2023-06-18 19:30:52 -05:00
|
|
|
window_state.floating = Float::Tiled(Some((
|
2023-06-19 12:42:49 -05:00
|
|
|
// We get the location this way because window.geometry().loc
|
|
|
|
// doesn't seem to be the actual location
|
|
|
|
state.space.element_location(window).unwrap(),
|
2023-05-28 19:14:30 -05:00
|
|
|
window.geometry().size,
|
|
|
|
)));
|
2023-07-12 18:50:41 -05:00
|
|
|
window.toplevel().with_pending_state(|tl_state| {
|
|
|
|
tl_state.states.set(xdg_toplevel::State::TiledTop);
|
|
|
|
tl_state.states.set(xdg_toplevel::State::TiledBottom);
|
|
|
|
tl_state.states.set(xdg_toplevel::State::TiledLeft);
|
|
|
|
tl_state.states.set(xdg_toplevel::State::TiledRight);
|
|
|
|
});
|
2023-05-28 19:14:30 -05:00
|
|
|
}
|
|
|
|
}
|
2023-06-18 19:30:52 -05:00
|
|
|
});
|
|
|
|
|
2023-07-11 16:10:31 -05:00
|
|
|
let output = state.focus_state.focused_output.clone().unwrap();
|
|
|
|
state.re_layout(&output);
|
2023-07-09 17:48:46 -05:00
|
|
|
|
2023-07-10 17:14:37 -05:00
|
|
|
let render = output.with_state(|op_state| {
|
2023-07-09 21:04:26 -05:00
|
|
|
state
|
|
|
|
.windows
|
|
|
|
.iter()
|
|
|
|
.cloned()
|
|
|
|
.filter(|win| {
|
2023-07-10 17:14:37 -05:00
|
|
|
win.with_state(|win_state| {
|
2023-07-09 21:04:26 -05:00
|
|
|
if win_state.floating.is_floating() {
|
|
|
|
return true;
|
|
|
|
}
|
2023-07-11 16:10:31 -05:00
|
|
|
for tag in win_state.tags.iter() {
|
|
|
|
if op_state.focused_tags().any(|tg| tg == tag) {
|
2023-07-09 21:04:26 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
false
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
});
|
|
|
|
|
|
|
|
let clone = window.clone();
|
2023-07-16 20:44:18 -05:00
|
|
|
state.loop_handle.insert_idle(move |data| {
|
|
|
|
crate::state::schedule_on_commit(data, render, move |dt| {
|
|
|
|
dt.state.space.raise_element(&clone, true);
|
|
|
|
});
|
2023-07-09 17:48:46 -05:00
|
|
|
});
|
2023-05-28 19:14:30 -05:00
|
|
|
}
|
2023-06-26 18:48:29 -05:00
|
|
|
|
2023-07-16 20:44:18 -05:00
|
|
|
pub struct WindowBlocker;
|
|
|
|
pub static BLOCKER_COUNTER: AtomicU32 = AtomicU32::new(0);
|
|
|
|
|
|
|
|
impl Blocker for WindowBlocker {
|
|
|
|
fn state(&self) -> BlockerState {
|
|
|
|
if BLOCKER_COUNTER.load(std::sync::atomic::Ordering::SeqCst) > 0 {
|
|
|
|
BlockerState::Pending
|
|
|
|
} else {
|
|
|
|
BlockerState::Released
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|