shell/tiling: Implement window swap mode
This commit is contained in:
parent
ac4bf01315
commit
1251b7e9f7
18 changed files with 1305 additions and 197 deletions
|
|
@ -62,6 +62,7 @@ pub mod window;
|
|||
pub use self::window::CosmicWindow;
|
||||
pub mod resize_indicator;
|
||||
pub mod stack_hover;
|
||||
pub mod swap_indicator;
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
use egui::plot::{Corner, Legend, Plot, PlotPoints, Polygon};
|
||||
|
|
@ -72,7 +73,10 @@ use tracing::debug;
|
|||
|
||||
use super::{
|
||||
focus::FocusDirection,
|
||||
layout::{floating::ResizeState, tiling::Direction},
|
||||
layout::{
|
||||
floating::ResizeState,
|
||||
tiling::{Direction, NodeDesc},
|
||||
},
|
||||
};
|
||||
|
||||
space_elements! {
|
||||
|
|
@ -90,7 +94,7 @@ pub struct CosmicMapped {
|
|||
last_cursor_position: Arc<Mutex<HashMap<usize, Point<f64, Logical>>>>,
|
||||
|
||||
//tiling
|
||||
pub(super) tiling_node_id: Arc<Mutex<Option<NodeId>>>,
|
||||
pub tiling_node_id: Arc<Mutex<Option<NodeId>>>,
|
||||
//floating
|
||||
pub(super) last_geometry: Arc<Mutex<Option<Rectangle<i32, Logical>>>>,
|
||||
pub(super) resize_state: Arc<Mutex<Option<ResizeState>>>,
|
||||
|
|
@ -167,14 +171,12 @@ impl CosmicMapped {
|
|||
CosmicMappedInternal::Stack(stack) => {
|
||||
let win = stack.active();
|
||||
let location = stack.offset();
|
||||
let mut size = win.geometry().size;
|
||||
size -= location.to_size();
|
||||
let size = win.geometry().size;
|
||||
Rectangle::from_loc_and_size(location, size)
|
||||
}
|
||||
CosmicMappedInternal::Window(win) => {
|
||||
let location = win.offset();
|
||||
let mut size = win.geometry().size;
|
||||
size -= location.to_size();
|
||||
let size = win.geometry().size;
|
||||
Rectangle::from_loc_and_size(location, size)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
|
|
@ -248,9 +250,9 @@ impl CosmicMapped {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn handle_focus(&self, direction: FocusDirection) -> bool {
|
||||
pub fn handle_focus(&self, direction: FocusDirection, swap: Option<NodeDesc>) -> bool {
|
||||
if let CosmicMappedInternal::Stack(stack) = &self.element {
|
||||
stack.handle_focus(direction)
|
||||
stack.handle_focus(direction, swap)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
|
@ -1100,9 +1102,13 @@ where
|
|||
RescaleRenderElement<CropRenderElement<self::window::CosmicWindowRenderElement<R>>>,
|
||||
>,
|
||||
),
|
||||
TiledOverlay(
|
||||
RelocateRenderElement<RescaleRenderElement<CropRenderElement<PixelShaderElement>>>,
|
||||
),
|
||||
GrabbedStack(RescaleRenderElement<self::stack::CosmicStackRenderElement<R>>),
|
||||
GrabbedWindow(RescaleRenderElement<self::window::CosmicWindowRenderElement<R>>),
|
||||
FocusIndicator(PixelShaderElement),
|
||||
Overlay(PixelShaderElement),
|
||||
StackHoverIndicator(MemoryRenderBufferRenderElement<R>),
|
||||
#[cfg(feature = "debug")]
|
||||
Egui(TextureRenderElement<GlesTexture>),
|
||||
|
|
@ -1119,9 +1125,11 @@ where
|
|||
CosmicMappedRenderElement::Window(elem) => elem.id(),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.id(),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.id(),
|
||||
CosmicMappedRenderElement::TiledOverlay(elem) => elem.id(),
|
||||
CosmicMappedRenderElement::GrabbedStack(elem) => elem.id(),
|
||||
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.id(),
|
||||
CosmicMappedRenderElement::FocusIndicator(elem) => elem.id(),
|
||||
CosmicMappedRenderElement::Overlay(elem) => elem.id(),
|
||||
CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.id(),
|
||||
#[cfg(feature = "debug")]
|
||||
CosmicMappedRenderElement::Egui(elem) => elem.id(),
|
||||
|
|
@ -1134,9 +1142,11 @@ where
|
|||
CosmicMappedRenderElement::Window(elem) => elem.current_commit(),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.current_commit(),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.current_commit(),
|
||||
CosmicMappedRenderElement::TiledOverlay(elem) => elem.current_commit(),
|
||||
CosmicMappedRenderElement::GrabbedStack(elem) => elem.current_commit(),
|
||||
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.current_commit(),
|
||||
CosmicMappedRenderElement::FocusIndicator(elem) => elem.current_commit(),
|
||||
CosmicMappedRenderElement::Overlay(elem) => elem.current_commit(),
|
||||
CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.current_commit(),
|
||||
#[cfg(feature = "debug")]
|
||||
CosmicMappedRenderElement::Egui(elem) => elem.current_commit(),
|
||||
|
|
@ -1149,9 +1159,11 @@ where
|
|||
CosmicMappedRenderElement::Window(elem) => elem.src(),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.src(),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.src(),
|
||||
CosmicMappedRenderElement::TiledOverlay(elem) => elem.src(),
|
||||
CosmicMappedRenderElement::GrabbedStack(elem) => elem.src(),
|
||||
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.src(),
|
||||
CosmicMappedRenderElement::FocusIndicator(elem) => elem.src(),
|
||||
CosmicMappedRenderElement::Overlay(elem) => elem.src(),
|
||||
CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.src(),
|
||||
#[cfg(feature = "debug")]
|
||||
CosmicMappedRenderElement::Egui(elem) => elem.src(),
|
||||
|
|
@ -1164,9 +1176,11 @@ where
|
|||
CosmicMappedRenderElement::Window(elem) => elem.geometry(scale),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.geometry(scale),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.geometry(scale),
|
||||
CosmicMappedRenderElement::TiledOverlay(elem) => elem.geometry(scale),
|
||||
CosmicMappedRenderElement::GrabbedStack(elem) => elem.geometry(scale),
|
||||
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.geometry(scale),
|
||||
CosmicMappedRenderElement::FocusIndicator(elem) => elem.geometry(scale),
|
||||
CosmicMappedRenderElement::Overlay(elem) => elem.geometry(scale),
|
||||
CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.geometry(scale),
|
||||
#[cfg(feature = "debug")]
|
||||
CosmicMappedRenderElement::Egui(elem) => elem.geometry(scale),
|
||||
|
|
@ -1179,9 +1193,11 @@ where
|
|||
CosmicMappedRenderElement::Window(elem) => elem.location(scale),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.location(scale),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.location(scale),
|
||||
CosmicMappedRenderElement::TiledOverlay(elem) => elem.location(scale),
|
||||
CosmicMappedRenderElement::GrabbedStack(elem) => elem.location(scale),
|
||||
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.location(scale),
|
||||
CosmicMappedRenderElement::FocusIndicator(elem) => elem.location(scale),
|
||||
CosmicMappedRenderElement::Overlay(elem) => elem.location(scale),
|
||||
CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.location(scale),
|
||||
#[cfg(feature = "debug")]
|
||||
CosmicMappedRenderElement::Egui(elem) => elem.location(scale),
|
||||
|
|
@ -1194,9 +1210,11 @@ where
|
|||
CosmicMappedRenderElement::Window(elem) => elem.transform(),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.transform(),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.transform(),
|
||||
CosmicMappedRenderElement::TiledOverlay(elem) => elem.transform(),
|
||||
CosmicMappedRenderElement::GrabbedStack(elem) => elem.transform(),
|
||||
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.transform(),
|
||||
CosmicMappedRenderElement::FocusIndicator(elem) => elem.transform(),
|
||||
CosmicMappedRenderElement::Overlay(elem) => elem.transform(),
|
||||
CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.transform(),
|
||||
#[cfg(feature = "debug")]
|
||||
CosmicMappedRenderElement::Egui(elem) => elem.transform(),
|
||||
|
|
@ -1213,9 +1231,11 @@ where
|
|||
CosmicMappedRenderElement::Window(elem) => elem.damage_since(scale, commit),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.damage_since(scale, commit),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.damage_since(scale, commit),
|
||||
CosmicMappedRenderElement::TiledOverlay(elem) => elem.damage_since(scale, commit),
|
||||
CosmicMappedRenderElement::GrabbedStack(elem) => elem.damage_since(scale, commit),
|
||||
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.damage_since(scale, commit),
|
||||
CosmicMappedRenderElement::FocusIndicator(elem) => elem.damage_since(scale, commit),
|
||||
CosmicMappedRenderElement::Overlay(elem) => elem.damage_since(scale, commit),
|
||||
CosmicMappedRenderElement::StackHoverIndicator(elem) => {
|
||||
elem.damage_since(scale, commit)
|
||||
}
|
||||
|
|
@ -1230,9 +1250,11 @@ where
|
|||
CosmicMappedRenderElement::Window(elem) => elem.opaque_regions(scale),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.opaque_regions(scale),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.opaque_regions(scale),
|
||||
CosmicMappedRenderElement::TiledOverlay(elem) => elem.opaque_regions(scale),
|
||||
CosmicMappedRenderElement::GrabbedStack(elem) => elem.opaque_regions(scale),
|
||||
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.opaque_regions(scale),
|
||||
CosmicMappedRenderElement::FocusIndicator(elem) => elem.opaque_regions(scale),
|
||||
CosmicMappedRenderElement::Overlay(elem) => elem.opaque_regions(scale),
|
||||
CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.opaque_regions(scale),
|
||||
#[cfg(feature = "debug")]
|
||||
CosmicMappedRenderElement::Egui(elem) => elem.opaque_regions(scale),
|
||||
|
|
@ -1245,9 +1267,11 @@ where
|
|||
CosmicMappedRenderElement::Window(elem) => elem.alpha(),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.alpha(),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.alpha(),
|
||||
CosmicMappedRenderElement::TiledOverlay(elem) => elem.alpha(),
|
||||
CosmicMappedRenderElement::GrabbedStack(elem) => elem.alpha(),
|
||||
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.alpha(),
|
||||
CosmicMappedRenderElement::FocusIndicator(elem) => elem.alpha(),
|
||||
CosmicMappedRenderElement::Overlay(elem) => elem.alpha(),
|
||||
CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.alpha(),
|
||||
#[cfg(feature = "debug")]
|
||||
CosmicMappedRenderElement::Egui(elem) => elem.alpha(),
|
||||
|
|
@ -1268,11 +1292,17 @@ impl RenderElement<GlowRenderer> for CosmicMappedRenderElement<GlowRenderer> {
|
|||
CosmicMappedRenderElement::Window(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::TiledOverlay(elem) => {
|
||||
RenderElement::<GlowRenderer>::draw(elem, frame, src, dst, damage)
|
||||
}
|
||||
CosmicMappedRenderElement::GrabbedStack(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::FocusIndicator(elem) => {
|
||||
RenderElement::<GlowRenderer>::draw(elem, frame, src, dst, damage)
|
||||
}
|
||||
CosmicMappedRenderElement::Overlay(elem) => {
|
||||
RenderElement::<GlowRenderer>::draw(elem, frame, src, dst, damage)
|
||||
}
|
||||
CosmicMappedRenderElement::StackHoverIndicator(elem) => {
|
||||
RenderElement::<GlowRenderer>::draw(elem, frame, src, dst, damage)
|
||||
}
|
||||
|
|
@ -1289,9 +1319,11 @@ impl RenderElement<GlowRenderer> for CosmicMappedRenderElement<GlowRenderer> {
|
|||
CosmicMappedRenderElement::Window(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::TiledOverlay(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::GrabbedStack(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::FocusIndicator(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::Overlay(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::StackHoverIndicator(elem) => {
|
||||
elem.underlying_storage(renderer)
|
||||
}
|
||||
|
|
@ -1316,12 +1348,20 @@ impl<'a, 'b> RenderElement<GlMultiRenderer<'a, 'b>>
|
|||
CosmicMappedRenderElement::Window(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::TiledOverlay(elem) => {
|
||||
RenderElement::<GlowRenderer>::draw(elem, frame.glow_frame_mut(), src, dst, damage)
|
||||
.map_err(|err| GlMultiError::Render(err))
|
||||
}
|
||||
CosmicMappedRenderElement::GrabbedStack(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.draw(frame, src, dst, damage),
|
||||
CosmicMappedRenderElement::FocusIndicator(elem) => {
|
||||
RenderElement::<GlowRenderer>::draw(elem, frame.glow_frame_mut(), src, dst, damage)
|
||||
.map_err(|err| GlMultiError::Render(err))
|
||||
}
|
||||
CosmicMappedRenderElement::Overlay(elem) => {
|
||||
RenderElement::<GlowRenderer>::draw(elem, frame.glow_frame_mut(), src, dst, damage)
|
||||
.map_err(|err| GlMultiError::Render(err))
|
||||
}
|
||||
CosmicMappedRenderElement::StackHoverIndicator(elem) => {
|
||||
elem.draw(frame, src, dst, damage)
|
||||
}
|
||||
|
|
@ -1343,11 +1383,17 @@ impl<'a, 'b> RenderElement<GlMultiRenderer<'a, 'b>>
|
|||
CosmicMappedRenderElement::Window(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::TiledStack(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::TiledWindow(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::TiledOverlay(elem) => {
|
||||
elem.underlying_storage(renderer.glow_renderer_mut())
|
||||
}
|
||||
CosmicMappedRenderElement::GrabbedStack(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.underlying_storage(renderer),
|
||||
CosmicMappedRenderElement::FocusIndicator(elem) => {
|
||||
elem.underlying_storage(renderer.glow_renderer_mut())
|
||||
}
|
||||
CosmicMappedRenderElement::Overlay(elem) => {
|
||||
elem.underlying_storage(renderer.glow_renderer_mut())
|
||||
}
|
||||
CosmicMappedRenderElement::StackHoverIndicator(elem) => {
|
||||
elem.underlying_storage(renderer)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
use super::{CosmicMapped, CosmicSurface, CosmicWindow};
|
||||
use crate::{
|
||||
shell::{focus::FocusDirection, grabs::MoveGrab, layout::tiling::Direction, Shell, Trigger},
|
||||
shell::{
|
||||
focus::FocusDirection,
|
||||
grabs::MoveGrab,
|
||||
layout::tiling::{Direction, NodeDesc},
|
||||
Shell, Trigger,
|
||||
},
|
||||
state::State,
|
||||
utils::iced::{IcedElement, Program},
|
||||
utils::prelude::SeatExt,
|
||||
|
|
@ -85,6 +90,7 @@ pub struct CosmicStackInternal {
|
|||
previous_keyboard: Arc<AtomicUsize>,
|
||||
pointer_entered: Arc<AtomicU8>,
|
||||
previous_pointer: Arc<AtomicUsize>,
|
||||
reenter: Arc<AtomicBool>,
|
||||
potential_drag: Arc<Mutex<Option<usize>>>,
|
||||
override_alive: Arc<AtomicBool>,
|
||||
last_seat: Arc<Mutex<Option<(Seat<State>, Serial)>>>,
|
||||
|
|
@ -107,7 +113,7 @@ impl CosmicStackInternal {
|
|||
}
|
||||
}
|
||||
|
||||
const TAB_HEIGHT: i32 = 24;
|
||||
pub const TAB_HEIGHT: i32 = 24;
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
|
@ -148,6 +154,7 @@ impl CosmicStack {
|
|||
previous_keyboard: Arc::new(AtomicUsize::new(0)),
|
||||
pointer_entered: Arc::new(AtomicU8::new(Focus::None as u8)),
|
||||
previous_pointer: Arc::new(AtomicUsize::new(0)),
|
||||
reenter: Arc::new(AtomicBool::new(false)),
|
||||
potential_drag: Arc::new(Mutex::new(None)),
|
||||
override_alive: Arc::new(AtomicBool::new(true)),
|
||||
last_seat: Arc::new(Mutex::new(None)),
|
||||
|
|
@ -198,6 +205,9 @@ impl CosmicStack {
|
|||
let Some(idx) = windows.iter().position(|w| w == window) else {
|
||||
return;
|
||||
};
|
||||
if idx == p.active.load(Ordering::SeqCst) {
|
||||
p.reenter.store(true, Ordering::SeqCst);
|
||||
}
|
||||
let window = windows.remove(idx);
|
||||
window.try_force_undecorated(false);
|
||||
window.set_tiled(false);
|
||||
|
|
@ -220,7 +230,10 @@ impl CosmicStack {
|
|||
if windows.len() <= idx {
|
||||
return;
|
||||
}
|
||||
let window = dbg!(windows.remove(idx));
|
||||
if idx == p.active.load(Ordering::SeqCst) {
|
||||
p.reenter.store(true, Ordering::SeqCst);
|
||||
}
|
||||
let window = windows.remove(idx);
|
||||
window.try_force_undecorated(false);
|
||||
window.set_tiled(false);
|
||||
|
||||
|
|
@ -233,7 +246,7 @@ impl CosmicStack {
|
|||
self.0.with_program(|p| p.windows.lock().unwrap().len())
|
||||
}
|
||||
|
||||
pub fn handle_focus(&self, direction: FocusDirection) -> bool {
|
||||
pub fn handle_focus(&self, direction: FocusDirection, swap: Option<NodeDesc>) -> bool {
|
||||
let result = self.0.with_program(|p| match direction {
|
||||
FocusDirection::Left => {
|
||||
if !p.group_focused.load(Ordering::SeqCst) {
|
||||
|
|
@ -278,7 +291,7 @@ impl CosmicStack {
|
|||
false
|
||||
}
|
||||
}
|
||||
FocusDirection::Out => {
|
||||
FocusDirection::Out if swap.is_none() => {
|
||||
if !p.group_focused.swap(true, Ordering::SeqCst) {
|
||||
p.windows.lock().unwrap().iter().for_each(|w| {
|
||||
w.set_activated(false);
|
||||
|
|
@ -289,7 +302,7 @@ impl CosmicStack {
|
|||
false
|
||||
}
|
||||
}
|
||||
FocusDirection::In => {
|
||||
FocusDirection::In if swap.is_none() => {
|
||||
if !p.group_focused.swap(false, Ordering::SeqCst) {
|
||||
p.windows.lock().unwrap().iter().for_each(|w| {
|
||||
w.set_activated(true);
|
||||
|
|
@ -360,6 +373,11 @@ impl CosmicStack {
|
|||
.with_program(|p| &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)] == window)
|
||||
}
|
||||
|
||||
pub fn whole_stack_focused(&self) -> bool {
|
||||
self.0
|
||||
.with_program(|p| p.group_focused.load(Ordering::SeqCst))
|
||||
}
|
||||
|
||||
pub fn set_active(&self, window: &CosmicSurface) {
|
||||
self.0.with_program(|p| {
|
||||
if let Some(val) = p.windows.lock().unwrap().iter().position(|w| w == window) {
|
||||
|
|
@ -412,10 +430,12 @@ impl CosmicStack {
|
|||
self.0.with_program(|p| {
|
||||
let active = p.active.load(Ordering::SeqCst);
|
||||
let previous = p.previous_keyboard.swap(active, Ordering::SeqCst);
|
||||
if previous != active {
|
||||
if previous != active || p.reenter.swap(false, Ordering::SeqCst) {
|
||||
let windows = p.windows.lock().unwrap();
|
||||
if let Some(previous) = windows.get(previous) {
|
||||
KeyboardTarget::leave(previous, seat, data, serial);
|
||||
if let Some(previous_surface) = windows.get(previous) {
|
||||
if previous != active {
|
||||
KeyboardTarget::leave(previous_surface, seat, data, serial);
|
||||
}
|
||||
}
|
||||
KeyboardTarget::enter(
|
||||
&windows[active],
|
||||
|
|
@ -476,7 +496,7 @@ impl CosmicStack {
|
|||
.with_program(|p| p.group_focused.store(true, Ordering::SeqCst));
|
||||
}
|
||||
|
||||
pub(super) fn loop_handle(&self) -> LoopHandle<'static, crate::state::Data> {
|
||||
pub(in super::super) fn loop_handle(&self) -> LoopHandle<'static, crate::state::Data> {
|
||||
self.0.loop_handle()
|
||||
}
|
||||
|
||||
|
|
@ -1051,9 +1071,10 @@ impl PointerTarget<State> for CosmicStack {
|
|||
was_tiled,
|
||||
);
|
||||
if grab.is_tiling_grab() {
|
||||
data.common
|
||||
.shell
|
||||
.set_overview_mode(Some(Trigger::Pointer(button)));
|
||||
data.common.shell.set_overview_mode(
|
||||
Some(Trigger::Pointer(button)),
|
||||
data.common.event_loop_handle.clone(),
|
||||
);
|
||||
}
|
||||
|
||||
let seat = seat.clone();
|
||||
|
|
|
|||
58
src/shell/element/swap_indicator.rs
Normal file
58
src/shell/element/swap_indicator.rs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
use crate::{
|
||||
fl,
|
||||
utils::iced::{IcedElement, Program},
|
||||
};
|
||||
|
||||
use apply::Apply;
|
||||
use calloop::LoopHandle;
|
||||
use cosmic::{
|
||||
iced::widget::{container, horizontal_space, row},
|
||||
iced_core::{Alignment, Background, Color, Length},
|
||||
theme,
|
||||
widget::{icon, text},
|
||||
};
|
||||
use smithay::utils::Size;
|
||||
|
||||
pub type SwapIndicator = IcedElement<SwapIndicatorInternal>;
|
||||
|
||||
pub fn swap_indicator(evlh: LoopHandle<'static, crate::state::Data>) -> SwapIndicator {
|
||||
SwapIndicator::new(SwapIndicatorInternal, Size::from((1, 1)), evlh)
|
||||
}
|
||||
|
||||
pub struct SwapIndicatorInternal;
|
||||
|
||||
impl Program for SwapIndicatorInternal {
|
||||
type Message = ();
|
||||
|
||||
fn view(&self) -> crate::utils::iced::Element<'_, Self::Message> {
|
||||
row(vec![
|
||||
icon("window-swap-symbolic", 32).force_svg(true).into(),
|
||||
horizontal_space(16).into(),
|
||||
text(fl!("swap-windows"))
|
||||
.font(cosmic::font::FONT)
|
||||
.size(24)
|
||||
.into(),
|
||||
])
|
||||
.align_items(Alignment::Center)
|
||||
.apply(container)
|
||||
.center_x()
|
||||
.center_y()
|
||||
.padding(16)
|
||||
.apply(container)
|
||||
.style(theme::Container::custom(|theme| container::Appearance {
|
||||
text_color: Some(Color::from(theme.cosmic().accent.on)),
|
||||
background: Some(Background::Color(theme.cosmic().accent_color().into())),
|
||||
border_radius: 18.0.into(),
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
}))
|
||||
.width(Length::Shrink)
|
||||
.height(Length::Shrink)
|
||||
.apply(container)
|
||||
.height(Length::Fill)
|
||||
.width(Length::Fill)
|
||||
.center_x()
|
||||
.center_y()
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ use crate::{
|
|||
backend::render::{
|
||||
cursor::{CursorShape, CursorState},
|
||||
element::AsGlowRenderer,
|
||||
IndicatorShader,
|
||||
IndicatorShader, Key, Usage,
|
||||
},
|
||||
shell::{
|
||||
element::{
|
||||
|
|
@ -96,7 +96,7 @@ impl MoveGrabState {
|
|||
Some(
|
||||
CosmicMappedRenderElement::from(IndicatorShader::focus_element(
|
||||
renderer,
|
||||
self.window.clone(),
|
||||
Key::Window(Usage::MoveGrabIndicator, self.window.clone()),
|
||||
Rectangle::from_loc_and_size(
|
||||
render_location,
|
||||
self.window
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use smithay::{
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
backend::render::{element::AsGlowRenderer, IndicatorShader},
|
||||
backend::render::{element::AsGlowRenderer, IndicatorShader, Key, Usage},
|
||||
shell::{
|
||||
element::{
|
||||
resize_indicator::ResizeIndicator, stack::CosmicStackRenderElement,
|
||||
|
|
@ -514,7 +514,7 @@ impl FloatingLayout {
|
|||
if indicator_thickness > 0 {
|
||||
let element = IndicatorShader::focus_element(
|
||||
renderer,
|
||||
elem.clone(),
|
||||
Key::Window(Usage::FocusIndicator, elem.clone()),
|
||||
indicator_geometry,
|
||||
indicator_thickness,
|
||||
output_scale,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
mod resize;
|
||||
mod swap;
|
||||
|
||||
pub use self::resize::*;
|
||||
pub use self::swap::*;
|
||||
|
|
|
|||
93
src/shell/layout/tiling/grabs/swap.rs
Normal file
93
src/shell/layout/tiling/grabs/swap.rs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
use smithay::{
|
||||
backend::input::KeyState,
|
||||
input::{
|
||||
keyboard::{
|
||||
GrabStartData as KeyboardGrabStartData, KeyboardGrab, KeyboardInnerHandle,
|
||||
ModifiersState,
|
||||
},
|
||||
Seat, SeatHandler,
|
||||
},
|
||||
utils::Serial,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
config::{Action, KeyPattern},
|
||||
shell::{layout::tiling::NodeDesc, OverviewMode, Trigger},
|
||||
state::State,
|
||||
};
|
||||
|
||||
pub struct SwapWindowGrab {
|
||||
seat: Seat<State>,
|
||||
desc: NodeDesc,
|
||||
}
|
||||
|
||||
impl SwapWindowGrab {
|
||||
pub fn new(seat: Seat<State>, desc: NodeDesc) -> Self {
|
||||
SwapWindowGrab { seat, desc }
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyboardGrab<State> for SwapWindowGrab {
|
||||
fn input(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut KeyboardInnerHandle<'_, State>,
|
||||
keycode: u32,
|
||||
state: KeyState,
|
||||
modifiers: Option<ModifiersState>,
|
||||
serial: Serial,
|
||||
time: u32,
|
||||
) {
|
||||
if self.desc.output.upgrade().is_none()
|
||||
|| !matches!(&data.common.shell.overview_mode, OverviewMode::Started(Trigger::KeyboardSwap(_, d), _) if d == &self.desc)
|
||||
{
|
||||
handle.unset_grab(data, serial, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if state == KeyState::Released {
|
||||
return;
|
||||
}
|
||||
|
||||
let syms = Vec::from(handle.keysym_handle(keycode).raw_syms());
|
||||
let focus_bindings = &data
|
||||
.common
|
||||
.config
|
||||
.static_conf
|
||||
.key_bindings
|
||||
.iter()
|
||||
.filter(|(_, action)| matches!(action, Action::Focus(_)))
|
||||
.map(|(pattern, action)| {
|
||||
let Action::Focus(direction) = action else { unreachable!() };
|
||||
(pattern.key, *direction)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let Some(direction) = syms.iter().find_map(|sym| focus_bindings.iter().find_map(|(key, direction)| (sym == key).then_some(*direction))) else { return };
|
||||
|
||||
data.handle_action(
|
||||
Action::Focus(direction),
|
||||
&self.seat,
|
||||
serial,
|
||||
time,
|
||||
KeyPattern {
|
||||
modifiers: modifiers.map(Into::into).unwrap_or_default(),
|
||||
key: keycode,
|
||||
},
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
fn set_focus(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut KeyboardInnerHandle<'_, State>,
|
||||
focus: Option<<State as SeatHandler>::KeyboardFocus>,
|
||||
serial: Serial,
|
||||
) {
|
||||
handle.set_focus(data, focus, serial)
|
||||
}
|
||||
|
||||
fn start_data(&self) -> &KeyboardGrabStartData<State> {
|
||||
&KeyboardGrabStartData { focus: None }
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -59,13 +59,14 @@ pub use self::workspace::*;
|
|||
use self::{
|
||||
element::{
|
||||
resize_indicator::{resize_indicator, ResizeIndicator},
|
||||
swap_indicator::{swap_indicator, SwapIndicator},
|
||||
CosmicWindow,
|
||||
},
|
||||
focus::target::KeyboardFocusTarget,
|
||||
grabs::ResizeEdge,
|
||||
layout::{
|
||||
floating::{FloatingLayout, ResizeState},
|
||||
tiling::{Direction, TilingLayout},
|
||||
tiling::{Direction, NodeDesc, TilingLayout},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -73,7 +74,8 @@ const ANIMATION_DURATION: Duration = Duration::from_millis(200);
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Trigger {
|
||||
Keyboard(KeyModifiers),
|
||||
KeyboardSwap(KeyPattern, NodeDesc),
|
||||
KeyboardMove(KeyModifiers),
|
||||
Pointer(u32),
|
||||
}
|
||||
|
||||
|
|
@ -81,7 +83,7 @@ pub enum Trigger {
|
|||
pub enum OverviewMode {
|
||||
None,
|
||||
Started(Trigger, Instant),
|
||||
Ended(Instant),
|
||||
Ended(Option<Trigger>, Instant),
|
||||
}
|
||||
|
||||
impl OverviewMode {
|
||||
|
|
@ -92,7 +94,7 @@ impl OverviewMode {
|
|||
/ ANIMATION_DURATION.as_millis() as f32;
|
||||
Some(ease(EaseInOutCubic, 0.0, 1.0, percentage))
|
||||
}
|
||||
OverviewMode::Ended(end) => {
|
||||
OverviewMode::Ended(_, end) => {
|
||||
let percentage = Instant::now().duration_since(*end).as_millis() as f32
|
||||
/ ANIMATION_DURATION.as_millis() as f32;
|
||||
if percentage < 1.0 {
|
||||
|
|
@ -160,6 +162,7 @@ pub struct Shell {
|
|||
|
||||
gaps: (u8, u8),
|
||||
overview_mode: OverviewMode,
|
||||
swap_indicator: Option<SwapIndicator>,
|
||||
resize_mode: ResizeMode,
|
||||
resize_state: Option<(
|
||||
KeyboardFocusTarget,
|
||||
|
|
@ -628,6 +631,7 @@ impl Shell {
|
|||
|
||||
gaps: config.static_conf.gaps,
|
||||
overview_mode: OverviewMode::None,
|
||||
swap_indicator: None,
|
||||
resize_mode: ResizeMode::None,
|
||||
resize_state: None,
|
||||
resize_indicator: None,
|
||||
|
|
@ -1206,32 +1210,45 @@ impl Shell {
|
|||
clients
|
||||
}
|
||||
|
||||
pub fn set_overview_mode(&mut self, enabled: Option<Trigger>) {
|
||||
pub fn set_overview_mode(
|
||||
&mut self,
|
||||
enabled: Option<Trigger>,
|
||||
evlh: LoopHandle<'static, crate::state::Data>,
|
||||
) {
|
||||
if let Some(trigger) = enabled {
|
||||
if !matches!(self.overview_mode, OverviewMode::Started(_, _)) {
|
||||
if matches!(trigger, Trigger::KeyboardSwap(_, _)) {
|
||||
self.swap_indicator = Some(swap_indicator(evlh));
|
||||
}
|
||||
self.overview_mode = OverviewMode::Started(trigger, Instant::now());
|
||||
}
|
||||
} else {
|
||||
if !matches!(self.overview_mode, OverviewMode::Ended(_)) {
|
||||
let reverse_duration = if let OverviewMode::Started(_, start) = self.overview_mode {
|
||||
ANIMATION_DURATION
|
||||
- Instant::now().duration_since(start).min(ANIMATION_DURATION)
|
||||
} else {
|
||||
Duration::ZERO
|
||||
};
|
||||
self.overview_mode = OverviewMode::Ended(Instant::now() - reverse_duration);
|
||||
if !matches!(self.overview_mode, OverviewMode::Ended(_, _)) {
|
||||
let (reverse_duration, trigger) =
|
||||
if let OverviewMode::Started(trigger, start) = self.overview_mode.clone() {
|
||||
(
|
||||
ANIMATION_DURATION
|
||||
- Instant::now().duration_since(start).min(ANIMATION_DURATION),
|
||||
Some(trigger),
|
||||
)
|
||||
} else {
|
||||
(Duration::ZERO, None)
|
||||
};
|
||||
self.overview_mode =
|
||||
OverviewMode::Ended(trigger, Instant::now() - reverse_duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn overview_mode(&mut self) -> OverviewMode {
|
||||
if let OverviewMode::Ended(timestamp) = self.overview_mode {
|
||||
pub fn overview_mode(&mut self) -> (OverviewMode, Option<SwapIndicator>) {
|
||||
if let OverviewMode::Ended(_, timestamp) = self.overview_mode {
|
||||
if Instant::now().duration_since(timestamp) > ANIMATION_DURATION {
|
||||
self.overview_mode = OverviewMode::None;
|
||||
self.swap_indicator = None;
|
||||
}
|
||||
}
|
||||
|
||||
self.overview_mode.clone()
|
||||
(self.overview_mode.clone(), self.swap_indicator.clone())
|
||||
}
|
||||
|
||||
pub fn set_resize_mode(
|
||||
|
|
@ -1570,10 +1587,10 @@ impl Shell {
|
|||
.toplevel_info_state
|
||||
.toplevel_leave_output(&window, &output);
|
||||
if grab.is_tiling_grab() {
|
||||
state
|
||||
.common
|
||||
.shell
|
||||
.set_overview_mode(Some(Trigger::Pointer(button)));
|
||||
state.common.shell.set_overview_mode(
|
||||
Some(Trigger::Pointer(button)),
|
||||
state.common.event_loop_handle.clone(),
|
||||
);
|
||||
}
|
||||
seat.get_pointer().unwrap().set_grab(
|
||||
state,
|
||||
|
|
|
|||
|
|
@ -50,13 +50,14 @@ use wayland_backend::server::ClientId;
|
|||
use super::{
|
||||
element::{
|
||||
resize_indicator::ResizeIndicator, stack::CosmicStackRenderElement,
|
||||
window::CosmicWindowRenderElement, CosmicMapped,
|
||||
swap_indicator::SwapIndicator, window::CosmicWindowRenderElement, CosmicMapped,
|
||||
},
|
||||
focus::{
|
||||
target::{KeyboardFocusTarget, PointerFocusTarget},
|
||||
target::{KeyboardFocusTarget, PointerFocusTarget, WindowGroup},
|
||||
FocusStack, FocusStackMut,
|
||||
},
|
||||
grabs::{ResizeEdge, ResizeGrab},
|
||||
layout::tiling::NodeDesc,
|
||||
CosmicMappedRenderElement, CosmicSurface, ResizeDirection, ResizeMode,
|
||||
};
|
||||
|
||||
|
|
@ -482,6 +483,43 @@ impl Workspace {
|
|||
&& self.tiling_layer.mapped().any(|(_, m, _)| m == mapped)
|
||||
}
|
||||
|
||||
pub fn node_desc(&self, focus: KeyboardFocusTarget) -> Option<NodeDesc> {
|
||||
match focus {
|
||||
KeyboardFocusTarget::Element(mapped) => {
|
||||
self.tiling_layer.mapped().find_map(|(output, m, _)| {
|
||||
(m == &mapped).then_some(output.clone()).and_then(|output| {
|
||||
mapped
|
||||
.tiling_node_id
|
||||
.lock()
|
||||
.unwrap()
|
||||
.clone()
|
||||
.map(|node_id| NodeDesc {
|
||||
handle: self.handle.clone(),
|
||||
output: output.downgrade(),
|
||||
node: node_id,
|
||||
stack_window: if mapped
|
||||
.stack_ref()
|
||||
.map(|stack| !stack.whole_stack_focused())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
Some(mapped.active_window())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
KeyboardFocusTarget::Group(WindowGroup { output, node, .. }) => Some(NodeDesc {
|
||||
handle: self.handle.clone(),
|
||||
output,
|
||||
node,
|
||||
stack_window: None,
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_output<'a, R>(
|
||||
&self,
|
||||
renderer: &mut R,
|
||||
|
|
@ -489,7 +527,7 @@ impl Workspace {
|
|||
override_redirect_windows: &[X11Surface],
|
||||
xwm_state: Option<&'a mut XWaylandState>,
|
||||
draw_focus_indicator: Option<&Seat<State>>,
|
||||
overview: OverviewMode,
|
||||
overview: (OverviewMode, Option<SwapIndicator>),
|
||||
resize_indicator: Option<(ResizeMode, ResizeIndicator)>,
|
||||
indicator_thickness: u8,
|
||||
) -> Result<
|
||||
|
|
@ -582,7 +620,7 @@ impl Workspace {
|
|||
draw_focus_indicator.and_then(|seat| self.focus_stack.get(seat).last().cloned());
|
||||
|
||||
// floating surfaces
|
||||
let alpha = match &overview {
|
||||
let alpha = match &overview.0 {
|
||||
OverviewMode::Started(_, started) => {
|
||||
(1.0 - (Instant::now().duration_since(*started).as_millis()
|
||||
/ ANIMATION_DURATION.as_millis()) as f32)
|
||||
|
|
@ -590,7 +628,7 @@ impl Workspace {
|
|||
* 0.4
|
||||
+ 0.6
|
||||
}
|
||||
OverviewMode::Ended(ended) => {
|
||||
OverviewMode::Ended(_, ended) => {
|
||||
((Instant::now().duration_since(*ended).as_millis()
|
||||
/ ANIMATION_DURATION.as_millis()) as f32)
|
||||
* 0.4
|
||||
|
|
@ -614,6 +652,7 @@ impl Workspace {
|
|||
let (w_elements, p_elements) = self.tiling_layer.render_output::<R>(
|
||||
renderer,
|
||||
output,
|
||||
&self.handle,
|
||||
draw_focus_indicator,
|
||||
layer_map.non_exclusive_zone(),
|
||||
overview.clone(),
|
||||
|
|
@ -635,12 +674,12 @@ impl Workspace {
|
|||
}
|
||||
}
|
||||
|
||||
let alpha = match overview {
|
||||
let alpha = match overview.0 {
|
||||
OverviewMode::Started(_, start) => Some(
|
||||
(Instant::now().duration_since(start).as_millis() as f64 / 100.0).min(1.0)
|
||||
as f32,
|
||||
),
|
||||
OverviewMode::Ended(ended) => Some(
|
||||
OverviewMode::Ended(_, ended) => Some(
|
||||
1.0 - (Instant::now().duration_since(ended).as_millis() as f64 / 100.0).min(1.0)
|
||||
as f32,
|
||||
),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue