shell/tiling: semi-working stacking
This commit is contained in:
parent
fc7dd3398a
commit
b3401eb18a
7 changed files with 251 additions and 12 deletions
|
|
@ -6,6 +6,7 @@ use crate::{
|
|||
state::State,
|
||||
utils::prelude::SeatExt,
|
||||
};
|
||||
use calloop::LoopHandle;
|
||||
use id_tree::NodeId;
|
||||
use smithay::{
|
||||
backend::{
|
||||
|
|
@ -228,8 +229,7 @@ impl CosmicMapped {
|
|||
|
||||
pub fn handle_focus(&self, direction: FocusDirection) -> bool {
|
||||
if let CosmicMappedInternal::Stack(stack) = &self.element {
|
||||
//TODO: stack.handle_focus(direction)
|
||||
false
|
||||
stack.handle_focus(direction)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
|
@ -458,6 +458,62 @@ impl CosmicMapped {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn convert_to_stack<'a>(
|
||||
&mut self,
|
||||
outputs: impl Iterator<Item = (&'a Output, Rectangle<i32, Logical>)>,
|
||||
) {
|
||||
match &self.element {
|
||||
CosmicMappedInternal::Window(window) => {
|
||||
let surface = window.surface();
|
||||
let activated = surface.is_activated();
|
||||
let handle = window.loop_handle();
|
||||
|
||||
let stack = CosmicStack::new(std::iter::once(surface), handle);
|
||||
if let Some(geo) = self.last_geometry.lock().unwrap().clone() {
|
||||
stack.set_geometry(geo);
|
||||
}
|
||||
for (output, overlap) in outputs {
|
||||
stack.output_enter(output, overlap);
|
||||
}
|
||||
stack.set_activate(activated);
|
||||
stack.active().send_configure();
|
||||
stack.refresh();
|
||||
|
||||
self.element = CosmicMappedInternal::Stack(stack);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_to_surface<'a>(
|
||||
&mut self,
|
||||
surface: CosmicSurface,
|
||||
outputs: impl Iterator<Item = (&'a Output, Rectangle<i32, Logical>)>,
|
||||
) {
|
||||
let handle = self.loop_handle();
|
||||
let window = CosmicWindow::new(surface, handle);
|
||||
|
||||
if let Some(geo) = self.last_geometry.lock().unwrap().clone() {
|
||||
window.set_geometry(geo);
|
||||
}
|
||||
for (output, overlap) in outputs {
|
||||
window.output_enter(output, overlap);
|
||||
}
|
||||
window.set_activate(self.is_activated());
|
||||
window.surface().send_configure();
|
||||
window.refresh();
|
||||
|
||||
self.element = CosmicMappedInternal::Window(window);
|
||||
}
|
||||
|
||||
pub(super) fn loop_handle(&self) -> LoopHandle<'static, crate::state::Data> {
|
||||
match &self.element {
|
||||
CosmicMappedInternal::Stack(stack) => stack.loop_handle(),
|
||||
CosmicMappedInternal::Window(window) => window.loop_handle(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
pub fn set_debug(&self, flag: bool) {
|
||||
let mut debug = self.debug.lock().unwrap();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::{
|
||||
shell::focus::FocusDirection,
|
||||
state::State,
|
||||
utils::iced::{IcedElement, Program},
|
||||
utils::prelude::SeatExt,
|
||||
|
|
@ -126,6 +127,10 @@ impl CosmicStack {
|
|||
pub fn remove_window(&self, window: &CosmicSurface) {
|
||||
self.0.with_program(|p| {
|
||||
let mut windows = p.windows.lock().unwrap();
|
||||
if windows.len() == 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(idx) = windows.iter().position(|w| w == window) else { return };
|
||||
windows.remove(idx);
|
||||
p.active.fetch_min(windows.len() - 1, Ordering::SeqCst);
|
||||
|
|
@ -135,11 +140,14 @@ impl CosmicStack {
|
|||
pub fn remove_idx(&self, idx: usize) {
|
||||
self.0.with_program(|p| {
|
||||
let mut windows = p.windows.lock().unwrap();
|
||||
if windows.len() == 1 {
|
||||
return;
|
||||
}
|
||||
if windows.len() >= idx {
|
||||
return;
|
||||
}
|
||||
windows.remove(idx);
|
||||
p.active.fetch_min(windows.len(), Ordering::SeqCst);
|
||||
p.active.fetch_min(windows.len() - 1, Ordering::SeqCst);
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -147,6 +155,32 @@ impl CosmicStack {
|
|||
self.0.with_program(|p| p.windows.lock().unwrap().len())
|
||||
}
|
||||
|
||||
pub fn handle_focus(&self, direction: FocusDirection) -> bool {
|
||||
self.0.with_program(|p| {
|
||||
match direction {
|
||||
FocusDirection::Left => p
|
||||
.active
|
||||
.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |val| val.checked_sub(1))
|
||||
.is_ok(),
|
||||
FocusDirection::Right => {
|
||||
let max = p.windows.lock().unwrap().len();
|
||||
p.active
|
||||
.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |val| {
|
||||
if val < max - 1 {
|
||||
Some(val + 1)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.is_ok()
|
||||
}
|
||||
FocusDirection::Out => false, //TODO
|
||||
FocusDirection::In => false, //TODO
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn active(&self) -> CosmicSurface {
|
||||
self.0
|
||||
.with_program(|p| p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)].clone())
|
||||
|
|
@ -267,6 +301,10 @@ impl CosmicStack {
|
|||
active
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn loop_handle(&self) -> LoopHandle<'static, crate::state::Data> {
|
||||
self.0.loop_handle()
|
||||
}
|
||||
}
|
||||
|
||||
impl Program for CosmicStackInternal {
|
||||
|
|
@ -396,12 +434,19 @@ impl SpaceElement for CosmicStack {
|
|||
fn refresh(&self) {
|
||||
self.0.with_program(|p| {
|
||||
let mut windows = p.windows.lock().unwrap();
|
||||
windows.retain(IsAlive::alive); // TODO: We don't handle empty stacks properly
|
||||
|
||||
// don't let the stack become empty
|
||||
let active = windows[p.active.load(Ordering::SeqCst)].clone();
|
||||
windows.retain(IsAlive::alive);
|
||||
if windows.is_empty() {
|
||||
windows.push(active);
|
||||
}
|
||||
|
||||
let len = windows.len();
|
||||
let _ = p
|
||||
.active
|
||||
.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |active| {
|
||||
(active > len).then_some(len - 1)
|
||||
(active >= len).then_some(len - 1)
|
||||
});
|
||||
windows.iter().for_each(|w| SpaceElement::refresh(w))
|
||||
})
|
||||
|
|
@ -490,11 +535,9 @@ impl PointerTarget<State> for CosmicStack {
|
|||
|
||||
if event.location.y < TAB_HEIGHT as f64 {
|
||||
let focus = p.swap_focus(Focus::Header);
|
||||
assert_eq!(focus, Focus::None);
|
||||
true
|
||||
} else {
|
||||
let focus = p.swap_focus(Focus::Window);
|
||||
assert_eq!(focus, Focus::None);
|
||||
|
||||
*p.last_location.lock().unwrap() = Some((event.location, event.serial, event.time));
|
||||
let active = p.active.load(Ordering::SeqCst);
|
||||
|
|
|
|||
|
|
@ -165,6 +165,10 @@ impl CosmicWindow {
|
|||
Point::from((0, 0))
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn loop_handle(&self) -> LoopHandle<'static, crate::state::Data> {
|
||||
self.0.loop_handle()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue