2023-07-28 19:18:14 +02:00
|
|
|
use super::{CosmicMapped, CosmicSurface, CosmicWindow};
|
2022-11-03 18:51:27 +01:00
|
|
|
use crate::{
|
2023-08-11 18:15:22 +02:00
|
|
|
shell::{
|
2023-09-20 18:57:58 +02:00
|
|
|
focus::FocusDirection, grabs::MoveGrab, layout::tiling::NodeDesc, Direction, Shell, Trigger,
|
2023-08-11 18:15:22 +02:00
|
|
|
},
|
2023-01-16 15:12:25 +01:00
|
|
|
state::State,
|
2023-06-22 20:58:39 +02:00
|
|
|
utils::iced::{IcedElement, Program},
|
2023-01-16 15:12:25 +01:00
|
|
|
utils::prelude::SeatExt,
|
|
|
|
|
wayland::handlers::screencopy::ScreencopySessions,
|
2022-11-03 18:51:27 +01:00
|
|
|
};
|
2023-06-08 13:19:30 +02:00
|
|
|
use apply::Apply;
|
2023-01-16 15:12:25 +01:00
|
|
|
use calloop::LoopHandle;
|
2023-06-08 13:19:30 +02:00
|
|
|
use cosmic::{
|
2023-06-13 18:32:04 +02:00
|
|
|
iced::{id::Id, widget as iced_widget},
|
2023-06-22 21:01:05 +02:00
|
|
|
iced_core::{Background, BorderRadius, Color, Length},
|
2023-06-08 21:50:25 +02:00
|
|
|
iced_runtime::Command,
|
2023-06-22 20:58:39 +02:00
|
|
|
iced_widget::scrollable::AbsoluteOffset,
|
2023-06-08 13:19:30 +02:00
|
|
|
theme, widget as cosmic_widget, Element as CosmicElement,
|
|
|
|
|
};
|
2022-11-03 18:51:27 +01:00
|
|
|
use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::InputType;
|
2023-06-13 18:32:04 +02:00
|
|
|
use once_cell::sync::Lazy;
|
2022-09-28 12:01:29 +02:00
|
|
|
use smithay::{
|
|
|
|
|
backend::{
|
|
|
|
|
input::KeyState,
|
|
|
|
|
renderer::{
|
2023-01-16 15:12:25 +01:00
|
|
|
element::{
|
|
|
|
|
memory::MemoryRenderBufferRenderElement, surface::WaylandSurfaceRenderElement,
|
2023-06-08 21:50:16 +02:00
|
|
|
AsRenderElements,
|
2023-01-16 15:12:25 +01:00
|
|
|
},
|
|
|
|
|
ImportAll, ImportMem, Renderer,
|
2022-09-28 12:01:29 +02:00
|
|
|
},
|
|
|
|
|
},
|
2023-01-16 15:12:25 +01:00
|
|
|
desktop::space::SpaceElement,
|
2022-09-28 12:01:29 +02:00
|
|
|
input::{
|
|
|
|
|
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
|
2023-07-28 19:18:14 +02:00
|
|
|
pointer::{
|
2023-09-05 10:55:23 -07:00
|
|
|
AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent,
|
|
|
|
|
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent,
|
|
|
|
|
GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent,
|
|
|
|
|
GrabStartData as PointerGrabStartData, MotionEvent, PointerTarget, RelativeMotionEvent,
|
2023-07-28 19:18:14 +02:00
|
|
|
},
|
2022-09-28 12:01:29 +02:00
|
|
|
Seat,
|
|
|
|
|
},
|
|
|
|
|
output::Output,
|
2023-06-08 21:50:16 +02:00
|
|
|
render_elements,
|
2023-07-13 17:19:29 +02:00
|
|
|
utils::{IsAlive, Logical, Point, Rectangle, Serial, Size},
|
2023-06-08 21:50:16 +02:00
|
|
|
wayland::seat::WaylandFocus,
|
2022-09-28 12:01:29 +02:00
|
|
|
};
|
|
|
|
|
use std::{
|
2023-01-16 15:12:25 +01:00
|
|
|
fmt,
|
2022-09-28 12:01:29 +02:00
|
|
|
hash::Hash,
|
|
|
|
|
sync::{
|
2023-06-08 13:19:30 +02:00
|
|
|
atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering},
|
2022-09-28 12:01:29 +02:00
|
|
|
Arc, Mutex,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
2023-06-22 20:58:39 +02:00
|
|
|
mod tab;
|
|
|
|
|
mod tab_text;
|
|
|
|
|
mod tabs;
|
|
|
|
|
|
|
|
|
|
use self::{
|
|
|
|
|
tab::{Tab, TabMessage},
|
|
|
|
|
tabs::Tabs,
|
|
|
|
|
};
|
|
|
|
|
|
2023-06-13 18:32:04 +02:00
|
|
|
static SCROLLABLE_ID: Lazy<Id> = Lazy::new(|| Id::new("scrollable"));
|
2023-01-16 15:12:25 +01:00
|
|
|
|
|
|
|
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
|
|
|
|
pub struct CosmicStack(IcedElement<CosmicStackInternal>);
|
|
|
|
|
|
|
|
|
|
impl fmt::Debug for CosmicStack {
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2023-06-13 18:32:04 +02:00
|
|
|
f.debug_struct("CosmicStack")
|
|
|
|
|
.field("internal", &self.0)
|
|
|
|
|
.finish_non_exhaustive()
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-28 12:01:29 +02:00
|
|
|
#[derive(Debug, Clone)]
|
2023-01-16 15:12:25 +01:00
|
|
|
pub struct CosmicStackInternal {
|
|
|
|
|
windows: Arc<Mutex<Vec<CosmicSurface>>>,
|
2022-09-28 12:01:29 +02:00
|
|
|
active: Arc<AtomicUsize>,
|
2023-06-08 13:19:30 +02:00
|
|
|
activated: Arc<AtomicBool>,
|
|
|
|
|
group_focused: Arc<AtomicBool>,
|
2023-06-22 20:58:39 +02:00
|
|
|
scroll_to_focus: Arc<AtomicBool>,
|
2022-11-03 18:51:27 +01:00
|
|
|
previous_keyboard: Arc<AtomicUsize>,
|
2023-06-08 21:50:25 +02:00
|
|
|
pointer_entered: Arc<AtomicU8>,
|
2022-11-03 18:51:27 +01:00
|
|
|
previous_pointer: Arc<AtomicUsize>,
|
2023-08-11 18:15:22 +02:00
|
|
|
reenter: Arc<AtomicBool>,
|
2023-07-28 19:18:14 +02:00
|
|
|
potential_drag: Arc<Mutex<Option<usize>>>,
|
|
|
|
|
override_alive: Arc<AtomicBool>,
|
2023-06-08 21:50:25 +02:00
|
|
|
last_seat: Arc<Mutex<Option<(Seat<State>, Serial)>>>,
|
2023-01-16 15:12:25 +01:00
|
|
|
last_location: Arc<Mutex<Option<(Point<f64, Logical>, Serial, u32)>>>,
|
2023-06-08 13:19:30 +02:00
|
|
|
geometry: Arc<Mutex<Option<Rectangle<i32, Logical>>>>,
|
2023-05-31 20:02:39 +02:00
|
|
|
mask: Arc<Mutex<Option<tiny_skia::Mask>>>,
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
impl CosmicStackInternal {
|
|
|
|
|
pub fn swap_focus(&self, focus: Focus) -> Focus {
|
2023-06-08 21:50:25 +02:00
|
|
|
unsafe {
|
|
|
|
|
std::mem::transmute::<u8, Focus>(
|
|
|
|
|
self.pointer_entered.swap(focus as u8, Ordering::SeqCst),
|
|
|
|
|
)
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
pub fn current_focus(&self) -> Focus {
|
2023-06-08 21:50:25 +02:00
|
|
|
unsafe { std::mem::transmute::<u8, Focus>(self.pointer_entered.load(Ordering::SeqCst)) }
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-11 18:15:22 +02:00
|
|
|
pub const TAB_HEIGHT: i32 = 24;
|
2022-09-28 12:01:29 +02:00
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
#[repr(u8)]
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
|
|
|
pub enum Focus {
|
|
|
|
|
None,
|
|
|
|
|
Header,
|
|
|
|
|
Window,
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
|
2023-06-12 17:24:36 +02:00
|
|
|
pub enum MoveResult {
|
|
|
|
|
Handled,
|
2023-09-29 21:33:16 +02:00
|
|
|
MoveOut(CosmicSurface, LoopHandle<'static, crate::state::State>),
|
2023-06-12 17:24:36 +02:00
|
|
|
Default,
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-28 12:01:29 +02:00
|
|
|
impl CosmicStack {
|
2023-05-31 14:15:41 +02:00
|
|
|
pub fn new<I: Into<CosmicSurface>>(
|
|
|
|
|
windows: impl Iterator<Item = I>,
|
2023-09-29 21:33:16 +02:00
|
|
|
handle: LoopHandle<'static, crate::state::State>,
|
2023-01-16 15:12:25 +01:00
|
|
|
) -> CosmicStack {
|
2023-05-31 14:15:41 +02:00
|
|
|
let windows = windows.map(Into::into).collect::<Vec<_>>();
|
|
|
|
|
assert!(!windows.is_empty());
|
2023-06-08 13:19:30 +02:00
|
|
|
|
|
|
|
|
for window in &windows {
|
|
|
|
|
window.try_force_undecorated(true);
|
|
|
|
|
window.set_tiled(true);
|
2023-07-06 18:20:10 +02:00
|
|
|
window.send_configure();
|
2023-06-08 13:19:30 +02:00
|
|
|
}
|
|
|
|
|
|
2023-05-31 14:15:41 +02:00
|
|
|
let width = windows[0].geometry().size.w;
|
2023-01-16 15:12:25 +01:00
|
|
|
CosmicStack(IcedElement::new(
|
|
|
|
|
CosmicStackInternal {
|
2023-05-31 14:15:41 +02:00
|
|
|
windows: Arc::new(Mutex::new(windows)),
|
2023-01-16 15:12:25 +01:00
|
|
|
active: Arc::new(AtomicUsize::new(0)),
|
2023-06-08 13:19:30 +02:00
|
|
|
activated: Arc::new(AtomicBool::new(false)),
|
|
|
|
|
group_focused: Arc::new(AtomicBool::new(false)),
|
2023-06-22 20:58:39 +02:00
|
|
|
scroll_to_focus: Arc::new(AtomicBool::new(false)),
|
2023-01-16 15:12:25 +01:00
|
|
|
previous_keyboard: Arc::new(AtomicUsize::new(0)),
|
2023-06-08 21:50:25 +02:00
|
|
|
pointer_entered: Arc::new(AtomicU8::new(Focus::None as u8)),
|
2023-01-16 15:12:25 +01:00
|
|
|
previous_pointer: Arc::new(AtomicUsize::new(0)),
|
2023-08-11 18:15:22 +02:00
|
|
|
reenter: Arc::new(AtomicBool::new(false)),
|
2023-07-28 19:18:14 +02:00
|
|
|
potential_drag: Arc::new(Mutex::new(None)),
|
|
|
|
|
override_alive: Arc::new(AtomicBool::new(true)),
|
2023-06-08 21:50:25 +02:00
|
|
|
last_seat: Arc::new(Mutex::new(None)),
|
2023-01-16 15:12:25 +01:00
|
|
|
last_location: Arc::new(Mutex::new(None)),
|
2023-06-08 13:19:30 +02:00
|
|
|
geometry: Arc::new(Mutex::new(None)),
|
2023-05-31 20:02:39 +02:00
|
|
|
mask: Arc::new(Mutex::new(None)),
|
2023-01-16 15:12:25 +01:00
|
|
|
},
|
|
|
|
|
(width, TAB_HEIGHT),
|
|
|
|
|
handle,
|
|
|
|
|
))
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
|
2023-06-12 17:24:36 +02:00
|
|
|
pub fn add_window(&self, window: impl Into<CosmicSurface>, idx: Option<usize>) {
|
2023-06-08 13:19:30 +02:00
|
|
|
let window = window.into();
|
|
|
|
|
window.try_force_undecorated(true);
|
|
|
|
|
window.set_tiled(true);
|
2023-06-12 17:24:36 +02:00
|
|
|
self.0.with_program(|p| {
|
2023-06-23 16:08:23 +02:00
|
|
|
if let Some(mut geo) = p.geometry.lock().unwrap().clone() {
|
|
|
|
|
geo.loc.y += TAB_HEIGHT;
|
|
|
|
|
geo.size.h -= TAB_HEIGHT;
|
|
|
|
|
window.set_geometry(geo);
|
|
|
|
|
}
|
|
|
|
|
window.send_configure();
|
2023-06-12 17:24:36 +02:00
|
|
|
if let Some(idx) = idx {
|
|
|
|
|
p.windows.lock().unwrap().insert(idx, window);
|
2023-09-11 21:10:46 +02:00
|
|
|
let old_idx = p.active.swap(idx, Ordering::SeqCst);
|
|
|
|
|
if old_idx == idx {
|
|
|
|
|
p.reenter.store(true, Ordering::SeqCst);
|
|
|
|
|
p.previous_keyboard.store(old_idx, Ordering::SeqCst);
|
|
|
|
|
p.previous_pointer.store(old_idx, Ordering::SeqCst);
|
|
|
|
|
}
|
2023-06-12 17:24:36 +02:00
|
|
|
} else {
|
|
|
|
|
let mut windows = p.windows.lock().unwrap();
|
|
|
|
|
windows.push(window);
|
|
|
|
|
p.active.store(windows.len() - 1, Ordering::SeqCst);
|
|
|
|
|
}
|
2023-06-22 20:58:39 +02:00
|
|
|
p.scroll_to_focus.store(true, Ordering::SeqCst);
|
2023-06-12 17:24:36 +02:00
|
|
|
});
|
2023-06-08 13:19:30 +02:00
|
|
|
self.0.force_redraw()
|
2023-05-31 14:15:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn remove_window(&self, window: &CosmicSurface) {
|
|
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
let mut windows = p.windows.lock().unwrap();
|
2023-06-05 17:52:47 +02:00
|
|
|
if windows.len() == 1 {
|
2023-07-28 19:18:14 +02:00
|
|
|
p.override_alive.store(false, Ordering::SeqCst);
|
|
|
|
|
let window = windows.get(0).unwrap();
|
|
|
|
|
window.try_force_undecorated(false);
|
|
|
|
|
window.set_tiled(false);
|
2023-06-05 17:52:47 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-31 17:36:32 +02:00
|
|
|
let Some(idx) = windows.iter().position(|w| w == window) else {
|
|
|
|
|
return;
|
|
|
|
|
};
|
2023-08-11 18:15:22 +02:00
|
|
|
if idx == p.active.load(Ordering::SeqCst) {
|
|
|
|
|
p.reenter.store(true, Ordering::SeqCst);
|
|
|
|
|
}
|
2023-06-08 13:19:30 +02:00
|
|
|
let window = windows.remove(idx);
|
|
|
|
|
window.try_force_undecorated(false);
|
|
|
|
|
window.set_tiled(false);
|
|
|
|
|
|
2023-05-31 14:15:41 +02:00
|
|
|
p.active.fetch_min(windows.len() - 1, Ordering::SeqCst);
|
2023-06-08 13:19:30 +02:00
|
|
|
});
|
|
|
|
|
self.0.force_redraw()
|
2023-05-31 14:15:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn remove_idx(&self, idx: usize) {
|
|
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
let mut windows = p.windows.lock().unwrap();
|
2023-06-05 17:52:47 +02:00
|
|
|
if windows.len() == 1 {
|
2023-07-28 19:18:14 +02:00
|
|
|
p.override_alive.store(false, Ordering::SeqCst);
|
|
|
|
|
let window = windows.get(0).unwrap();
|
|
|
|
|
window.try_force_undecorated(false);
|
|
|
|
|
window.set_tiled(false);
|
2023-06-05 17:52:47 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2023-07-28 19:18:14 +02:00
|
|
|
if windows.len() <= idx {
|
2023-05-31 14:15:41 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2023-08-11 18:15:22 +02:00
|
|
|
if idx == p.active.load(Ordering::SeqCst) {
|
|
|
|
|
p.reenter.store(true, Ordering::SeqCst);
|
|
|
|
|
}
|
|
|
|
|
let window = windows.remove(idx);
|
2023-06-08 13:19:30 +02:00
|
|
|
window.try_force_undecorated(false);
|
|
|
|
|
window.set_tiled(false);
|
|
|
|
|
|
2023-06-05 17:52:47 +02:00
|
|
|
p.active.fetch_min(windows.len() - 1, Ordering::SeqCst);
|
2023-06-08 13:19:30 +02:00
|
|
|
});
|
|
|
|
|
self.0.force_redraw()
|
2023-05-31 14:15:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn len(&self) -> usize {
|
|
|
|
|
self.0.with_program(|p| p.windows.lock().unwrap().len())
|
|
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
|
2023-08-11 18:15:22 +02:00
|
|
|
pub fn handle_focus(&self, direction: FocusDirection, swap: Option<NodeDesc>) -> bool {
|
2023-06-08 13:19:30 +02:00
|
|
|
let result = self.0.with_program(|p| match direction {
|
|
|
|
|
FocusDirection::Left => {
|
|
|
|
|
if !p.group_focused.load(Ordering::SeqCst) {
|
2023-06-08 21:50:25 +02:00
|
|
|
if let Ok(old) =
|
|
|
|
|
p.active
|
|
|
|
|
.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |val| {
|
|
|
|
|
val.checked_sub(1)
|
|
|
|
|
})
|
|
|
|
|
{
|
|
|
|
|
p.previous_keyboard.store(old, Ordering::SeqCst);
|
|
|
|
|
p.previous_pointer.store(old, Ordering::SeqCst);
|
2023-06-22 20:58:39 +02:00
|
|
|
p.scroll_to_focus.store(true, Ordering::SeqCst);
|
2023-06-08 21:50:25 +02:00
|
|
|
true
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
2023-06-08 13:19:30 +02:00
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
FocusDirection::Right => {
|
|
|
|
|
if !p.group_focused.load(Ordering::SeqCst) {
|
2023-06-05 17:52:47 +02:00
|
|
|
let max = p.windows.lock().unwrap().len();
|
2023-06-08 21:50:25 +02:00
|
|
|
if let Ok(old) =
|
|
|
|
|
p.active
|
|
|
|
|
.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |val| {
|
|
|
|
|
if val < max - 1 {
|
|
|
|
|
Some(val + 1)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
{
|
|
|
|
|
p.previous_keyboard.store(old, Ordering::SeqCst);
|
|
|
|
|
p.previous_pointer.store(old, Ordering::SeqCst);
|
2023-06-22 20:58:39 +02:00
|
|
|
p.scroll_to_focus.store(true, Ordering::SeqCst);
|
2023-06-08 21:50:25 +02:00
|
|
|
true
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
2023-06-08 13:19:30 +02:00
|
|
|
} else {
|
|
|
|
|
false
|
2023-06-05 17:52:47 +02:00
|
|
|
}
|
|
|
|
|
}
|
2023-08-11 18:15:22 +02:00
|
|
|
FocusDirection::Out if swap.is_none() => {
|
2023-06-08 13:19:30 +02:00
|
|
|
if !p.group_focused.swap(true, Ordering::SeqCst) {
|
|
|
|
|
p.windows.lock().unwrap().iter().for_each(|w| {
|
|
|
|
|
w.set_activated(false);
|
|
|
|
|
w.send_configure();
|
|
|
|
|
});
|
|
|
|
|
true
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-08-11 18:15:22 +02:00
|
|
|
FocusDirection::In if swap.is_none() => {
|
2023-06-08 13:19:30 +02:00
|
|
|
if !p.group_focused.swap(false, Ordering::SeqCst) {
|
|
|
|
|
p.windows.lock().unwrap().iter().for_each(|w| {
|
|
|
|
|
w.set_activated(true);
|
|
|
|
|
w.send_configure();
|
|
|
|
|
});
|
|
|
|
|
true
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => false,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if result {
|
|
|
|
|
self.0.force_update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result
|
2023-06-05 17:52:47 +02:00
|
|
|
}
|
|
|
|
|
|
2023-06-12 17:24:36 +02:00
|
|
|
pub fn handle_move(&self, direction: Direction) -> MoveResult {
|
|
|
|
|
let loop_handle = self.0.loop_handle();
|
|
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
if p.group_focused.load(Ordering::SeqCst) {
|
|
|
|
|
return MoveResult::Default;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let active = p.active.load(Ordering::SeqCst);
|
|
|
|
|
let mut windows = p.windows.lock().unwrap();
|
|
|
|
|
|
|
|
|
|
let next = match direction {
|
|
|
|
|
Direction::Left => active.checked_sub(1),
|
|
|
|
|
Direction::Right => (active + 1 < windows.len()).then_some(active + 1),
|
|
|
|
|
Direction::Down | Direction::Up => None,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if let Some(val) = next {
|
|
|
|
|
let old = p.active.swap(val, Ordering::SeqCst);
|
|
|
|
|
windows.swap(old, val);
|
|
|
|
|
p.previous_keyboard.store(old, Ordering::SeqCst);
|
|
|
|
|
p.previous_pointer.store(old, Ordering::SeqCst);
|
2023-06-22 20:58:39 +02:00
|
|
|
p.scroll_to_focus.store(true, Ordering::SeqCst);
|
2023-06-12 17:24:36 +02:00
|
|
|
MoveResult::Handled
|
|
|
|
|
} else {
|
|
|
|
|
if windows.len() == 1 {
|
|
|
|
|
return MoveResult::Default;
|
|
|
|
|
}
|
|
|
|
|
let window = windows.remove(active);
|
|
|
|
|
if active == windows.len() {
|
|
|
|
|
p.active.store(active - 1, Ordering::SeqCst);
|
2023-06-22 20:58:39 +02:00
|
|
|
p.scroll_to_focus.store(true, Ordering::SeqCst);
|
2023-06-12 17:24:36 +02:00
|
|
|
}
|
|
|
|
|
window.try_force_undecorated(false);
|
|
|
|
|
window.set_tiled(false);
|
|
|
|
|
|
|
|
|
|
MoveResult::MoveOut(window, loop_handle)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
pub fn active(&self) -> CosmicSurface {
|
|
|
|
|
self.0
|
|
|
|
|
.with_program(|p| p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)].clone())
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-01 20:35:58 +04:00
|
|
|
pub fn has_active(&self, window: &CosmicSurface) -> bool {
|
|
|
|
|
self.0
|
|
|
|
|
.with_program(|p| &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)] == window)
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-11 18:15:22 +02:00
|
|
|
pub fn whole_stack_focused(&self) -> bool {
|
|
|
|
|
self.0
|
|
|
|
|
.with_program(|p| p.group_focused.load(Ordering::SeqCst))
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
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) {
|
|
|
|
|
let old = p.active.swap(val, Ordering::SeqCst);
|
|
|
|
|
p.previous_keyboard.store(old, Ordering::SeqCst);
|
|
|
|
|
p.previous_pointer.store(old, Ordering::SeqCst);
|
|
|
|
|
}
|
2023-06-08 13:19:30 +02:00
|
|
|
});
|
|
|
|
|
self.0.force_redraw()
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn surfaces(&self) -> impl Iterator<Item = CosmicSurface> {
|
|
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
p.windows
|
|
|
|
|
.lock()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.iter()
|
|
|
|
|
.cloned()
|
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
|
.into_iter()
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn offset(&self) -> Point<i32, Logical> {
|
|
|
|
|
Point::from((0, TAB_HEIGHT))
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
|
2023-01-23 18:25:01 +01:00
|
|
|
pub fn set_geometry(&self, geo: Rectangle<i32, Logical>) {
|
2023-01-16 15:12:25 +01:00
|
|
|
self.0.with_program(|p| {
|
2023-01-23 18:25:01 +01:00
|
|
|
let loc = (geo.loc.x, geo.loc.y + TAB_HEIGHT);
|
|
|
|
|
let size = (geo.size.w, geo.size.h - TAB_HEIGHT);
|
2023-01-16 15:12:25 +01:00
|
|
|
|
2023-06-08 13:19:30 +02:00
|
|
|
let win_geo = Rectangle::from_loc_and_size(loc, size);
|
2023-01-16 15:12:25 +01:00
|
|
|
for window in p.windows.lock().unwrap().iter() {
|
2023-06-08 13:19:30 +02:00
|
|
|
window.set_geometry(win_geo);
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
2023-06-08 13:19:30 +02:00
|
|
|
|
|
|
|
|
*p.geometry.lock().unwrap() = Some(geo);
|
|
|
|
|
p.mask.lock().unwrap().take();
|
2023-01-16 15:12:25 +01:00
|
|
|
});
|
2023-01-23 18:25:01 +01:00
|
|
|
self.0.resize(Size::from((geo.size.w, TAB_HEIGHT)));
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
2022-11-03 18:51:27 +01:00
|
|
|
|
|
|
|
|
fn keyboard_leave_if_previous(
|
|
|
|
|
&self,
|
|
|
|
|
seat: &Seat<State>,
|
|
|
|
|
data: &mut State,
|
|
|
|
|
serial: Serial,
|
|
|
|
|
) -> usize {
|
2023-01-16 15:12:25 +01:00
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
let active = p.active.load(Ordering::SeqCst);
|
|
|
|
|
let previous = p.previous_keyboard.swap(active, Ordering::SeqCst);
|
2023-08-11 18:15:22 +02:00
|
|
|
if previous != active || p.reenter.swap(false, Ordering::SeqCst) {
|
2023-06-08 13:19:30 +02:00
|
|
|
let windows = p.windows.lock().unwrap();
|
2023-08-11 18:15:22 +02:00
|
|
|
if let Some(previous_surface) = windows.get(previous) {
|
|
|
|
|
if previous != active {
|
|
|
|
|
KeyboardTarget::leave(previous_surface, seat, data, serial);
|
|
|
|
|
}
|
2023-06-08 13:19:30 +02:00
|
|
|
}
|
2023-06-08 21:50:25 +02:00
|
|
|
KeyboardTarget::enter(
|
|
|
|
|
&windows[active],
|
|
|
|
|
seat,
|
|
|
|
|
data,
|
|
|
|
|
Vec::new(), /* TODO */
|
|
|
|
|
serial,
|
|
|
|
|
)
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
active
|
|
|
|
|
})
|
2022-11-03 18:51:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn pointer_leave_if_previous(
|
|
|
|
|
&self,
|
|
|
|
|
seat: &Seat<State>,
|
|
|
|
|
data: &mut State,
|
|
|
|
|
serial: Serial,
|
|
|
|
|
time: u32,
|
|
|
|
|
location: Point<f64, Logical>,
|
|
|
|
|
) -> usize {
|
2023-01-16 15:12:25 +01:00
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
let active = p.active.load(Ordering::SeqCst);
|
|
|
|
|
let previous = p.previous_pointer.swap(active, Ordering::SeqCst);
|
|
|
|
|
if previous != active {
|
2023-06-08 13:19:30 +02:00
|
|
|
let windows = p.windows.lock().unwrap();
|
|
|
|
|
if let Some(previous) = windows.get(previous) {
|
|
|
|
|
if let Some(sessions) = previous.user_data().get::<ScreencopySessions>() {
|
|
|
|
|
for session in &*sessions.0.borrow() {
|
|
|
|
|
session.cursor_leave(seat, InputType::Pointer)
|
|
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
2023-06-08 13:19:30 +02:00
|
|
|
PointerTarget::leave(previous, seat, data, serial, time);
|
2022-11-03 18:51:27 +01:00
|
|
|
}
|
2023-06-08 13:19:30 +02:00
|
|
|
|
|
|
|
|
if let Some(sessions) = windows[active].user_data().get::<ScreencopySessions>() {
|
2023-01-16 15:12:25 +01:00
|
|
|
for session in &*sessions.0.borrow() {
|
|
|
|
|
session.cursor_enter(seat, InputType::Pointer)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
PointerTarget::enter(
|
2023-06-08 13:19:30 +02:00
|
|
|
&windows[active],
|
2023-01-16 15:12:25 +01:00
|
|
|
seat,
|
|
|
|
|
data,
|
|
|
|
|
&MotionEvent {
|
|
|
|
|
location,
|
|
|
|
|
serial,
|
|
|
|
|
time,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
active
|
|
|
|
|
})
|
|
|
|
|
}
|
2023-06-05 17:52:47 +02:00
|
|
|
|
2023-06-14 17:29:08 +02:00
|
|
|
pub(in super::super) fn focus_stack(&self) {
|
|
|
|
|
self.0
|
|
|
|
|
.with_program(|p| p.group_focused.store(true, Ordering::SeqCst));
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-29 21:33:16 +02:00
|
|
|
pub(in super::super) fn loop_handle(&self) -> LoopHandle<'static, crate::state::State> {
|
2023-06-05 17:52:47 +02:00
|
|
|
self.0.loop_handle()
|
|
|
|
|
}
|
2023-07-13 17:19:29 +02:00
|
|
|
|
|
|
|
|
pub fn split_render_elements<R, C>(
|
|
|
|
|
&self,
|
|
|
|
|
renderer: &mut R,
|
|
|
|
|
location: smithay::utils::Point<i32, smithay::utils::Physical>,
|
|
|
|
|
scale: smithay::utils::Scale<f64>,
|
|
|
|
|
alpha: f32,
|
|
|
|
|
) -> (Vec<C>, Vec<C>)
|
|
|
|
|
where
|
|
|
|
|
R: Renderer + ImportAll + ImportMem,
|
|
|
|
|
<R as Renderer>::TextureId: 'static,
|
|
|
|
|
C: From<CosmicStackRenderElement<R>>,
|
|
|
|
|
{
|
|
|
|
|
let stack_loc = location
|
|
|
|
|
+ self
|
|
|
|
|
.0
|
|
|
|
|
.with_program(|p| {
|
|
|
|
|
p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]
|
|
|
|
|
.geometry()
|
|
|
|
|
.loc
|
|
|
|
|
})
|
|
|
|
|
.to_physical_precise_round(scale);
|
|
|
|
|
let window_loc = location + Point::from((0, (TAB_HEIGHT as f64 * scale.y) as i32));
|
|
|
|
|
|
|
|
|
|
let elements = AsRenderElements::<R>::render_elements::<CosmicStackRenderElement<R>>(
|
|
|
|
|
&self.0, renderer, stack_loc, scale, alpha,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let (window_elements, popup_elements) = self.0.with_program(|p| {
|
|
|
|
|
p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]
|
|
|
|
|
.split_render_elements::<R, CosmicStackRenderElement<R>>(
|
|
|
|
|
renderer, window_loc, scale, alpha,
|
|
|
|
|
)
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
(
|
|
|
|
|
elements
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(C::from)
|
|
|
|
|
.chain(window_elements.into_iter().map(C::from))
|
|
|
|
|
.collect(),
|
|
|
|
|
popup_elements.into_iter().map(C::from).collect(),
|
|
|
|
|
)
|
|
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
|
2023-06-08 21:50:25 +02:00
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
|
pub enum Message {
|
|
|
|
|
DragStart,
|
2023-07-28 19:18:14 +02:00
|
|
|
PotentialTabDragStart(usize),
|
2023-06-22 20:58:39 +02:00
|
|
|
Activate(usize),
|
2023-06-08 21:50:25 +02:00
|
|
|
Close(usize),
|
2023-06-22 20:58:39 +02:00
|
|
|
ScrollForward,
|
2023-06-13 18:32:04 +02:00
|
|
|
ScrollBack,
|
2023-06-22 20:58:39 +02:00
|
|
|
Scrolled,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TabMessage for Message {
|
|
|
|
|
fn activate(idx: usize) -> Self {
|
|
|
|
|
Message::Activate(idx)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn is_activate(&self) -> Option<usize> {
|
|
|
|
|
match self {
|
|
|
|
|
Message::Activate(idx) => Some(*idx),
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn scroll_back() -> Self {
|
|
|
|
|
Message::ScrollBack
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn scroll_further() -> Self {
|
|
|
|
|
Message::ScrollForward
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn populate_scroll(&mut self, mut current_offset: AbsoluteOffset) -> Option<AbsoluteOffset> {
|
|
|
|
|
match self {
|
|
|
|
|
Message::ScrollBack => Some({
|
|
|
|
|
current_offset.x -= 10.;
|
|
|
|
|
current_offset
|
|
|
|
|
}),
|
|
|
|
|
Message::ScrollForward => Some({
|
|
|
|
|
current_offset.x += 10.;
|
|
|
|
|
current_offset
|
|
|
|
|
}),
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn scrolled() -> Self {
|
|
|
|
|
Message::Scrolled
|
|
|
|
|
}
|
2023-06-08 21:50:25 +02:00
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
impl Program for CosmicStackInternal {
|
2023-06-08 21:50:25 +02:00
|
|
|
type Message = Message;
|
|
|
|
|
|
|
|
|
|
fn update(
|
|
|
|
|
&mut self,
|
|
|
|
|
message: Self::Message,
|
2023-09-29 21:33:16 +02:00
|
|
|
loop_handle: &LoopHandle<'static, crate::state::State>,
|
2023-06-08 21:50:25 +02:00
|
|
|
) -> Command<Self::Message> {
|
|
|
|
|
match message {
|
|
|
|
|
Message::DragStart => {
|
|
|
|
|
if let Some((seat, serial)) = self.last_seat.lock().unwrap().clone() {
|
|
|
|
|
if let Some(surface) = self.windows.lock().unwrap()
|
|
|
|
|
[self.active.load(Ordering::SeqCst)]
|
|
|
|
|
.wl_surface()
|
|
|
|
|
{
|
2023-09-29 21:33:16 +02:00
|
|
|
loop_handle.insert_idle(move |state| {
|
|
|
|
|
Shell::move_request(state, &surface, &seat, serial);
|
2023-06-08 21:50:25 +02:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-07-28 19:18:14 +02:00
|
|
|
Message::PotentialTabDragStart(idx) => {
|
|
|
|
|
*self.potential_drag.lock().unwrap() = Some(idx);
|
|
|
|
|
}
|
2023-06-22 20:58:39 +02:00
|
|
|
Message::Activate(idx) => {
|
2023-07-28 19:18:14 +02:00
|
|
|
*self.potential_drag.lock().unwrap() = None;
|
2023-06-08 21:50:25 +02:00
|
|
|
if self.windows.lock().unwrap().get(idx).is_some() {
|
|
|
|
|
let old = self.active.swap(idx, Ordering::SeqCst);
|
|
|
|
|
self.previous_keyboard.store(old, Ordering::SeqCst);
|
|
|
|
|
self.previous_pointer.store(old, Ordering::SeqCst);
|
2023-06-22 20:58:39 +02:00
|
|
|
self.scroll_to_focus.store(true, Ordering::SeqCst);
|
2023-06-13 18:32:04 +02:00
|
|
|
}
|
2023-06-08 21:50:25 +02:00
|
|
|
}
|
|
|
|
|
Message::Close(idx) => {
|
|
|
|
|
if let Some(val) = self.windows.lock().unwrap().get(idx) {
|
|
|
|
|
val.close()
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-06-22 20:58:39 +02:00
|
|
|
Message::Scrolled => {
|
|
|
|
|
self.scroll_to_focus.store(false, Ordering::SeqCst);
|
2023-06-13 18:32:04 +02:00
|
|
|
}
|
2023-06-22 20:58:39 +02:00
|
|
|
_ => unreachable!(),
|
2023-06-08 21:50:25 +02:00
|
|
|
}
|
|
|
|
|
Command::none()
|
|
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
|
2023-06-08 13:19:30 +02:00
|
|
|
fn view(&self) -> CosmicElement<'_, Self::Message> {
|
|
|
|
|
let windows = self.windows.lock().unwrap();
|
2023-09-12 17:48:13 +02:00
|
|
|
if self.geometry.lock().unwrap().is_none() {
|
2023-06-08 13:19:30 +02:00
|
|
|
return iced_widget::row(Vec::new()).into();
|
|
|
|
|
};
|
|
|
|
|
let active = self.active.load(Ordering::SeqCst);
|
|
|
|
|
let group_focused = self.group_focused.load(Ordering::SeqCst);
|
|
|
|
|
|
2023-06-22 20:58:39 +02:00
|
|
|
let elements = vec![
|
|
|
|
|
cosmic_widget::icon("window-stack-symbolic", 16)
|
|
|
|
|
.force_svg(true)
|
|
|
|
|
.style(if group_focused {
|
|
|
|
|
theme::Svg::custom(|theme| iced_widget::svg::Appearance {
|
|
|
|
|
color: Some(if theme.cosmic().is_dark {
|
|
|
|
|
Color::BLACK
|
2023-06-08 13:19:30 +02:00
|
|
|
} else {
|
2023-06-22 20:58:39 +02:00
|
|
|
Color::WHITE
|
|
|
|
|
}),
|
2023-06-08 13:19:30 +02:00
|
|
|
})
|
2023-06-22 20:58:39 +02:00
|
|
|
} else {
|
|
|
|
|
theme::Svg::Symbolic
|
|
|
|
|
})
|
|
|
|
|
.apply(iced_widget::container)
|
|
|
|
|
.padding([4, 24])
|
|
|
|
|
.center_y()
|
|
|
|
|
.apply(iced_widget::mouse_area)
|
|
|
|
|
.on_press(Message::DragStart)
|
2023-06-08 13:19:30 +02:00
|
|
|
.into(),
|
2023-06-22 20:58:39 +02:00
|
|
|
CosmicElement::new(
|
|
|
|
|
Tabs::new(
|
2023-06-26 21:05:31 +02:00
|
|
|
windows.iter().enumerate().map(|(i, w)| {
|
|
|
|
|
let user_data = w.user_data();
|
|
|
|
|
user_data.insert_if_missing(Id::unique);
|
|
|
|
|
Tab::new(
|
|
|
|
|
w.title(),
|
|
|
|
|
w.app_id(),
|
|
|
|
|
user_data.get::<Id>().unwrap().clone(),
|
|
|
|
|
)
|
2023-07-28 19:18:14 +02:00
|
|
|
.on_press(Message::PotentialTabDragStart(i))
|
2023-06-26 21:05:31 +02:00
|
|
|
.on_close(Message::Close(i))
|
|
|
|
|
}),
|
2023-06-22 20:58:39 +02:00
|
|
|
active,
|
|
|
|
|
windows[active].is_activated(false),
|
|
|
|
|
group_focused,
|
|
|
|
|
)
|
|
|
|
|
.id(SCROLLABLE_ID.clone())
|
|
|
|
|
.force_visible(
|
|
|
|
|
self.scroll_to_focus
|
|
|
|
|
.load(Ordering::SeqCst)
|
|
|
|
|
.then_some(active),
|
|
|
|
|
)
|
|
|
|
|
.height(Length::Fill)
|
|
|
|
|
.width(Length::Fill),
|
|
|
|
|
),
|
2023-07-26 17:13:22 +02:00
|
|
|
iced_widget::horizontal_space(0)
|
|
|
|
|
.apply(iced_widget::container)
|
|
|
|
|
.padding([64, 24])
|
2023-06-08 21:50:25 +02:00
|
|
|
.apply(iced_widget::mouse_area)
|
|
|
|
|
.on_press(Message::DragStart)
|
|
|
|
|
.into(),
|
2023-06-22 20:58:39 +02:00
|
|
|
];
|
2023-06-08 13:19:30 +02:00
|
|
|
|
|
|
|
|
iced_widget::row(elements)
|
|
|
|
|
.height(TAB_HEIGHT as u16)
|
2023-09-12 17:48:13 +02:00
|
|
|
.width(Length::Fill) //width as u16)
|
2023-06-08 13:19:30 +02:00
|
|
|
.apply(iced_widget::container)
|
|
|
|
|
.center_y()
|
2023-06-12 17:25:28 +02:00
|
|
|
.style(if self.group_focused.load(Ordering::SeqCst) {
|
|
|
|
|
theme::Container::custom(|theme| iced_widget::container::Appearance {
|
|
|
|
|
text_color: Some(Color::from(theme.cosmic().background.on)),
|
|
|
|
|
background: Some(Background::Color(theme.cosmic().accent_color().into())),
|
|
|
|
|
border_radius: BorderRadius::from([8.0, 8.0, 0.0, 0.0]),
|
|
|
|
|
border_width: 0.0,
|
|
|
|
|
border_color: Color::TRANSPARENT,
|
|
|
|
|
})
|
|
|
|
|
} else {
|
|
|
|
|
theme::Container::custom(|theme| iced_widget::container::Appearance {
|
|
|
|
|
text_color: Some(Color::from(theme.cosmic().background.on)),
|
|
|
|
|
background: Some(Background::Color(theme.cosmic().palette.neutral_3.into())),
|
|
|
|
|
border_radius: BorderRadius::from([8.0, 8.0, 0.0, 0.0]),
|
|
|
|
|
border_width: 0.0,
|
|
|
|
|
border_color: Color::TRANSPARENT,
|
|
|
|
|
})
|
|
|
|
|
})
|
2023-06-08 13:19:30 +02:00
|
|
|
.into()
|
2022-11-03 18:51:27 +01:00
|
|
|
}
|
2023-05-31 20:02:39 +02:00
|
|
|
|
2023-06-08 13:19:30 +02:00
|
|
|
fn foreground(
|
|
|
|
|
&self,
|
|
|
|
|
pixels: &mut tiny_skia::PixmapMut<'_>,
|
|
|
|
|
damage: &[Rectangle<i32, smithay::utils::Buffer>],
|
|
|
|
|
scale: f32,
|
|
|
|
|
) {
|
|
|
|
|
if self.group_focused.load(Ordering::SeqCst) {
|
|
|
|
|
let border = Rectangle::from_loc_and_size(
|
2023-08-31 18:07:45 +02:00
|
|
|
(0, ((TAB_HEIGHT as f32 * scale) - scale).floor() as i32),
|
|
|
|
|
(pixels.width() as i32, scale.ceil() as i32),
|
2023-06-08 13:19:30 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let mut paint = tiny_skia::Paint::default();
|
|
|
|
|
let (b, g, r, a) = theme::COSMIC_DARK.accent_color().into_components();
|
|
|
|
|
paint.set_color(tiny_skia::Color::from_rgba(r, g, b, a).unwrap());
|
|
|
|
|
|
|
|
|
|
for rect in damage {
|
|
|
|
|
if let Some(overlap) = rect.intersection(border) {
|
|
|
|
|
pixels.fill_rect(
|
|
|
|
|
tiny_skia::Rect::from_xywh(
|
|
|
|
|
overlap.loc.x as f32,
|
|
|
|
|
overlap.loc.y as f32,
|
|
|
|
|
overlap.size.w as f32,
|
|
|
|
|
overlap.size.h as f32,
|
|
|
|
|
)
|
|
|
|
|
.unwrap(),
|
|
|
|
|
&paint,
|
|
|
|
|
Default::default(),
|
2023-06-12 17:25:28 +02:00
|
|
|
None,
|
2023-06-08 13:19:30 +02:00
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-05-31 20:02:39 +02:00
|
|
|
}
|
|
|
|
|
}
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl IsAlive for CosmicStack {
|
|
|
|
|
fn alive(&self) -> bool {
|
2023-07-28 19:18:14 +02:00
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
p.override_alive.load(Ordering::SeqCst)
|
|
|
|
|
&& p.windows.lock().unwrap().iter().any(IsAlive::alive)
|
|
|
|
|
})
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl SpaceElement for CosmicStack {
|
|
|
|
|
fn bbox(&self) -> Rectangle<i32, Logical> {
|
2023-01-16 15:12:25 +01:00
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
let mut bbox =
|
|
|
|
|
SpaceElement::bbox(&p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]);
|
|
|
|
|
bbox.size.h += TAB_HEIGHT;
|
|
|
|
|
bbox
|
|
|
|
|
})
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
fn is_in_input_region(&self, point: &Point<f64, Logical>) -> bool {
|
2023-01-16 15:12:25 +01:00
|
|
|
let mut point = *point;
|
|
|
|
|
if point.y < TAB_HEIGHT as f64 {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
point.y -= TAB_HEIGHT as f64;
|
|
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
SpaceElement::is_in_input_region(
|
|
|
|
|
&p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)],
|
|
|
|
|
&point,
|
|
|
|
|
)
|
|
|
|
|
})
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
fn set_activate(&self, activated: bool) {
|
2023-01-16 15:12:25 +01:00
|
|
|
SpaceElement::set_activate(&self.0, activated);
|
2023-06-08 13:19:30 +02:00
|
|
|
self.0.force_redraw();
|
2023-01-16 15:12:25 +01:00
|
|
|
self.0.with_program(|p| {
|
2023-06-08 13:19:30 +02:00
|
|
|
p.activated.store(activated, Ordering::SeqCst);
|
|
|
|
|
if !p.group_focused.load(Ordering::SeqCst) {
|
|
|
|
|
p.windows
|
|
|
|
|
.lock()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.iter()
|
|
|
|
|
.for_each(|w| SpaceElement::set_activate(w, activated))
|
|
|
|
|
}
|
|
|
|
|
});
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
fn output_enter(&self, output: &Output, overlap: Rectangle<i32, Logical>) {
|
2023-01-16 15:12:25 +01:00
|
|
|
SpaceElement::output_enter(&self.0, output, overlap);
|
|
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
p.windows
|
|
|
|
|
.lock()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.iter()
|
|
|
|
|
.for_each(|w| SpaceElement::output_enter(w, output, overlap))
|
|
|
|
|
})
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
fn output_leave(&self, output: &Output) {
|
2023-01-16 15:12:25 +01:00
|
|
|
SpaceElement::output_leave(&self.0, output);
|
|
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
p.windows
|
|
|
|
|
.lock()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.iter()
|
|
|
|
|
.for_each(|w| SpaceElement::output_leave(w, output))
|
|
|
|
|
})
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
fn geometry(&self) -> Rectangle<i32, Logical> {
|
2023-01-16 15:12:25 +01:00
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
let mut geo =
|
|
|
|
|
SpaceElement::geometry(&p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]);
|
|
|
|
|
geo.size.h += TAB_HEIGHT;
|
|
|
|
|
geo
|
|
|
|
|
})
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
fn z_index(&self) -> u8 {
|
2023-01-16 15:12:25 +01:00
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
SpaceElement::z_index(&p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)])
|
|
|
|
|
})
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
fn refresh(&self) {
|
2023-06-08 13:19:30 +02:00
|
|
|
SpaceElement::refresh(&self.0);
|
2023-01-16 15:12:25 +01:00
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
let mut windows = p.windows.lock().unwrap();
|
2023-06-05 17:52:47 +02:00
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
let len = windows.len();
|
|
|
|
|
let _ = p
|
|
|
|
|
.active
|
|
|
|
|
.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |active| {
|
2023-06-05 17:52:47 +02:00
|
|
|
(active >= len).then_some(len - 1)
|
2023-01-16 15:12:25 +01:00
|
|
|
});
|
2023-06-08 13:19:30 +02:00
|
|
|
windows.iter().for_each(|w| SpaceElement::refresh(w));
|
|
|
|
|
});
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl KeyboardTarget<State> for CosmicStack {
|
|
|
|
|
fn enter(
|
|
|
|
|
&self,
|
|
|
|
|
seat: &Seat<State>,
|
|
|
|
|
data: &mut State,
|
|
|
|
|
keys: Vec<KeysymHandle<'_>>,
|
|
|
|
|
serial: Serial,
|
|
|
|
|
) {
|
2023-01-16 15:12:25 +01:00
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
let active = p.active.load(Ordering::SeqCst);
|
|
|
|
|
p.previous_keyboard.store(active, Ordering::SeqCst);
|
|
|
|
|
KeyboardTarget::enter(
|
|
|
|
|
&p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)],
|
|
|
|
|
seat,
|
|
|
|
|
data,
|
|
|
|
|
keys,
|
|
|
|
|
serial,
|
|
|
|
|
)
|
|
|
|
|
})
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial) {
|
2022-11-03 18:51:27 +01:00
|
|
|
let active = self.keyboard_leave_if_previous(seat, data, serial);
|
2023-06-08 13:19:30 +02:00
|
|
|
self.0.force_redraw();
|
2023-01-16 15:12:25 +01:00
|
|
|
self.0.with_program(|p| {
|
2023-06-08 13:19:30 +02:00
|
|
|
p.group_focused.store(false, Ordering::SeqCst);
|
2023-01-16 15:12:25 +01:00
|
|
|
KeyboardTarget::leave(&p.windows.lock().unwrap()[active], seat, data, serial)
|
|
|
|
|
})
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
fn key(
|
|
|
|
|
&self,
|
|
|
|
|
seat: &Seat<State>,
|
|
|
|
|
data: &mut State,
|
|
|
|
|
key: KeysymHandle<'_>,
|
|
|
|
|
state: KeyState,
|
|
|
|
|
serial: Serial,
|
|
|
|
|
time: u32,
|
|
|
|
|
) {
|
2022-11-03 18:51:27 +01:00
|
|
|
let active = self.keyboard_leave_if_previous(seat, data, serial);
|
2023-01-16 15:12:25 +01:00
|
|
|
self.0.with_program(|p| {
|
2023-06-08 13:19:30 +02:00
|
|
|
if !p.group_focused.load(Ordering::SeqCst) {
|
|
|
|
|
KeyboardTarget::key(
|
|
|
|
|
&p.windows.lock().unwrap()[active],
|
|
|
|
|
seat,
|
|
|
|
|
data,
|
|
|
|
|
key,
|
|
|
|
|
state,
|
|
|
|
|
serial,
|
|
|
|
|
time,
|
|
|
|
|
)
|
|
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
})
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
fn modifiers(
|
|
|
|
|
&self,
|
|
|
|
|
seat: &Seat<State>,
|
|
|
|
|
data: &mut State,
|
|
|
|
|
modifiers: ModifiersState,
|
|
|
|
|
serial: Serial,
|
|
|
|
|
) {
|
2022-11-03 18:51:27 +01:00
|
|
|
let active = self.keyboard_leave_if_previous(seat, data, serial);
|
2023-01-16 15:12:25 +01:00
|
|
|
self.0.with_program(|p| {
|
2023-06-08 13:19:30 +02:00
|
|
|
if !p.group_focused.load(Ordering::SeqCst) {
|
|
|
|
|
KeyboardTarget::modifiers(
|
|
|
|
|
&p.windows.lock().unwrap()[active],
|
|
|
|
|
seat,
|
|
|
|
|
data,
|
|
|
|
|
modifiers,
|
|
|
|
|
serial,
|
|
|
|
|
)
|
|
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
})
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl PointerTarget<State> for CosmicStack {
|
|
|
|
|
fn enter(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) {
|
2023-06-08 21:50:25 +02:00
|
|
|
let mut event = event.clone();
|
|
|
|
|
event.location.y -= TAB_HEIGHT as f64;
|
2023-01-16 15:12:25 +01:00
|
|
|
if self.0.with_program(|p| {
|
2023-06-08 21:50:25 +02:00
|
|
|
let active_window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)];
|
|
|
|
|
if let Some(sessions) = active_window.user_data().get::<ScreencopySessions>() {
|
2023-01-16 15:12:25 +01:00
|
|
|
for session in &*sessions.0.borrow() {
|
|
|
|
|
session.cursor_enter(seat, InputType::Pointer)
|
|
|
|
|
}
|
2022-11-03 18:51:27 +01:00
|
|
|
}
|
|
|
|
|
|
2023-06-08 21:50:25 +02:00
|
|
|
if (event.location.y - active_window.geometry().loc.y as f64) < 0. {
|
|
|
|
|
let previous = p.swap_focus(Focus::Header);
|
|
|
|
|
if previous == Focus::Window {
|
|
|
|
|
PointerTarget::leave(active_window, seat, data, event.serial, event.time);
|
|
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
true
|
|
|
|
|
} else {
|
2023-06-08 21:50:25 +02:00
|
|
|
p.swap_focus(Focus::Window);
|
2022-11-03 18:51:27 +01:00
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
*p.last_location.lock().unwrap() = Some((event.location, event.serial, event.time));
|
|
|
|
|
let active = p.active.load(Ordering::SeqCst);
|
|
|
|
|
p.previous_pointer.store(active, Ordering::SeqCst);
|
|
|
|
|
|
2023-06-08 21:50:25 +02:00
|
|
|
PointerTarget::enter(active_window, seat, data, &event);
|
2023-01-16 15:12:25 +01:00
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}) {
|
2023-06-08 21:50:25 +02:00
|
|
|
event.location.y += TAB_HEIGHT as f64;
|
|
|
|
|
event.location -= self.0.with_program(|p| {
|
|
|
|
|
p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]
|
|
|
|
|
.geometry()
|
|
|
|
|
.loc
|
|
|
|
|
.to_f64()
|
|
|
|
|
});
|
|
|
|
|
PointerTarget::enter(&self.0, seat, data, &event)
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
|
2022-09-28 12:01:29 +02:00
|
|
|
fn motion(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) {
|
2023-06-08 21:50:25 +02:00
|
|
|
let mut event = event.clone();
|
|
|
|
|
event.location.y -= TAB_HEIGHT as f64;
|
2022-11-03 18:51:27 +01:00
|
|
|
let active =
|
|
|
|
|
self.pointer_leave_if_previous(seat, data, event.serial, event.time, event.location);
|
2023-07-28 19:18:14 +02:00
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
if let Some((previous, next)) = self.0.with_program(|p| {
|
2023-06-08 21:50:25 +02:00
|
|
|
let active_window = &p.windows.lock().unwrap()[active];
|
|
|
|
|
if let Some(sessions) = active_window.user_data().get::<ScreencopySessions>() {
|
2023-01-16 15:12:25 +01:00
|
|
|
for session in &*sessions.0.borrow() {
|
|
|
|
|
let buffer_loc = (event.location.x, event.location.y); // we always screencast windows at 1x1 scale
|
|
|
|
|
if let Some((geo, hotspot)) =
|
|
|
|
|
seat.cursor_geometry(buffer_loc, data.common.clock.now())
|
|
|
|
|
{
|
|
|
|
|
session.cursor_info(seat, InputType::Pointer, geo, hotspot);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-03 18:51:27 +01:00
|
|
|
|
2023-06-08 21:50:25 +02:00
|
|
|
if (event.location.y - active_window.geometry().loc.y as f64) < 0. {
|
2023-01-16 15:12:25 +01:00
|
|
|
let previous = p.swap_focus(Focus::Header);
|
|
|
|
|
if previous == Focus::Window {
|
2023-06-08 21:50:25 +02:00
|
|
|
PointerTarget::leave(active_window, seat, data, event.serial, event.time);
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
Some((previous, Focus::Header))
|
|
|
|
|
} else {
|
2023-06-08 21:50:25 +02:00
|
|
|
*p.last_location.lock().unwrap() = Some((event.location, event.serial, event.time));
|
2023-01-16 15:12:25 +01:00
|
|
|
|
|
|
|
|
let previous = p.swap_focus(Focus::Window);
|
|
|
|
|
if previous != Focus::Window {
|
2023-06-08 21:50:25 +02:00
|
|
|
PointerTarget::enter(active_window, seat, data, &event);
|
2023-01-16 15:12:25 +01:00
|
|
|
} else {
|
2023-06-08 21:50:25 +02:00
|
|
|
PointerTarget::motion(active_window, seat, data, &event);
|
2022-11-03 18:51:27 +01:00
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
|
|
|
|
|
Some((previous, Focus::Window))
|
|
|
|
|
}
|
|
|
|
|
}) {
|
2023-06-08 21:50:25 +02:00
|
|
|
event.location.y += TAB_HEIGHT as f64;
|
|
|
|
|
event.location -= self
|
|
|
|
|
.0
|
|
|
|
|
.with_program(|p| p.windows.lock().unwrap()[active].geometry().loc.to_f64());
|
2023-01-16 15:12:25 +01:00
|
|
|
match (previous, next) {
|
2023-06-08 21:50:25 +02:00
|
|
|
(Focus::Header, Focus::Header) => {
|
|
|
|
|
PointerTarget::motion(&self.0, seat, data, &event)
|
|
|
|
|
}
|
|
|
|
|
(_, Focus::Header) => PointerTarget::enter(&self.0, seat, data, &event),
|
2023-01-16 15:12:25 +01:00
|
|
|
(Focus::Header, _) => {
|
2023-07-28 19:18:14 +02:00
|
|
|
PointerTarget::leave(&self.0, seat, data, event.serial, event.time);
|
|
|
|
|
if let Some(dragged_out) = self
|
|
|
|
|
.0
|
|
|
|
|
.with_program(|p| p.potential_drag.lock().unwrap().take())
|
|
|
|
|
{
|
|
|
|
|
if let Some(surface) = self
|
|
|
|
|
.0
|
|
|
|
|
.with_program(|p| p.windows.lock().unwrap().get(dragged_out).cloned())
|
|
|
|
|
{
|
|
|
|
|
if let Some(stack_mapped) =
|
|
|
|
|
data.common.shell.element_for_surface(&surface)
|
|
|
|
|
{
|
|
|
|
|
if let Some(workspace) = data.common.shell.space_for(stack_mapped) {
|
|
|
|
|
// TODO: Unify this somehow with Shell::move_request/Workspace::move_request
|
|
|
|
|
let button = 0x110; // BTN_LEFT
|
|
|
|
|
let pos = event.location;
|
|
|
|
|
let start_data = PointerGrabStartData {
|
|
|
|
|
focus: None,
|
|
|
|
|
button,
|
|
|
|
|
location: pos,
|
|
|
|
|
};
|
|
|
|
|
let mapped = CosmicMapped::from(CosmicWindow::new(
|
|
|
|
|
surface,
|
|
|
|
|
self.0.loop_handle(),
|
|
|
|
|
));
|
|
|
|
|
let elem_geo =
|
|
|
|
|
workspace.element_geometry(stack_mapped).unwrap();
|
|
|
|
|
let indicator_thickness =
|
|
|
|
|
data.common.config.static_conf.active_hint;
|
|
|
|
|
let was_tiled = workspace.is_tiled(stack_mapped);
|
|
|
|
|
|
|
|
|
|
self.remove_idx(dragged_out);
|
|
|
|
|
mapped.configure();
|
|
|
|
|
|
|
|
|
|
let grab = MoveGrab::new(
|
|
|
|
|
start_data,
|
|
|
|
|
mapped,
|
|
|
|
|
seat,
|
|
|
|
|
pos,
|
|
|
|
|
pos.to_i32_round() - Point::from((elem_geo.size.w / 2, 24)),
|
|
|
|
|
indicator_thickness,
|
|
|
|
|
was_tiled,
|
|
|
|
|
);
|
|
|
|
|
if grab.is_tiling_grab() {
|
2023-08-11 18:15:22 +02:00
|
|
|
data.common.shell.set_overview_mode(
|
|
|
|
|
Some(Trigger::Pointer(button)),
|
|
|
|
|
data.common.event_loop_handle.clone(),
|
|
|
|
|
);
|
2023-07-28 19:18:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let seat = seat.clone();
|
2023-09-29 21:33:16 +02:00
|
|
|
data.common.event_loop_handle.insert_idle(move |state| {
|
2023-07-28 19:18:14 +02:00
|
|
|
seat.get_pointer().unwrap().set_grab(
|
2023-09-29 21:33:16 +02:00
|
|
|
state,
|
2023-07-28 19:18:14 +02:00
|
|
|
grab,
|
|
|
|
|
event.serial,
|
|
|
|
|
smithay::input::pointer::Focus::Clear,
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
_ => {}
|
2022-11-03 18:51:27 +01:00
|
|
|
}
|
|
|
|
|
}
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
|
2023-01-30 23:19:36 +01:00
|
|
|
fn relative_motion(&self, seat: &Seat<State>, data: &mut State, event: &RelativeMotionEvent) {
|
|
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
if p.current_focus() == Focus::Window {
|
|
|
|
|
let window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)];
|
|
|
|
|
window.relative_motion(seat, data, event)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-28 12:01:29 +02:00
|
|
|
fn button(&self, seat: &Seat<State>, data: &mut State, event: &ButtonEvent) {
|
2023-01-16 15:12:25 +01:00
|
|
|
if let Some((location, _serial, _time)) = self
|
|
|
|
|
.0
|
|
|
|
|
.with_program(|p| p.last_location.lock().unwrap().clone())
|
|
|
|
|
{
|
2022-11-03 18:51:27 +01:00
|
|
|
self.pointer_leave_if_previous(seat, data, event.serial, event.time, location);
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
match self.0.with_program(|p| p.current_focus()) {
|
2023-06-08 21:50:25 +02:00
|
|
|
Focus::Header => {
|
|
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
*p.last_seat.lock().unwrap() = Some((seat.clone(), event.serial));
|
|
|
|
|
});
|
|
|
|
|
PointerTarget::button(&self.0, seat, data, event)
|
|
|
|
|
}
|
2023-06-08 13:19:30 +02:00
|
|
|
Focus::Window => {
|
|
|
|
|
if self.0.with_program(|p| {
|
|
|
|
|
PointerTarget::button(
|
|
|
|
|
&p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)],
|
|
|
|
|
seat,
|
|
|
|
|
data,
|
|
|
|
|
event,
|
|
|
|
|
);
|
|
|
|
|
if p.group_focused.swap(false, Ordering::SeqCst) {
|
|
|
|
|
p.windows.lock().unwrap().iter().for_each(|w| {
|
|
|
|
|
SpaceElement::set_activate(w, true);
|
|
|
|
|
w.send_configure();
|
|
|
|
|
});
|
|
|
|
|
true
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}) {
|
|
|
|
|
self.0.force_redraw();
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
_ => {}
|
|
|
|
|
}
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
|
2022-09-28 12:01:29 +02:00
|
|
|
fn axis(&self, seat: &Seat<State>, data: &mut State, frame: AxisFrame) {
|
2023-01-16 15:12:25 +01:00
|
|
|
if let Some((location, serial, time)) = self
|
|
|
|
|
.0
|
|
|
|
|
.with_program(|p| p.last_location.lock().unwrap().clone())
|
|
|
|
|
{
|
2022-11-03 18:51:27 +01:00
|
|
|
self.pointer_leave_if_previous(seat, data, serial, time, location);
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
match self.0.with_program(|p| p.current_focus()) {
|
|
|
|
|
Focus::Header => PointerTarget::axis(&self.0, seat, data, frame),
|
|
|
|
|
Focus::Window => self.0.with_program(|p| {
|
|
|
|
|
PointerTarget::axis(
|
|
|
|
|
&p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)],
|
|
|
|
|
seat,
|
|
|
|
|
data,
|
|
|
|
|
frame,
|
|
|
|
|
)
|
|
|
|
|
}),
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
|
2023-09-13 20:52:10 -07:00
|
|
|
fn frame(&self, seat: &Seat<State>, data: &mut State) {
|
|
|
|
|
if let Some((location, serial, time)) = self
|
|
|
|
|
.0
|
|
|
|
|
.with_program(|p| p.last_location.lock().unwrap().clone())
|
|
|
|
|
{
|
|
|
|
|
self.pointer_leave_if_previous(seat, data, serial, time, location);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
match self.0.with_program(|p| p.current_focus()) {
|
|
|
|
|
Focus::Header => PointerTarget::frame(&self.0, seat, data),
|
|
|
|
|
Focus::Window => self.0.with_program(|p| {
|
|
|
|
|
PointerTarget::frame(
|
|
|
|
|
&p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)],
|
|
|
|
|
seat,
|
|
|
|
|
data,
|
|
|
|
|
)
|
|
|
|
|
}),
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-28 12:01:29 +02:00
|
|
|
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: u32) {
|
2023-01-16 15:12:25 +01:00
|
|
|
if let Some((location, serial, time)) = self
|
|
|
|
|
.0
|
|
|
|
|
.with_program(|p| p.last_location.lock().unwrap().clone())
|
|
|
|
|
{
|
2022-11-03 18:51:27 +01:00
|
|
|
self.pointer_leave_if_previous(seat, data, serial, time, location);
|
|
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
|
|
|
|
|
let previous = self.0.with_program(|p| {
|
|
|
|
|
if let Some(sessions) = p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]
|
|
|
|
|
.user_data()
|
|
|
|
|
.get::<ScreencopySessions>()
|
|
|
|
|
{
|
|
|
|
|
for session in &*sessions.0.borrow() {
|
|
|
|
|
session.cursor_leave(seat, InputType::Pointer)
|
|
|
|
|
}
|
2022-11-03 18:51:27 +01:00
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
p.swap_focus(Focus::None)
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
match previous {
|
|
|
|
|
Focus::Header => PointerTarget::leave(&self.0, seat, data, serial, time),
|
|
|
|
|
Focus::Window => self.0.with_program(|p| {
|
|
|
|
|
PointerTarget::leave(
|
|
|
|
|
&p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)],
|
|
|
|
|
seat,
|
|
|
|
|
data,
|
|
|
|
|
serial,
|
|
|
|
|
time,
|
|
|
|
|
)
|
|
|
|
|
}),
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
2023-09-05 10:55:23 -07:00
|
|
|
|
|
|
|
|
fn gesture_swipe_begin(
|
|
|
|
|
&self,
|
|
|
|
|
seat: &Seat<State>,
|
|
|
|
|
data: &mut State,
|
|
|
|
|
event: &GestureSwipeBeginEvent,
|
|
|
|
|
) {
|
|
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
if p.current_focus() == Focus::Window {
|
|
|
|
|
let window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)];
|
|
|
|
|
window.gesture_swipe_begin(seat, data, event)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn gesture_swipe_update(
|
|
|
|
|
&self,
|
|
|
|
|
seat: &Seat<State>,
|
|
|
|
|
data: &mut State,
|
|
|
|
|
event: &GestureSwipeUpdateEvent,
|
|
|
|
|
) {
|
|
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
if p.current_focus() == Focus::Window {
|
|
|
|
|
let window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)];
|
|
|
|
|
window.gesture_swipe_update(seat, data, event)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn gesture_swipe_end(
|
|
|
|
|
&self,
|
|
|
|
|
seat: &Seat<State>,
|
|
|
|
|
data: &mut State,
|
|
|
|
|
event: &GestureSwipeEndEvent,
|
|
|
|
|
) {
|
|
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
if p.current_focus() == Focus::Window {
|
|
|
|
|
let window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)];
|
|
|
|
|
window.gesture_swipe_end(seat, data, event)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn gesture_pinch_begin(
|
|
|
|
|
&self,
|
|
|
|
|
seat: &Seat<State>,
|
|
|
|
|
data: &mut State,
|
|
|
|
|
event: &GesturePinchBeginEvent,
|
|
|
|
|
) {
|
|
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
if p.current_focus() == Focus::Window {
|
|
|
|
|
let window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)];
|
|
|
|
|
window.gesture_pinch_begin(seat, data, event)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn gesture_pinch_update(
|
|
|
|
|
&self,
|
|
|
|
|
seat: &Seat<State>,
|
|
|
|
|
data: &mut State,
|
|
|
|
|
event: &GesturePinchUpdateEvent,
|
|
|
|
|
) {
|
|
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
if p.current_focus() == Focus::Window {
|
|
|
|
|
let window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)];
|
|
|
|
|
window.gesture_pinch_update(seat, data, event)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn gesture_pinch_end(
|
|
|
|
|
&self,
|
|
|
|
|
seat: &Seat<State>,
|
|
|
|
|
data: &mut State,
|
|
|
|
|
event: &GesturePinchEndEvent,
|
|
|
|
|
) {
|
|
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
if p.current_focus() == Focus::Window {
|
|
|
|
|
let window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)];
|
|
|
|
|
window.gesture_pinch_end(seat, data, event)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn gesture_hold_begin(
|
|
|
|
|
&self,
|
|
|
|
|
seat: &Seat<State>,
|
|
|
|
|
data: &mut State,
|
|
|
|
|
event: &GestureHoldBeginEvent,
|
|
|
|
|
) {
|
|
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
if p.current_focus() == Focus::Window {
|
|
|
|
|
let window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)];
|
|
|
|
|
window.gesture_hold_begin(seat, data, event)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn gesture_hold_end(&self, seat: &Seat<State>, data: &mut State, event: &GestureHoldEndEvent) {
|
|
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
if p.current_focus() == Focus::Window {
|
|
|
|
|
let window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)];
|
|
|
|
|
window.gesture_hold_end(seat, data, event)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
|
2023-06-08 21:50:16 +02:00
|
|
|
render_elements! {
|
|
|
|
|
pub CosmicStackRenderElement<R> where R: ImportAll + ImportMem;
|
|
|
|
|
Header = MemoryRenderBufferRenderElement<R>,
|
|
|
|
|
Window = WaylandSurfaceRenderElement<R>,
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|