2022-11-03 18:51:27 +01:00
|
|
|
use crate::{
|
2023-03-07 22:20:44 +01:00
|
|
|
backend::render::{
|
|
|
|
|
element::{AsGlowFrame, AsGlowRenderer},
|
|
|
|
|
GlMultiFrame, GlMultiRenderer,
|
|
|
|
|
},
|
2023-01-18 20:23:41 +01:00
|
|
|
shell::Shell,
|
2023-01-16 15:12:25 +01:00
|
|
|
state::State,
|
|
|
|
|
utils::{
|
|
|
|
|
iced::{IcedElement, Program},
|
|
|
|
|
prelude::SeatExt,
|
|
|
|
|
},
|
|
|
|
|
wayland::handlers::screencopy::ScreencopySessions,
|
2022-11-03 18:51:27 +01:00
|
|
|
};
|
2023-01-16 15:12:25 +01:00
|
|
|
use calloop::LoopHandle;
|
2023-03-07 22:20:44 +01:00
|
|
|
use cosmic::iced_native::Command;
|
2023-01-16 15:12:25 +01:00
|
|
|
use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::InputType;
|
|
|
|
|
use iced_softbuffer::native::raqote::{DrawOptions, DrawTarget, PathBuilder, SolidSource, Source};
|
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-03-07 22:20:44 +01:00
|
|
|
AsRenderElements, Element, Id, RenderElement,
|
2023-01-16 15:12:25 +01:00
|
|
|
},
|
2023-03-07 22:20:44 +01:00
|
|
|
glow::GlowRenderer,
|
|
|
|
|
multigpu::Error as MultiError,
|
|
|
|
|
utils::CommitCounter,
|
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-01-30 23:19:36 +01:00
|
|
|
pointer::{AxisFrame, ButtonEvent, MotionEvent, PointerTarget, RelativeMotionEvent},
|
2022-09-28 12:01:29 +02:00
|
|
|
Seat,
|
|
|
|
|
},
|
|
|
|
|
output::Output,
|
2023-03-07 22:20:44 +01:00
|
|
|
utils::{IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size, Transform},
|
2023-01-18 20:23:41 +01: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,
|
2023-01-16 15:12:25 +01:00
|
|
|
sync::{
|
|
|
|
|
atomic::{AtomicU8, Ordering},
|
2023-01-18 20:23:41 +01:00
|
|
|
Arc, Mutex,
|
2023-01-16 15:12:25 +01:00
|
|
|
},
|
2022-09-28 12:01:29 +02:00
|
|
|
};
|
|
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
use super::{surface::SSD_HEIGHT, CosmicSurface};
|
2022-09-28 12:01:29 +02:00
|
|
|
|
2023-01-16 15:12:25 +01: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 {
|
|
|
|
|
self.0.with_program(|window| {
|
|
|
|
|
f.debug_struct("CosmicWindow")
|
|
|
|
|
.field("internal", window)
|
|
|
|
|
.finish_non_exhaustive()
|
|
|
|
|
})
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-18 20:23:41 +01:00
|
|
|
#[derive(Clone)]
|
2023-01-16 15:12:25 +01:00
|
|
|
pub struct CosmicWindowInternal {
|
|
|
|
|
pub(super) window: CosmicSurface,
|
2023-01-18 20:23:41 +01:00
|
|
|
/// TODO: This needs to be per seat
|
2023-01-16 20:31:43 +01:00
|
|
|
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)
|
|
|
|
|
.field("pointer_entered", &self.pointer_entered)
|
|
|
|
|
// skip seat to avoid loop
|
|
|
|
|
.field("last_seat", &"...")
|
|
|
|
|
.finish()
|
|
|
|
|
}
|
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-01-16 15:12:25 +01:00
|
|
|
impl CosmicWindowInternal {
|
|
|
|
|
pub fn swap_focus(&self, focus: Focus) -> Focus {
|
2023-01-16 20:31:43 +01:00
|
|
|
unsafe {
|
|
|
|
|
std::mem::transmute::<u8, Focus>(
|
|
|
|
|
self.pointer_entered.swap(focus as u8, Ordering::SeqCst),
|
|
|
|
|
)
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn current_focus(&self) -> Focus {
|
2023-01-16 20:31:43 +01:00
|
|
|
unsafe { std::mem::transmute::<u8, Focus>(self.pointer_entered.load(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 has_ssd(&self) -> bool {
|
2023-01-16 20:31:43 +01:00
|
|
|
!self.window.is_decorated()
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl CosmicWindow {
|
2023-01-16 15:12:25 +01:00
|
|
|
pub fn new(
|
|
|
|
|
window: impl Into<CosmicSurface>,
|
|
|
|
|
handle: LoopHandle<'static, crate::state::Data>,
|
|
|
|
|
) -> CosmicWindow {
|
|
|
|
|
let window = window.into();
|
|
|
|
|
let width = window.geometry().size.w;
|
2023-03-06 19:26:26 +01:00
|
|
|
let last_title = window.title();
|
2023-01-16 15:12:25 +01:00
|
|
|
CosmicWindow(IcedElement::new(
|
|
|
|
|
CosmicWindowInternal {
|
|
|
|
|
window,
|
2023-01-16 20:31:43 +01:00
|
|
|
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)),
|
2023-01-16 15:12:25 +01:00
|
|
|
},
|
|
|
|
|
(width, SSD_HEIGHT),
|
|
|
|
|
handle,
|
|
|
|
|
))
|
|
|
|
|
}
|
|
|
|
|
|
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 + if p.has_ssd() { SSD_HEIGHT } else { 0 },
|
|
|
|
|
);
|
|
|
|
|
let size = (
|
|
|
|
|
geo.size.w,
|
2023-01-25 15:14:18 +01:00
|
|
|
std::cmp::max(geo.size.h - if p.has_ssd() { SSD_HEIGHT } else { 0 }, 0),
|
2023-01-23 18:25:01 +01:00
|
|
|
);
|
|
|
|
|
p.window
|
|
|
|
|
.set_geometry(Rectangle::from_loc_and_size(loc, size));
|
2023-01-16 15:12:25 +01:00
|
|
|
});
|
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
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:12:25 +01: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)
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
pub fn offset(&self) -> Point<i32, Logical> {
|
|
|
|
|
let has_ssd = self.0.with_program(|p| p.has_ssd());
|
|
|
|
|
if has_ssd {
|
|
|
|
|
Point::from((0, SSD_HEIGHT))
|
|
|
|
|
} else {
|
|
|
|
|
Point::from((0, 0))
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
|
pub enum Message {
|
|
|
|
|
DragStart,
|
|
|
|
|
Maximize,
|
|
|
|
|
Close,
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
impl Program for CosmicWindowInternal {
|
|
|
|
|
type Message = Message;
|
|
|
|
|
|
2023-01-18 20:23:41 +01:00
|
|
|
fn update(
|
|
|
|
|
&mut self,
|
|
|
|
|
message: Self::Message,
|
|
|
|
|
loop_handle: &LoopHandle<'static, crate::state::Data>,
|
|
|
|
|
) -> Command<Self::Message> {
|
2023-01-16 15:12:25 +01:00
|
|
|
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() {
|
|
|
|
|
loop_handle.insert_idle(move |data| {
|
|
|
|
|
Shell::move_request(&mut data.state, &surface, &seat, serial);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Message::Maximize => {
|
|
|
|
|
if let Some((seat, _serial)) = self.last_seat.lock().unwrap().clone() {
|
|
|
|
|
if let Some(surface) = self.window.wl_surface() {
|
|
|
|
|
loop_handle.insert_idle(move |data| {
|
|
|
|
|
if let Some(mapped) = data
|
|
|
|
|
.state
|
|
|
|
|
.common
|
|
|
|
|
.shell
|
|
|
|
|
.element_for_wl_surface(&surface)
|
|
|
|
|
.cloned()
|
|
|
|
|
{
|
|
|
|
|
if let Some(workspace) =
|
|
|
|
|
data.state.common.shell.space_for_mut(&mapped)
|
|
|
|
|
{
|
|
|
|
|
let output = seat.active_output();
|
|
|
|
|
let (window, _) = mapped
|
|
|
|
|
.windows()
|
|
|
|
|
.find(|(w, _)| w.wl_surface().as_ref() == Some(&surface))
|
|
|
|
|
.unwrap();
|
|
|
|
|
workspace.maximize_request(&window, &output)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Message::Close => self.window.close(),
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
Command::none()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn background(&self, target: &mut DrawTarget<&mut [u32]>) {
|
|
|
|
|
let radius = 8.;
|
|
|
|
|
let (w, h) = (target.width() as f32, target.height() as f32);
|
|
|
|
|
|
2023-01-18 20:23:41 +01:00
|
|
|
if !(self.window.is_maximized() || self.window.is_fullscreen()) {
|
|
|
|
|
let mut pb = PathBuilder::new();
|
|
|
|
|
pb.move_to(0., h); // lower-left
|
2023-01-16 15:12:25 +01:00
|
|
|
|
2023-01-18 20:23:41 +01:00
|
|
|
// upper-left rounded corner
|
|
|
|
|
pb.line_to(0., radius);
|
|
|
|
|
pb.quad_to(0., 0., radius, 0.);
|
2023-01-16 15:12:25 +01:00
|
|
|
|
2023-01-18 20:23:41 +01:00
|
|
|
// upper-right rounded corner
|
|
|
|
|
pb.line_to(w - radius, 0.);
|
|
|
|
|
pb.quad_to(w, 0., w, radius);
|
2023-01-16 15:12:25 +01:00
|
|
|
|
2023-01-18 20:23:41 +01:00
|
|
|
pb.line_to(w, h); // lower-right
|
2023-01-16 15:12:25 +01:00
|
|
|
|
2023-01-18 20:23:41 +01:00
|
|
|
let path = pb.finish();
|
|
|
|
|
target.push_clip(&path);
|
|
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
|
|
|
|
|
if self.window.is_activated() {
|
|
|
|
|
target.clear(SolidSource::from_unpremultiplied_argb(u8::MAX, 30, 30, 30));
|
|
|
|
|
} else {
|
|
|
|
|
target.clear(SolidSource::from_unpremultiplied_argb(u8::MAX, 39, 39, 39));
|
|
|
|
|
}
|
2023-01-25 15:14:18 +01:00
|
|
|
|
|
|
|
|
target.pop_clip();
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
|
2023-03-07 22:20:44 +01:00
|
|
|
fn view(&self) -> cosmic::Element<'_, Self::Message> {
|
2023-01-16 15:12:25 +01:00
|
|
|
cosmic::widget::header_bar()
|
2023-03-06 19:26:26 +01:00
|
|
|
.title(self.last_title.lock().unwrap().clone())
|
2023-01-16 15:12:25 +01:00
|
|
|
.on_drag(Message::DragStart)
|
|
|
|
|
.on_maximize(Message::Maximize)
|
|
|
|
|
.on_close(Message::Close)
|
|
|
|
|
.into_element()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn foreground(&self, target: &mut DrawTarget<&mut [u32]>) {
|
|
|
|
|
if !self.window.is_activated() {
|
2023-01-25 15:14:18 +01:00
|
|
|
let radius = 8.;
|
2023-01-16 15:12:25 +01:00
|
|
|
let (w, h) = (target.width() as f32, target.height() as f32);
|
2023-01-25 15:14:18 +01:00
|
|
|
|
|
|
|
|
if !(self.window.is_maximized() || self.window.is_fullscreen()) {
|
|
|
|
|
let mut pb = PathBuilder::new();
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
pb.line_to(w, h); // lower-right
|
|
|
|
|
|
|
|
|
|
let path = pb.finish();
|
|
|
|
|
target.push_clip(&path);
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
let mut options = DrawOptions::new();
|
|
|
|
|
options.alpha = 0.4;
|
|
|
|
|
target.fill_rect(
|
|
|
|
|
0.,
|
|
|
|
|
0.,
|
|
|
|
|
w,
|
|
|
|
|
h,
|
|
|
|
|
&Source::Solid(SolidSource::from_unpremultiplied_argb(u8::MAX, 0, 0, 0)),
|
|
|
|
|
&options,
|
|
|
|
|
);
|
|
|
|
|
}
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl IsAlive for CosmicWindow {
|
|
|
|
|
fn alive(&self) -> bool {
|
2023-01-16 15:12:25 +01:00
|
|
|
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> {
|
2023-01-16 15:12:25 +01:00
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
let mut bbox = SpaceElement::bbox(&p.window);
|
|
|
|
|
if p.has_ssd() {
|
|
|
|
|
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 {
|
2023-01-16 15:12:25 +01:00
|
|
|
let mut point = *point;
|
2023-01-25 18:44:06 +01:00
|
|
|
if !self.bbox().contains(point.to_i32_round()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
self.0.with_program(|p| {
|
|
|
|
|
if p.has_ssd() {
|
|
|
|
|
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-01-16 15:12:25 +01:00
|
|
|
SpaceElement::set_activate(&self.0, activated);
|
|
|
|
|
self.0
|
|
|
|
|
.with_program(|p| SpaceElement::set_activate(&p.window, 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| SpaceElement::output_enter(&p.window, 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| SpaceElement::output_leave(&p.window, 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.window);
|
|
|
|
|
if p.has_ssd() {
|
|
|
|
|
geo.size.h += SSD_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.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,
|
|
|
|
|
) {
|
2023-01-16 15:12:25 +01:00
|
|
|
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) {
|
2023-01-16 15:12:25 +01:00
|
|
|
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,
|
|
|
|
|
) {
|
2023-01-16 15:12:25 +01:00
|
|
|
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,
|
|
|
|
|
) {
|
2023-01-16 15:12:25 +01:00
|
|
|
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) {
|
2023-01-16 15:12:25 +01:00
|
|
|
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() {
|
|
|
|
|
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
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
let mut event = event.clone();
|
|
|
|
|
event.location.y -= SSD_HEIGHT as f64;
|
|
|
|
|
PointerTarget::enter(&p.window, seat, data, &event)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2023-04-20 16:19:52 +02:00
|
|
|
p.swap_focus(Focus::Window);
|
2023-01-16 15:12:25 +01:00
|
|
|
PointerTarget::enter(&p.window, seat, data, event)
|
2022-11-03 18:51:27 +01:00
|
|
|
}
|
2023-01-16 15:12:25 +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
|
|
|
}
|
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-01-16 15:12:25 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
if p.has_ssd() {
|
|
|
|
|
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 {
|
2023-01-16 20:31:43 +01:00
|
|
|
p.swap_focus(Focus::Window);
|
2023-01-16 15:12:25 +01:00
|
|
|
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
|
|
|
}
|
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.has_ssd() || 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) {
|
2023-01-16 15:12:25 +01:00
|
|
|
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)
|
|
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
Focus::Window => self
|
|
|
|
|
.0
|
|
|
|
|
.with_program(|p| PointerTarget::button(&p.window, seat, data, event)),
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
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
|
|
|
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)),
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
2022-11-03 18:51:27 +01:00
|
|
|
|
2023-01-16 15:12:25 +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
|
|
|
}
|
|
|
|
|
|
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.window, seat, data, serial, time)),
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-07 22:20:44 +01:00
|
|
|
pub enum CosmicWindowRenderElement<R>
|
|
|
|
|
where
|
|
|
|
|
R: ImportAll + ImportMem + AsGlowRenderer + Renderer,
|
|
|
|
|
<R as Renderer>::TextureId: 'static,
|
|
|
|
|
{
|
|
|
|
|
Header(MemoryRenderBufferRenderElement<GlowRenderer>),
|
|
|
|
|
Window(WaylandSurfaceRenderElement<R>),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<R> From<WaylandSurfaceRenderElement<R>> for CosmicWindowRenderElement<R>
|
|
|
|
|
where
|
|
|
|
|
R: ImportAll + ImportMem + AsGlowRenderer + Renderer,
|
|
|
|
|
<R as Renderer>::TextureId: 'static,
|
|
|
|
|
{
|
|
|
|
|
fn from(elem: WaylandSurfaceRenderElement<R>) -> Self {
|
|
|
|
|
CosmicWindowRenderElement::Window(elem)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<R> From<MemoryRenderBufferRenderElement<GlowRenderer>> for CosmicWindowRenderElement<R>
|
|
|
|
|
where
|
|
|
|
|
R: ImportAll + ImportMem + AsGlowRenderer + Renderer,
|
|
|
|
|
<R as Renderer>::TextureId: 'static,
|
|
|
|
|
{
|
|
|
|
|
fn from(elem: MemoryRenderBufferRenderElement<GlowRenderer>) -> Self {
|
|
|
|
|
CosmicWindowRenderElement::Header(elem)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<R> Element for CosmicWindowRenderElement<R>
|
|
|
|
|
where
|
|
|
|
|
R: AsGlowRenderer + Renderer + ImportAll + ImportMem,
|
|
|
|
|
<R as Renderer>::TextureId: 'static,
|
|
|
|
|
{
|
|
|
|
|
fn id(&self) -> &Id {
|
|
|
|
|
match self {
|
|
|
|
|
CosmicWindowRenderElement::Header(h) => h.id(),
|
|
|
|
|
CosmicWindowRenderElement::Window(w) => w.id(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn current_commit(&self) -> CommitCounter {
|
|
|
|
|
match self {
|
|
|
|
|
CosmicWindowRenderElement::Header(h) => h.current_commit(),
|
|
|
|
|
CosmicWindowRenderElement::Window(w) => w.current_commit(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn src(&self) -> Rectangle<f64, smithay::utils::Buffer> {
|
|
|
|
|
match self {
|
|
|
|
|
CosmicWindowRenderElement::Header(h) => h.src(),
|
|
|
|
|
CosmicWindowRenderElement::Window(w) => w.src(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn geometry(&self, scale: Scale<f64>) -> Rectangle<i32, Physical> {
|
|
|
|
|
match self {
|
|
|
|
|
CosmicWindowRenderElement::Header(h) => h.geometry(scale),
|
|
|
|
|
CosmicWindowRenderElement::Window(w) => w.geometry(scale),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn location(&self, scale: Scale<f64>) -> Point<i32, Physical> {
|
|
|
|
|
match self {
|
|
|
|
|
CosmicWindowRenderElement::Header(h) => h.location(scale),
|
|
|
|
|
CosmicWindowRenderElement::Window(w) => w.location(scale),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn transform(&self) -> Transform {
|
|
|
|
|
match self {
|
|
|
|
|
CosmicWindowRenderElement::Header(h) => h.transform(),
|
|
|
|
|
CosmicWindowRenderElement::Window(w) => w.transform(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn damage_since(
|
|
|
|
|
&self,
|
|
|
|
|
scale: Scale<f64>,
|
|
|
|
|
commit: Option<CommitCounter>,
|
|
|
|
|
) -> Vec<Rectangle<i32, Physical>> {
|
|
|
|
|
match self {
|
|
|
|
|
CosmicWindowRenderElement::Header(h) => h.damage_since(scale, commit),
|
|
|
|
|
CosmicWindowRenderElement::Window(w) => w.damage_since(scale, commit),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn opaque_regions(&self, scale: Scale<f64>) -> Vec<Rectangle<i32, Physical>> {
|
|
|
|
|
match self {
|
|
|
|
|
CosmicWindowRenderElement::Header(h) => h.opaque_regions(scale),
|
|
|
|
|
CosmicWindowRenderElement::Window(w) => w.opaque_regions(scale),
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-05-12 20:01:37 +02:00
|
|
|
|
|
|
|
|
fn alpha(&self) -> f32 {
|
|
|
|
|
match self {
|
|
|
|
|
CosmicWindowRenderElement::Header(h) => h.alpha(),
|
|
|
|
|
CosmicWindowRenderElement::Window(w) => w.alpha(),
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-07 22:20:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl RenderElement<GlowRenderer> for CosmicWindowRenderElement<GlowRenderer> {
|
|
|
|
|
fn draw<'a>(
|
|
|
|
|
&self,
|
|
|
|
|
frame: &mut <GlowRenderer as Renderer>::Frame<'a>,
|
|
|
|
|
src: Rectangle<f64, smithay::utils::Buffer>,
|
|
|
|
|
dst: Rectangle<i32, Physical>,
|
|
|
|
|
damage: &[Rectangle<i32, Physical>],
|
|
|
|
|
) -> Result<(), <GlowRenderer as Renderer>::Error> {
|
|
|
|
|
match self {
|
|
|
|
|
CosmicWindowRenderElement::Header(h) => h.draw(frame, src, dst, damage),
|
|
|
|
|
CosmicWindowRenderElement::Window(w) => w.draw(frame, src, dst, damage),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn underlying_storage(
|
|
|
|
|
&self,
|
|
|
|
|
renderer: &mut GlowRenderer,
|
|
|
|
|
) -> Option<smithay::backend::renderer::element::UnderlyingStorage> {
|
|
|
|
|
match self {
|
|
|
|
|
CosmicWindowRenderElement::Header(h) => h.underlying_storage(renderer),
|
|
|
|
|
CosmicWindowRenderElement::Window(w) => w.underlying_storage(renderer),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a, 'b> RenderElement<GlMultiRenderer<'a, 'b>>
|
|
|
|
|
for CosmicWindowRenderElement<GlMultiRenderer<'a, 'b>>
|
|
|
|
|
{
|
|
|
|
|
fn draw<'c>(
|
|
|
|
|
&self,
|
|
|
|
|
frame: &mut GlMultiFrame<'a, 'b, 'c>,
|
|
|
|
|
src: Rectangle<f64, smithay::utils::Buffer>,
|
|
|
|
|
dst: Rectangle<i32, Physical>,
|
|
|
|
|
damage: &[Rectangle<i32, Physical>],
|
|
|
|
|
) -> Result<(), <GlMultiRenderer<'a, 'b> as Renderer>::Error> {
|
|
|
|
|
match self {
|
|
|
|
|
CosmicWindowRenderElement::Header(h) => h
|
|
|
|
|
.draw(frame.glow_frame_mut(), src, dst, damage)
|
|
|
|
|
.map_err(|err| MultiError::Render(err)),
|
|
|
|
|
CosmicWindowRenderElement::Window(w) => w.draw(frame, src, dst, damage),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn underlying_storage(
|
|
|
|
|
&self,
|
|
|
|
|
renderer: &mut GlMultiRenderer<'a, 'b>,
|
|
|
|
|
) -> Option<smithay::backend::renderer::element::UnderlyingStorage> {
|
|
|
|
|
match self {
|
|
|
|
|
CosmicWindowRenderElement::Header(h) => {
|
|
|
|
|
h.underlying_storage(renderer.glow_renderer_mut())
|
|
|
|
|
}
|
|
|
|
|
CosmicWindowRenderElement::Window(w) => w.underlying_storage(renderer),
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<R> AsRenderElements<R> for CosmicWindow
|
|
|
|
|
where
|
2023-03-07 22:20:44 +01:00
|
|
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
2022-09-28 12:01:29 +02:00
|
|
|
<R as Renderer>::TextureId: 'static,
|
2023-03-07 22:20:44 +01:00
|
|
|
CosmicWindowRenderElement<R>: RenderElement<R>,
|
2022-09-28 12:01:29 +02:00
|
|
|
{
|
|
|
|
|
type RenderElement = CosmicWindowRenderElement<R>;
|
|
|
|
|
fn render_elements<C: From<Self::RenderElement>>(
|
|
|
|
|
&self,
|
2022-11-28 17:48:50 +01:00
|
|
|
renderer: &mut R,
|
2023-01-16 20:31:43 +01:00
|
|
|
location: Point<i32, Physical>,
|
2022-09-28 12:01:29 +02:00
|
|
|
scale: Scale<f64>,
|
2023-05-12 20:01:37 +02:00
|
|
|
alpha: f32,
|
2022-09-28 12:01:29 +02:00
|
|
|
) -> Vec<C> {
|
2023-01-16 15:12:25 +01:00
|
|
|
let has_ssd = self.0.with_program(|p| p.has_ssd());
|
|
|
|
|
|
2023-01-16 20:31:43 +01:00
|
|
|
let window_loc = if has_ssd {
|
|
|
|
|
location + Point::from((0, (SSD_HEIGHT as f64 * scale.y) as i32))
|
2023-01-16 15:12:25 +01:00
|
|
|
} else {
|
2023-01-16 20:31:43 +01:00
|
|
|
location
|
2023-01-16 15:12:25 +01:00
|
|
|
};
|
|
|
|
|
|
2023-01-16 20:31:43 +01:00
|
|
|
let mut elements = self.0.with_program(|p| {
|
2023-01-16 15:12:25 +01:00
|
|
|
AsRenderElements::<R>::render_elements::<CosmicWindowRenderElement<R>>(
|
2023-05-12 20:01:37 +02:00
|
|
|
&p.window, renderer, window_loc, scale, alpha,
|
2023-01-16 15:12:25 +01:00
|
|
|
)
|
2023-01-16 20:31:43 +01:00
|
|
|
});
|
|
|
|
|
if has_ssd {
|
2023-03-07 22:20:44 +01:00
|
|
|
elements.extend(AsRenderElements::<GlowRenderer>::render_elements::<
|
2023-01-16 20:31:43 +01:00
|
|
|
CosmicWindowRenderElement<R>,
|
2023-03-07 22:20:44 +01:00
|
|
|
>(
|
2023-05-12 20:01:37 +02:00
|
|
|
&self.0,
|
|
|
|
|
renderer.glow_renderer_mut(),
|
|
|
|
|
location,
|
|
|
|
|
scale,
|
|
|
|
|
alpha,
|
2023-03-07 22:20:44 +01:00
|
|
|
))
|
2023-01-16 20:31:43 +01:00
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
|
|
|
|
|
elements.into_iter().map(C::from).collect()
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
}
|