cosmic-comp/src/shell/element/window.rs

781 lines
26 KiB
Rust
Raw Normal View History

2022-11-03 18:51:27 +01:00
use crate::{
shell::{grabs::ReleaseMode, Shell},
state::State,
utils::{
iced::{IcedElement, Program},
prelude::*,
},
wayland::handlers::screencopy::ScreencopySessions,
2022-11-03 18:51:27 +01:00
};
use calloop::LoopHandle;
2023-12-07 19:53:41 +00:00
use cosmic::{iced::Command, widget::mouse_area, Apply};
use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::InputType;
2022-09-28 12:01:29 +02:00
use smithay::{
backend::{
input::KeyState,
renderer::{
element::{
memory::MemoryRenderBufferRenderElement, surface::WaylandSurfaceRenderElement,
2023-06-08 21:50:16 +02:00
AsRenderElements,
},
ImportAll, ImportMem, Renderer,
2022-09-28 12:01:29 +02:00
},
},
desktop::space::SpaceElement,
2022-09-28 12:01:29 +02:00
input::{
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
pointer::{
AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent,
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent,
GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent,
PointerTarget, RelativeMotionEvent,
},
2022-09-28 12:01:29 +02:00
Seat,
},
output::Output,
reexports::wayland_server::protocol::wl_surface::WlSurface,
2023-06-08 21:50:16 +02:00
render_elements,
utils::{Buffer as BufferCoords, IsAlive, Logical, Point, Rectangle, Serial, Size},
2023-01-18 20:23:41 +01:00
wayland::seat::WaylandFocus,
2022-09-28 12:01:29 +02:00
};
use std::{
fmt,
2022-09-28 12:01:29 +02:00
hash::Hash,
sync::{
2023-06-26 16:59:39 +02:00
atomic::{AtomicBool, AtomicU8, Ordering},
2023-01-18 20:23:41 +01:00
Arc, Mutex,
},
2022-09-28 12:01:29 +02:00
};
use wayland_backend::server::ObjectId;
2022-09-28 12:01:29 +02:00
use super::{surface::SSD_HEIGHT, CosmicSurface};
2022-09-28 12:01:29 +02:00
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct CosmicWindow(IcedElement<CosmicWindowInternal>);
impl fmt::Debug for CosmicWindow {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2023-06-13 18:32:04 +02:00
f.debug_struct("CosmicWindow")
.field("internal", &self.0)
.finish_non_exhaustive()
2022-09-28 12:01:29 +02:00
}
}
2023-01-18 20:23:41 +01:00
#[derive(Clone)]
pub struct CosmicWindowInternal {
pub(super) window: CosmicSurface,
2023-05-31 20:02:39 +02:00
mask: Arc<Mutex<Option<tiny_skia::Mask>>>,
2023-06-26 16:59:39 +02:00
activated: Arc<AtomicBool>,
2023-01-18 20:23:41 +01:00
/// TODO: This needs to be per seat
pointer_entered: Arc<AtomicU8>,
2023-01-18 20:23:41 +01:00
last_seat: Arc<Mutex<Option<(Seat<State>, Serial)>>>,
2023-03-06 19:26:26 +01:00
last_title: Arc<Mutex<String>>,
2023-01-18 20:23:41 +01:00
}
impl fmt::Debug for CosmicWindowInternal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CosmicWindowInternal")
.field("window", &self.window)
2023-06-26 16:59:39 +02:00
.field("activated", &self.activated.load(Ordering::SeqCst))
2023-01-18 20:23:41 +01:00
.field("pointer_entered", &self.pointer_entered)
// skip seat to avoid loop
.field("last_seat", &"...")
.finish()
}
2022-09-28 12:01:29 +02:00
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Focus {
None,
Header,
Window,
2022-09-28 12:01:29 +02:00
}
impl CosmicWindowInternal {
pub fn swap_focus(&self, focus: Focus) -> Focus {
unsafe {
std::mem::transmute::<u8, Focus>(
self.pointer_entered.swap(focus as u8, Ordering::SeqCst),
)
}
}
pub fn current_focus(&self) -> Focus {
unsafe { std::mem::transmute::<u8, Focus>(self.pointer_entered.load(Ordering::SeqCst)) }
}
2022-09-28 12:01:29 +02:00
pub fn has_ssd(&self, pending: bool) -> bool {
!self.window.is_decorated(pending)
2022-09-28 12:01:29 +02:00
}
}
impl CosmicWindow {
pub fn new(
window: impl Into<CosmicSurface>,
2023-09-29 21:33:16 +02:00
handle: LoopHandle<'static, crate::state::State>,
theme: cosmic::Theme,
) -> CosmicWindow {
let window = window.into();
let width = window.geometry().size.w;
2023-03-06 19:26:26 +01:00
let last_title = window.title();
CosmicWindow(IcedElement::new(
CosmicWindowInternal {
window,
2023-05-31 20:02:39 +02:00
mask: Arc::new(Mutex::new(None)),
2023-06-26 16:59:39 +02:00
activated: Arc::new(AtomicBool::new(false)),
pointer_entered: Arc::new(AtomicU8::new(Focus::None as u8)),
2023-01-18 20:23:41 +01:00
last_seat: Arc::new(Mutex::new(None)),
2023-03-06 19:26:26 +01:00
last_title: Arc::new(Mutex::new(last_title)),
},
(width, SSD_HEIGHT),
handle,
theme,
))
}
pub fn pending_size(&self) -> Option<Size<i32, Logical>> {
self.0.with_program(|p| {
let mut size = p.window.pending_size()?;
if p.has_ssd(true) {
size.h += SSD_HEIGHT;
}
Some(size)
})
}
pub fn set_geometry(&self, geo: Rectangle<i32, Global>) {
self.0.with_program(|p| {
2023-01-23 18:25:01 +01:00
let loc = (
geo.loc.x,
geo.loc.y + if p.has_ssd(true) { SSD_HEIGHT } else { 0 },
2023-01-23 18:25:01 +01:00
);
let size = (
geo.size.w,
std::cmp::max(geo.size.h - if p.has_ssd(true) { SSD_HEIGHT } else { 0 }, 0),
2023-01-23 18:25:01 +01:00
);
p.window
.set_geometry(Rectangle::from_loc_and_size(loc, size));
p.mask.lock().unwrap().take();
});
2023-01-23 18:25:01 +01:00
self.0.resize(Size::from((geo.size.w, SSD_HEIGHT)));
2022-09-28 12:01:29 +02:00
}
pub fn surface(&self) -> CosmicSurface {
self.0.with_program(|p| p.window.clone())
2022-09-28 12:01:29 +02:00
}
2023-04-01 20:35:58 +04:00
pub fn contains_surface(&self, window: &CosmicSurface) -> bool {
self.0.with_program(|p| &p.window == window)
}
pub fn offset(&self) -> Point<i32, Logical> {
let has_ssd = self.0.with_program(|p| p.has_ssd(false));
if has_ssd {
Point::from((0, SSD_HEIGHT))
} else {
Point::from((0, 0))
2022-09-28 12:01:29 +02:00
}
}
2023-06-05 17:52:47 +02:00
2023-09-29 21:33:16 +02:00
pub(super) fn loop_handle(&self) -> LoopHandle<'static, crate::state::State> {
2023-06-05 17:52:47 +02:00
self.0.loop_handle()
}
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<CosmicWindowRenderElement<R>>,
{
let has_ssd = self.0.with_program(|p| p.has_ssd(false));
let window_loc = if has_ssd {
location + Point::from((0, (SSD_HEIGHT as f64 * scale.y) as i32))
} else {
location
};
let (mut window_elements, popup_elements) = self.0.with_program(|p| {
p.window
.split_render_elements::<R, CosmicWindowRenderElement<R>>(
renderer, window_loc, scale, alpha,
)
});
if has_ssd {
let ssd_loc = location
+ self
.0
.with_program(|p| p.window.geometry().loc)
.to_physical_precise_round(scale);
window_elements.extend(AsRenderElements::<R>::render_elements::<
CosmicWindowRenderElement<R>,
>(&self.0, renderer, ssd_loc, scale, alpha))
}
(
window_elements.into_iter().map(C::from).collect(),
popup_elements.into_iter().map(C::from).collect(),
)
}
pub(crate) fn set_theme(&self, theme: cosmic::Theme) {
self.0.set_theme(theme);
}
pub(crate) fn force_redraw(&self) {
self.0.force_redraw();
}
2022-09-28 12:01:29 +02:00
}
#[derive(Debug, Clone, Copy)]
pub enum Message {
DragStart,
Maximize,
Close,
2023-12-07 19:53:41 +00:00
Menu,
2022-09-28 12:01:29 +02:00
}
impl Program for CosmicWindowInternal {
type Message = Message;
2023-01-18 20:23:41 +01:00
fn update(
&mut self,
message: Self::Message,
2023-09-29 21:33:16 +02:00
loop_handle: &LoopHandle<'static, crate::state::State>,
2023-01-18 20:23:41 +01:00
) -> Command<Self::Message> {
match message {
2023-01-18 20:23:41 +01:00
Message::DragStart => {
if let Some((seat, serial)) = self.last_seat.lock().unwrap().clone() {
if let Some(surface) = self.window.wl_surface() {
2023-09-29 21:33:16 +02:00
loop_handle.insert_idle(move |state| {
Shell::move_request(
state,
&surface,
&seat,
serial,
ReleaseMode::NoMouseButtons,
);
2023-01-18 20:23:41 +01:00
});
}
}
}
Message::Maximize => {
2023-10-25 19:41:30 +02:00
if let Some(surface) = self.window.wl_surface() {
loop_handle.insert_idle(move |state| {
if let Some(mapped) =
state.common.shell.element_for_wl_surface(&surface).cloned()
{
if let Some(workspace) = state.common.shell.space_for_mut(&mapped) {
let (window, _) = mapped
.windows()
.find(|(w, _)| w.wl_surface().as_ref() == Some(&surface))
.unwrap();
workspace.maximize_toggle(&window)
2023-01-18 20:23:41 +01:00
}
2023-10-25 19:41:30 +02:00
}
});
2023-01-18 20:23:41 +01:00
}
}
Message::Close => self.window.close(),
2023-12-07 19:53:41 +00:00
Message::Menu => {
if let Some((seat, serial)) = self.last_seat.lock().unwrap().clone() {
if let Some(surface) = self.window.wl_surface() {
loop_handle.insert_idle(move |state| {
if let Some(mapped) =
state.common.shell.element_for_wl_surface(&surface).cloned()
{
if let Some(workspace) = state.common.shell.space_for_mut(&mapped) {
let position = workspace
.element_geometry(&mapped)
.unwrap()
.loc
.to_global(&workspace.output);
let mut cursor = seat
.get_pointer()
.unwrap()
.current_location()
.to_i32_round();
cursor.y -= SSD_HEIGHT;
Shell::menu_request(
state,
&surface,
&seat,
serial,
cursor - position.as_logical(),
2023-12-12 15:35:23 +00:00
false,
2023-12-07 19:53:41 +00:00
);
}
}
});
}
}
}
}
Command::none()
}
fn foreground(
&self,
pixels: &mut tiny_skia::PixmapMut<'_>,
damage: &[Rectangle<i32, BufferCoords>],
scale: f32,
) {
if !self.window.is_activated(false) {
let mut mask = self.mask.lock().unwrap();
if self.window.is_maximized(false) {
mask.take();
} else if mask.is_none() {
let (w, h) = (pixels.width(), pixels.height());
let mut new_mask = tiny_skia::Mask::new(w, h).unwrap();
let mut pb = tiny_skia::PathBuilder::new();
let radius = 8. * scale;
let (w, h) = (w as f32, h as f32);
pb.move_to(0., h); // lower-left
// upper-left rounded corner
pb.line_to(0., radius);
pb.quad_to(0., 0., radius, 0.);
// upper-right rounded corner
pb.line_to(w - radius, 0.);
pb.quad_to(w, 0., w, radius);
2023-05-31 20:02:39 +02:00
pb.line_to(w, h); // lower-right
let path = pb.finish().unwrap();
new_mask.fill_path(
&path,
tiny_skia::FillRule::EvenOdd,
true,
Default::default(),
);
2023-05-31 20:02:39 +02:00
*mask = Some(new_mask);
2023-05-31 20:02:39 +02:00
}
2023-01-25 15:14:18 +01:00
2023-05-31 20:02:39 +02:00
let mut paint = tiny_skia::Paint::default();
paint.set_color_rgba8(0, 0, 0, 102);
for rect in damage {
pixels.fill_rect(
tiny_skia::Rect::from_xywh(
rect.loc.x as f32,
rect.loc.y as f32,
rect.size.w as f32,
rect.size.h as f32,
)
.unwrap(),
&paint,
Default::default(),
mask.as_ref(),
);
}
}
}
2023-03-07 22:20:44 +01:00
fn view(&self) -> cosmic::Element<'_, Self::Message> {
cosmic::widget::header_bar()
2023-03-06 19:26:26 +01:00
.title(self.last_title.lock().unwrap().clone())
.on_drag(Message::DragStart)
.on_maximize(Message::Maximize)
.on_close(Message::Close)
2023-12-07 19:53:41 +00:00
.apply(mouse_area)
.on_right_press(Message::Menu)
.into()
}
2022-09-28 12:01:29 +02:00
}
impl IsAlive for CosmicWindow {
fn alive(&self) -> bool {
self.0.with_program(|p| p.window.alive())
2022-09-28 12:01:29 +02:00
}
}
impl SpaceElement for CosmicWindow {
fn bbox(&self) -> Rectangle<i32, Logical> {
self.0.with_program(|p| {
let mut bbox = SpaceElement::bbox(&p.window);
if p.has_ssd(false) {
bbox.size.h += SSD_HEIGHT;
}
bbox
})
2022-09-28 12:01:29 +02:00
}
fn is_in_input_region(&self, point: &Point<f64, Logical>) -> bool {
let mut point = *point;
if !self.bbox().contains(point.to_i32_round()) {
return false;
}
self.0.with_program(|p| {
if p.has_ssd(false) {
if point.y < SSD_HEIGHT as f64 {
return true;
} else {
point.y -= SSD_HEIGHT as f64;
}
}
SpaceElement::is_in_input_region(&p.window, &point)
})
2022-09-28 12:01:29 +02:00
}
fn set_activate(&self, activated: bool) {
2023-06-26 16:59:39 +02:00
if self
.0
.with_program(|p| p.activated.load(Ordering::SeqCst) != activated)
{
SpaceElement::set_activate(&self.0, activated);
self.0.force_redraw();
self.0.with_program(|p| {
p.activated.store(activated, Ordering::SeqCst);
SpaceElement::set_activate(&p.window, activated);
});
}
2022-09-28 12:01:29 +02:00
}
fn output_enter(&self, output: &Output, overlap: Rectangle<i32, Logical>) {
SpaceElement::output_enter(&self.0, output, overlap);
self.0
.with_program(|p| SpaceElement::output_enter(&p.window, output, overlap));
2022-09-28 12:01:29 +02:00
}
fn output_leave(&self, output: &Output) {
SpaceElement::output_leave(&self.0, output);
self.0
.with_program(|p| SpaceElement::output_leave(&p.window, output));
2022-09-28 12:01:29 +02:00
}
fn geometry(&self) -> Rectangle<i32, Logical> {
self.0.with_program(|p| {
let mut geo = SpaceElement::geometry(&p.window);
if p.has_ssd(false) {
geo.size.h += SSD_HEIGHT;
}
geo
})
2022-09-28 12:01:29 +02:00
}
fn z_index(&self) -> u8 {
self.0.with_program(|p| SpaceElement::z_index(&p.window))
2022-09-28 12:01:29 +02:00
}
fn refresh(&self) {
2023-01-25 15:14:18 +01:00
SpaceElement::refresh(&self.0);
2023-03-06 19:26:26 +01:00
if self.0.with_program(|p| {
SpaceElement::refresh(&p.window);
let title = p.window.title();
let mut last_title = p.last_title.lock().unwrap();
if *last_title != title {
*last_title = title;
true
} else {
false
}
}) {
self.0.force_update();
}
2022-09-28 12:01:29 +02:00
}
}
impl KeyboardTarget<State> for CosmicWindow {
fn enter(
&self,
seat: &Seat<State>,
data: &mut State,
keys: Vec<KeysymHandle<'_>>,
serial: Serial,
) {
self.0
.with_program(|p| KeyboardTarget::enter(&p.window, seat, data, keys, serial))
2022-09-28 12:01:29 +02:00
}
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial) {
self.0
.with_program(|p| KeyboardTarget::leave(&p.window, 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,
) {
self.0
.with_program(|p| KeyboardTarget::key(&p.window, seat, data, key, state, serial, time))
2022-09-28 12:01:29 +02:00
}
fn modifiers(
&self,
seat: &Seat<State>,
data: &mut State,
modifiers: ModifiersState,
serial: Serial,
) {
self.0
.with_program(|p| KeyboardTarget::modifiers(&p.window, seat, data, modifiers, serial))
2022-09-28 12:01:29 +02:00
}
}
impl PointerTarget<State> for CosmicWindow {
fn enter(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) {
if self.0.with_program(|p| {
if let Some(sessions) = p.window.user_data().get::<ScreencopySessions>() {
for session in &*sessions.0.borrow() {
session.cursor_enter(seat, InputType::Pointer)
}
}
if p.has_ssd(false) {
if event.location.y < SSD_HEIGHT as f64 {
let focus = p.swap_focus(Focus::Header);
assert_eq!(focus, Focus::None);
return true;
} else {
let focus = p.swap_focus(Focus::Window);
assert_eq!(focus, Focus::None);
2022-11-03 18:51:27 +01:00
let mut event = event.clone();
event.location.y -= SSD_HEIGHT as f64;
PointerTarget::enter(&p.window, seat, data, &event)
}
} else {
p.swap_focus(Focus::Window);
PointerTarget::enter(&p.window, seat, data, event)
2022-11-03 18:51:27 +01:00
}
false
}) {
PointerTarget::enter(&self.0, seat, data, event)
2022-11-03 18:51:27 +01:00
}
2022-09-28 12:01:29 +02:00
}
2022-09-28 12:01:29 +02:00
fn motion(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) {
if let Some((previous, next)) = self.0.with_program(|p| {
if let Some(sessions) = p.window.user_data().get::<ScreencopySessions>() {
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
}
}
if p.has_ssd(false) {
if event.location.y < SSD_HEIGHT as f64 {
let previous = p.swap_focus(Focus::Header);
if previous == Focus::Window {
PointerTarget::leave(&p.window, seat, data, event.serial, event.time);
}
Some((previous, Focus::Header))
} else {
let mut event = event.clone();
event.location.y -= SSD_HEIGHT as f64;
let previous = p.swap_focus(Focus::Window);
if previous != Focus::Window {
PointerTarget::enter(&p.window, seat, data, &event);
} else {
PointerTarget::motion(&p.window, seat, data, &event);
}
Some((previous, Focus::Window))
}
} else {
p.swap_focus(Focus::Window);
PointerTarget::motion(&p.window, seat, data, event);
None
}
}) {
match (previous, next) {
(Focus::Header, Focus::Header) => PointerTarget::motion(&self.0, seat, data, event),
(_, Focus::Header) => PointerTarget::enter(&self.0, seat, data, event),
(Focus::Header, _) => {
PointerTarget::leave(&self.0, seat, data, event.serial, event.time)
}
_ => {}
};
}
2022-09-28 12:01:29 +02:00
}
fn relative_motion(&self, seat: &Seat<State>, data: &mut State, event: &RelativeMotionEvent) {
self.0.with_program(|p| {
if !p.has_ssd(false) || p.current_focus() == Focus::Window {
PointerTarget::relative_motion(&p.window, seat, data, event)
}
})
}
2022-09-28 12:01:29 +02:00
fn button(&self, seat: &Seat<State>, data: &mut State, event: &ButtonEvent) {
match self.0.with_program(|p| p.current_focus()) {
2023-01-18 20:23:41 +01: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)
}
Focus::Window => self
.0
.with_program(|p| PointerTarget::button(&p.window, seat, data, event)),
_ => {}
}
2022-09-28 12:01:29 +02:00
}
2022-09-28 12:01:29 +02:00
fn axis(&self, seat: &Seat<State>, data: &mut State, frame: AxisFrame) {
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.window, seat, data, frame)),
_ => {}
}
}
fn frame(&self, seat: &Seat<State>, data: &mut State) {
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.window, seat, data)),
_ => {}
}
2022-09-28 12:01:29 +02:00
}
2022-11-03 18:51:27 +01:00
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: u32) {
let previous = self.0.with_program(|p| {
if let Some(sessions) = p.window.user_data().get::<ScreencopySessions>() {
for session in &*sessions.0.borrow() {
session.cursor_leave(seat, InputType::Pointer)
}
2022-11-03 18:51:27 +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.window, seat, data, serial, time)),
_ => {}
}
2022-09-28 12:01:29 +02:00
}
fn gesture_swipe_begin(
&self,
seat: &Seat<State>,
data: &mut State,
event: &GestureSwipeBeginEvent,
) {
self.0.with_program(|p| {
if !p.has_ssd(false) || p.current_focus() == Focus::Window {
PointerTarget::gesture_swipe_begin(&p.window, seat, data, event)
}
})
}
fn gesture_swipe_update(
&self,
seat: &Seat<State>,
data: &mut State,
event: &GestureSwipeUpdateEvent,
) {
self.0.with_program(|p| {
if !p.has_ssd(false) || p.current_focus() == Focus::Window {
PointerTarget::gesture_swipe_update(&p.window, seat, data, event)
}
})
}
fn gesture_swipe_end(
&self,
seat: &Seat<State>,
data: &mut State,
event: &GestureSwipeEndEvent,
) {
self.0.with_program(|p| {
if !p.has_ssd(false) || p.current_focus() == Focus::Window {
PointerTarget::gesture_swipe_end(&p.window, seat, data, event)
}
})
}
fn gesture_pinch_begin(
&self,
seat: &Seat<State>,
data: &mut State,
event: &GesturePinchBeginEvent,
) {
self.0.with_program(|p| {
if !p.has_ssd(false) || p.current_focus() == Focus::Window {
PointerTarget::gesture_pinch_begin(&p.window, seat, data, event)
}
})
}
fn gesture_pinch_update(
&self,
seat: &Seat<State>,
data: &mut State,
event: &GesturePinchUpdateEvent,
) {
self.0.with_program(|p| {
if !p.has_ssd(false) || p.current_focus() == Focus::Window {
PointerTarget::gesture_pinch_update(&p.window, seat, data, event)
}
})
}
fn gesture_pinch_end(
&self,
seat: &Seat<State>,
data: &mut State,
event: &GesturePinchEndEvent,
) {
self.0.with_program(|p| {
if !p.has_ssd(false) || p.current_focus() == Focus::Window {
PointerTarget::gesture_pinch_end(&p.window, seat, data, event)
}
})
}
fn gesture_hold_begin(
&self,
seat: &Seat<State>,
data: &mut State,
event: &GestureHoldBeginEvent,
) {
self.0.with_program(|p| {
if !p.has_ssd(false) || p.current_focus() == Focus::Window {
PointerTarget::gesture_hold_begin(&p.window, seat, data, event)
}
})
}
fn gesture_hold_end(&self, seat: &Seat<State>, data: &mut State, event: &GestureHoldEndEvent) {
self.0.with_program(|p| {
if !p.has_ssd(false) || p.current_focus() == Focus::Window {
PointerTarget::gesture_hold_end(&p.window, seat, data, event)
}
})
}
2022-09-28 12:01:29 +02:00
}
impl WaylandFocus for CosmicWindow {
fn wl_surface(&self) -> Option<WlSurface> {
self.0.with_program(|p| p.window.wl_surface())
}
fn same_client_as(&self, object_id: &ObjectId) -> bool {
self.0.with_program(|p| p.window.same_client_as(object_id))
}
}
2023-06-08 21:50:16 +02:00
render_elements! {
pub CosmicWindowRenderElement<R> where R: ImportAll + ImportMem;
Header = MemoryRenderBufferRenderElement<R>,
Window = WaylandSurfaceRenderElement<R>,
2022-09-28 12:01:29 +02:00
}