2025-09-25 19:20:29 -04:00
|
|
|
use crate::wayland::protocols::corner_radius::CacheableCorners;
|
2024-02-23 17:25:40 +01:00
|
|
|
use std::{
|
2024-05-13 14:16:21 -07:00
|
|
|
borrow::Cow,
|
2024-09-18 16:02:41 +02:00
|
|
|
sync::{
|
|
|
|
|
atomic::{AtomicBool, Ordering},
|
|
|
|
|
Mutex,
|
|
|
|
|
},
|
2024-02-23 17:25:40 +01:00
|
|
|
time::Duration,
|
|
|
|
|
};
|
2023-01-16 15:12:25 +01:00
|
|
|
|
|
|
|
|
use smithay::{
|
|
|
|
|
backend::renderer::{
|
2023-03-31 13:57:37 +02:00
|
|
|
element::{
|
2023-07-13 17:19:29 +02:00
|
|
|
surface::{render_elements_from_surface_tree, WaylandSurfaceRenderElement},
|
|
|
|
|
utils::select_dmabuf_feedback,
|
2025-07-22 16:39:33 +02:00
|
|
|
AsRenderElements, Kind, RenderElementStates,
|
2023-03-31 13:57:37 +02:00
|
|
|
},
|
2023-01-16 15:12:25 +01:00
|
|
|
ImportAll, Renderer,
|
|
|
|
|
},
|
|
|
|
|
desktop::{
|
2025-06-25 17:54:27 +02:00
|
|
|
space::SpaceElement, utils::OutputPresentationFeedback, PopupManager, Window,
|
|
|
|
|
WindowSurface, WindowSurfaceType,
|
2023-01-16 15:12:25 +01:00
|
|
|
},
|
2023-09-05 10:55:23 -07:00
|
|
|
input::{
|
|
|
|
|
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
|
|
|
|
|
Seat,
|
|
|
|
|
},
|
2023-01-16 15:12:25 +01:00
|
|
|
output::Output,
|
|
|
|
|
reexports::{
|
|
|
|
|
wayland_protocols::{
|
2025-07-22 16:39:33 +02:00
|
|
|
wp::presentation_time::server::wp_presentation_feedback::Kind as PresentationKind,
|
2023-01-16 15:12:25 +01:00
|
|
|
xdg::{
|
|
|
|
|
decoration::zv1::server::zxdg_toplevel_decoration_v1::Mode as DecorationMode,
|
|
|
|
|
shell::server::xdg_toplevel::State as ToplevelState,
|
|
|
|
|
},
|
|
|
|
|
},
|
2025-05-27 19:45:53 +02:00
|
|
|
wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration::Mode as KdeMode,
|
2025-09-25 19:20:29 -04:00
|
|
|
wayland_server::protocol::wl_surface::WlSurface,
|
2023-01-16 15:12:25 +01:00
|
|
|
},
|
2024-09-27 23:41:58 +02:00
|
|
|
utils::{
|
|
|
|
|
user_data::UserDataMap, IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size,
|
|
|
|
|
},
|
2023-01-16 15:12:25 +01:00
|
|
|
wayland::{
|
2025-06-25 17:54:27 +02:00
|
|
|
compositor::{with_states, with_surface_tree_downward, SurfaceData, TraversalAction},
|
2023-01-16 15:12:25 +01:00
|
|
|
seat::WaylandFocus,
|
2023-09-05 10:55:23 -07:00
|
|
|
shell::xdg::{SurfaceCachedState, ToplevelSurface, XdgToplevelSurfaceData},
|
2023-01-16 15:12:25 +01:00
|
|
|
},
|
2023-01-18 20:23:41 +01:00
|
|
|
xwayland::{xwm::X11Relatable, X11Surface},
|
2023-01-16 15:12:25 +01:00
|
|
|
};
|
2025-01-15 19:55:13 +01:00
|
|
|
use tracing::trace;
|
2023-01-16 15:12:25 +01:00
|
|
|
|
2023-09-05 10:55:23 -07:00
|
|
|
use crate::{
|
|
|
|
|
state::{State, SurfaceDmabufFeedback},
|
2023-10-25 19:24:51 +02:00
|
|
|
utils::prelude::*,
|
2025-07-22 16:31:56 +02:00
|
|
|
wayland::handlers::{
|
|
|
|
|
compositor::FRAME_TIME_FILTER,
|
|
|
|
|
decoration::{KdeDecorationData, PreferredDecorationMode},
|
|
|
|
|
},
|
2023-09-05 10:55:23 -07:00
|
|
|
};
|
2023-03-31 13:57:37 +02:00
|
|
|
|
2025-06-25 17:54:27 +02:00
|
|
|
#[derive(Debug, Clone, PartialEq, Hash, Eq)]
|
2024-02-21 13:24:56 -08:00
|
|
|
pub struct CosmicSurface(pub Window);
|
2023-01-16 15:12:25 +01:00
|
|
|
|
2023-01-18 20:23:41 +01:00
|
|
|
impl From<ToplevelSurface> for CosmicSurface {
|
|
|
|
|
fn from(s: ToplevelSurface) -> Self {
|
2024-02-21 13:24:56 -08:00
|
|
|
CosmicSurface(Window::new_wayland_window(s))
|
2023-01-18 20:23:41 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<Window> for CosmicSurface {
|
|
|
|
|
fn from(w: Window) -> Self {
|
2024-02-21 13:24:56 -08:00
|
|
|
CosmicSurface(w)
|
2023-01-18 20:23:41 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<X11Surface> for CosmicSurface {
|
|
|
|
|
fn from(s: X11Surface) -> Self {
|
2024-02-21 13:24:56 -08:00
|
|
|
CosmicSurface(Window::new_x11_window(s))
|
2023-01-18 20:23:41 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-21 12:44:40 +01:00
|
|
|
impl PartialEq<WlSurface> for CosmicSurface {
|
|
|
|
|
fn eq(&self, other: &WlSurface) -> bool {
|
2025-10-16 13:50:32 +02:00
|
|
|
self.wl_surface().is_some_and(|s| &*s == other)
|
2024-03-21 12:44:40 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-25 17:54:27 +02:00
|
|
|
impl PartialEq<ToplevelSurface> for CosmicSurface {
|
|
|
|
|
fn eq(&self, other: &ToplevelSurface) -> bool {
|
2025-10-16 13:50:32 +02:00
|
|
|
self.wl_surface().is_some_and(|s| &*s == other.wl_surface())
|
2025-06-25 17:54:27 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-21 12:44:40 +01:00
|
|
|
impl PartialEq<X11Surface> for CosmicSurface {
|
|
|
|
|
fn eq(&self, other: &X11Surface) -> bool {
|
2025-10-16 15:46:54 +02:00
|
|
|
self.x11_surface() == Some(other)
|
2024-03-21 12:44:40 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-23 17:25:40 +01:00
|
|
|
#[derive(Default)]
|
|
|
|
|
struct Minimized(AtomicBool);
|
|
|
|
|
|
2024-09-18 16:02:41 +02:00
|
|
|
#[derive(Default)]
|
|
|
|
|
struct Sticky(AtomicBool);
|
|
|
|
|
|
|
|
|
|
#[derive(Default)]
|
2024-12-05 17:30:27 +01:00
|
|
|
struct GlobalGeometry(Mutex<Option<Rectangle<i32, Global>>>);
|
2024-09-18 16:02:41 +02:00
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
impl CosmicSurface {
|
|
|
|
|
pub fn title(&self) -> String {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => with_states(toplevel.wl_surface(), |states| {
|
|
|
|
|
states
|
|
|
|
|
.data_map
|
|
|
|
|
.get::<XdgToplevelSurfaceData>()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.lock()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.title
|
|
|
|
|
.clone()
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
}),
|
2025-04-30 12:50:33 +02:00
|
|
|
WindowSurface::X11(surface) => surface.title().replace('\0', ""),
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-25 12:53:14 -04:00
|
|
|
pub fn corner_radius(&self, geometry_size: Size<i32, Logical>) -> Option<[u8; 4]> {
|
2025-09-25 11:00:57 -04:00
|
|
|
self.wl_surface().and_then(|surface| {
|
2025-09-25 12:53:14 -04:00
|
|
|
with_states(&surface, |states| {
|
2025-09-25 19:20:29 -04:00
|
|
|
let mut guard = states.cached_state.get::<CacheableCorners>();
|
2025-09-25 11:00:57 -04:00
|
|
|
|
2025-09-25 11:24:57 -04:00
|
|
|
// guard against corner radius being too large, potentially disconnecting the outline
|
2025-09-25 12:53:14 -04:00
|
|
|
let half_min_dim =
|
|
|
|
|
u8::try_from(geometry_size.w.min(geometry_size.h) / 2).unwrap_or(u8::MAX);
|
|
|
|
|
|
2025-09-25 19:20:29 -04:00
|
|
|
let corners = guard.current().0?;
|
|
|
|
|
|
|
|
|
|
Some([
|
|
|
|
|
corners.bottom_right.min(half_min_dim),
|
|
|
|
|
corners.top_right.min(half_min_dim),
|
|
|
|
|
corners.bottom_left.min(half_min_dim),
|
|
|
|
|
corners.top_left.min(half_min_dim),
|
|
|
|
|
])
|
2025-09-25 11:00:57 -04:00
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
pub fn app_id(&self) -> String {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => with_states(toplevel.wl_surface(), |states| {
|
|
|
|
|
states
|
|
|
|
|
.data_map
|
|
|
|
|
.get::<XdgToplevelSurfaceData>()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.lock()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.app_id
|
|
|
|
|
.clone()
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
}),
|
2025-04-30 12:50:33 +02:00
|
|
|
WindowSurface::X11(surface) => surface.class().replace('\0', ""),
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-23 22:15:27 +02:00
|
|
|
pub fn pending_size(&self) -> Option<Size<i32, Logical>> {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => toplevel.with_pending_state(|state| state.size),
|
|
|
|
|
WindowSurface::X11(surface) => Some(surface.geometry().size),
|
2023-10-23 22:15:27 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-05 17:30:27 +01:00
|
|
|
pub fn global_geometry(&self) -> Option<Rectangle<i32, Global>> {
|
2024-09-18 16:02:41 +02:00
|
|
|
*self
|
|
|
|
|
.0
|
|
|
|
|
.user_data()
|
|
|
|
|
.get_or_insert_threadsafe(GlobalGeometry::default)
|
|
|
|
|
.0
|
|
|
|
|
.lock()
|
2024-12-05 17:30:27 +01:00
|
|
|
.unwrap()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn set_geometry(&self, geo: Rectangle<i32, Global>, ssd_height: u32) {
|
|
|
|
|
{
|
|
|
|
|
let mut geo = geo;
|
|
|
|
|
geo.size.h += ssd_height as i32;
|
|
|
|
|
geo.loc.y -= ssd_height as i32;
|
|
|
|
|
|
|
|
|
|
*self
|
|
|
|
|
.0
|
|
|
|
|
.user_data()
|
|
|
|
|
.get_or_insert_threadsafe(GlobalGeometry::default)
|
|
|
|
|
.0
|
|
|
|
|
.lock()
|
|
|
|
|
.unwrap() = Some(geo);
|
|
|
|
|
}
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => {
|
|
|
|
|
toplevel.with_pending_state(|state| state.size = Some(geo.size.as_logical()))
|
|
|
|
|
}
|
|
|
|
|
WindowSurface::X11(surface) => {
|
2023-10-25 19:24:51 +02:00
|
|
|
let _ = surface.configure(geo.as_logical());
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-31 14:04:35 +02:00
|
|
|
pub fn set_bounds(&self, size: impl Into<Option<Size<i32, Logical>>>) {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => {
|
|
|
|
|
toplevel.with_pending_state(|state| state.bounds = size.into())
|
|
|
|
|
}
|
|
|
|
|
WindowSurface::X11(_surface) => {}
|
2023-03-31 14:04:35 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-09 16:26:13 +02:00
|
|
|
pub fn is_activated(&self, pending: bool) -> bool {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => {
|
2023-06-09 16:26:13 +02:00
|
|
|
if pending {
|
2024-02-21 13:24:56 -08:00
|
|
|
toplevel.with_pending_state(|pending| {
|
2023-06-09 16:26:13 +02:00
|
|
|
pending.states.contains(ToplevelState::Activated)
|
|
|
|
|
})
|
|
|
|
|
} else {
|
2024-02-21 13:24:56 -08:00
|
|
|
toplevel
|
2023-06-09 16:26:13 +02:00
|
|
|
.current_state()
|
|
|
|
|
.states
|
|
|
|
|
.contains(ToplevelState::Activated)
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-02-21 13:24:56 -08:00
|
|
|
WindowSurface::X11(surface) => surface.is_activated(),
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn set_activated(&self, activated: bool) {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => toplevel.with_pending_state(|state| {
|
2023-01-16 15:12:25 +01:00
|
|
|
if activated {
|
|
|
|
|
state.states.set(ToplevelState::Activated);
|
|
|
|
|
} else {
|
|
|
|
|
state.states.unset(ToplevelState::Activated);
|
|
|
|
|
}
|
|
|
|
|
}),
|
2024-02-21 13:24:56 -08:00
|
|
|
WindowSurface::X11(surface) => {
|
2023-01-16 15:12:25 +01:00
|
|
|
let _ = surface.set_activated(activated);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-09 16:26:13 +02:00
|
|
|
pub fn is_decorated(&self, pending: bool) -> bool {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => {
|
2025-05-30 17:28:51 +02:00
|
|
|
let kde_state = with_states(toplevel.wl_surface(), |states| {
|
|
|
|
|
states
|
|
|
|
|
.data_map
|
|
|
|
|
.get::<KdeDecorationData>()
|
|
|
|
|
.and_then(|data| data.lock().unwrap().mode.map(|m| m != KdeMode::Server))
|
|
|
|
|
});
|
|
|
|
|
|
2025-05-27 19:45:53 +02:00
|
|
|
let xdg_state = if pending {
|
2024-02-21 13:24:56 -08:00
|
|
|
toplevel.with_pending_state(|pending| {
|
2023-06-09 16:26:13 +02:00
|
|
|
pending
|
|
|
|
|
.decoration_mode
|
|
|
|
|
.map(|mode| mode == DecorationMode::ClientSide)
|
|
|
|
|
})
|
|
|
|
|
} else {
|
2024-02-21 13:24:56 -08:00
|
|
|
toplevel
|
2023-06-09 16:26:13 +02:00
|
|
|
.current_state()
|
|
|
|
|
.decoration_mode
|
|
|
|
|
.map(|mode| mode == DecorationMode::ClientSide)
|
2025-05-27 19:45:53 +02:00
|
|
|
};
|
|
|
|
|
|
2025-05-30 17:28:51 +02:00
|
|
|
kde_state.or(xdg_state).unwrap_or(true)
|
2023-06-09 16:26:13 +02:00
|
|
|
}
|
2024-02-21 13:24:56 -08:00
|
|
|
WindowSurface::X11(surface) => surface.is_decorated(),
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-08 13:19:30 +02:00
|
|
|
pub fn try_force_undecorated(&self, enable: bool) {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => {
|
2023-06-12 17:25:43 +02:00
|
|
|
if enable {
|
2025-10-16 15:46:54 +02:00
|
|
|
let previous_decoration_state = toplevel.current_state().decoration_mode;
|
2024-02-21 13:24:56 -08:00
|
|
|
if PreferredDecorationMode::is_unset(&self.0) {
|
|
|
|
|
PreferredDecorationMode::update(&self.0, previous_decoration_state);
|
2023-06-14 16:43:13 +02:00
|
|
|
}
|
2024-02-21 13:24:56 -08:00
|
|
|
toplevel.with_pending_state(|pending| {
|
2023-06-12 17:25:43 +02:00
|
|
|
pending.decoration_mode = Some(DecorationMode::ServerSide);
|
|
|
|
|
});
|
2025-05-27 19:45:53 +02:00
|
|
|
with_states(toplevel.wl_surface(), |data| {
|
|
|
|
|
if let Some(kde_data) = data.data_map.get::<KdeDecorationData>() {
|
|
|
|
|
for obj in kde_data.lock().unwrap().objs.iter() {
|
|
|
|
|
obj.mode(KdeMode::Server);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
2023-06-08 13:19:30 +02:00
|
|
|
} else {
|
2024-02-21 13:24:56 -08:00
|
|
|
let previous_mode = PreferredDecorationMode::mode(&self.0);
|
|
|
|
|
toplevel.with_pending_state(|pending| {
|
2023-06-12 17:25:43 +02:00
|
|
|
pending.decoration_mode = previous_mode;
|
|
|
|
|
});
|
2025-05-27 19:45:53 +02:00
|
|
|
with_states(toplevel.wl_surface(), |data| {
|
|
|
|
|
if let Some(kde_data) = data.data_map.get::<KdeDecorationData>() {
|
|
|
|
|
for obj in kde_data.lock().unwrap().objs.iter() {
|
|
|
|
|
obj.mode(KdeMode::Server);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
2023-06-12 17:25:43 +02:00
|
|
|
}
|
|
|
|
|
}
|
2024-02-21 13:24:56 -08:00
|
|
|
WindowSurface::X11(_surface) => {}
|
2023-06-08 13:19:30 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-09 16:26:13 +02:00
|
|
|
pub fn is_resizing(&self, pending: bool) -> Option<bool> {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => {
|
2023-06-09 16:26:13 +02:00
|
|
|
if pending {
|
2024-02-21 13:24:56 -08:00
|
|
|
Some(toplevel.with_pending_state(|pending| {
|
2023-06-09 16:26:13 +02:00
|
|
|
pending.states.contains(ToplevelState::Resizing)
|
|
|
|
|
}))
|
|
|
|
|
} else {
|
|
|
|
|
Some(
|
2024-02-21 13:24:56 -08:00
|
|
|
toplevel
|
2023-06-09 16:26:13 +02:00
|
|
|
.current_state()
|
|
|
|
|
.states
|
|
|
|
|
.contains(ToplevelState::Resizing),
|
|
|
|
|
)
|
|
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
2024-02-21 13:24:56 -08:00
|
|
|
WindowSurface::X11(_surface) => None,
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn set_resizing(&self, resizing: bool) {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => toplevel.with_pending_state(|state| {
|
2023-01-16 15:12:25 +01:00
|
|
|
if resizing {
|
|
|
|
|
state.states.set(ToplevelState::Resizing);
|
|
|
|
|
} else {
|
|
|
|
|
state.states.unset(ToplevelState::Resizing);
|
|
|
|
|
}
|
|
|
|
|
}),
|
2024-02-21 13:24:56 -08:00
|
|
|
WindowSurface::X11(_surface) => {}
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-09 16:26:13 +02:00
|
|
|
pub fn is_tiled(&self, pending: bool) -> Option<bool> {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => {
|
2023-06-09 16:26:13 +02:00
|
|
|
if pending {
|
2024-02-21 13:24:56 -08:00
|
|
|
Some(toplevel.with_pending_state(|pending| {
|
2023-06-09 16:26:13 +02:00
|
|
|
pending.states.contains(ToplevelState::TiledLeft)
|
|
|
|
|
}))
|
|
|
|
|
} else {
|
|
|
|
|
Some(
|
2024-02-21 13:24:56 -08:00
|
|
|
toplevel
|
2023-06-09 16:26:13 +02:00
|
|
|
.current_state()
|
|
|
|
|
.states
|
|
|
|
|
.contains(ToplevelState::TiledLeft),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-02-21 13:24:56 -08:00
|
|
|
WindowSurface::X11(_surface) => None,
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn set_tiled(&self, tiled: bool) {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => toplevel.with_pending_state(|state| {
|
2023-01-16 15:12:25 +01:00
|
|
|
if tiled {
|
|
|
|
|
state.states.set(ToplevelState::TiledLeft);
|
|
|
|
|
state.states.set(ToplevelState::TiledRight);
|
|
|
|
|
state.states.set(ToplevelState::TiledTop);
|
|
|
|
|
state.states.set(ToplevelState::TiledBottom);
|
|
|
|
|
} else {
|
|
|
|
|
state.states.unset(ToplevelState::TiledLeft);
|
|
|
|
|
state.states.unset(ToplevelState::TiledRight);
|
|
|
|
|
state.states.unset(ToplevelState::TiledTop);
|
|
|
|
|
state.states.unset(ToplevelState::TiledBottom);
|
|
|
|
|
}
|
|
|
|
|
}),
|
2024-02-21 13:24:56 -08:00
|
|
|
WindowSurface::X11(_surface) => {}
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-09 16:26:13 +02:00
|
|
|
pub fn is_fullscreen(&self, pending: bool) -> bool {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => {
|
2023-06-09 16:26:13 +02:00
|
|
|
if pending {
|
2024-02-21 13:24:56 -08:00
|
|
|
toplevel.with_pending_state(|pending| {
|
2023-06-09 16:26:13 +02:00
|
|
|
pending.states.contains(ToplevelState::Fullscreen)
|
2023-01-16 15:12:25 +01:00
|
|
|
})
|
2023-06-09 16:26:13 +02:00
|
|
|
} else {
|
2024-02-21 13:24:56 -08:00
|
|
|
toplevel
|
2023-06-09 16:26:13 +02:00
|
|
|
.current_state()
|
|
|
|
|
.states
|
|
|
|
|
.contains(ToplevelState::Fullscreen)
|
|
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
2024-02-21 13:24:56 -08:00
|
|
|
WindowSurface::X11(surface) => surface.is_fullscreen(),
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn set_fullscreen(&self, fullscreen: bool) {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => toplevel.with_pending_state(|state| {
|
2023-01-16 15:12:25 +01:00
|
|
|
if fullscreen {
|
|
|
|
|
state.states.set(ToplevelState::Fullscreen);
|
|
|
|
|
} else {
|
|
|
|
|
state.states.unset(ToplevelState::Fullscreen);
|
|
|
|
|
}
|
|
|
|
|
}),
|
2024-02-21 13:24:56 -08:00
|
|
|
WindowSurface::X11(surface) => {
|
2023-01-16 15:12:25 +01:00
|
|
|
let _ = surface.set_fullscreen(fullscreen);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-09 16:26:13 +02:00
|
|
|
pub fn is_maximized(&self, pending: bool) -> bool {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => {
|
2023-06-09 16:26:13 +02:00
|
|
|
if pending {
|
2024-02-21 13:24:56 -08:00
|
|
|
toplevel.with_pending_state(|pending| {
|
2023-06-09 16:26:13 +02:00
|
|
|
pending.states.contains(ToplevelState::Maximized)
|
|
|
|
|
})
|
|
|
|
|
} else {
|
2024-02-21 13:24:56 -08:00
|
|
|
toplevel
|
2023-06-09 16:26:13 +02:00
|
|
|
.current_state()
|
|
|
|
|
.states
|
|
|
|
|
.contains(ToplevelState::Maximized)
|
|
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
2024-02-21 13:24:56 -08:00
|
|
|
WindowSurface::X11(surface) => surface.is_maximized(),
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn set_maximized(&self, maximized: bool) {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => toplevel.with_pending_state(|state| {
|
2023-01-16 15:12:25 +01:00
|
|
|
if maximized {
|
|
|
|
|
state.states.set(ToplevelState::Maximized);
|
|
|
|
|
} else {
|
|
|
|
|
state.states.unset(ToplevelState::Maximized);
|
|
|
|
|
}
|
|
|
|
|
}),
|
2024-02-21 13:24:56 -08:00
|
|
|
WindowSurface::X11(surface) => {
|
2023-01-16 15:12:25 +01:00
|
|
|
let _ = surface.set_maximized(maximized);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-23 17:25:40 +01:00
|
|
|
pub fn is_minimized(&self) -> bool {
|
2024-07-09 17:22:00 +02:00
|
|
|
self.0
|
|
|
|
|
.user_data()
|
|
|
|
|
.get_or_insert_threadsafe(Minimized::default)
|
|
|
|
|
.0
|
|
|
|
|
.load(Ordering::SeqCst)
|
2024-02-23 17:25:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn set_minimized(&self, minimized: bool) {
|
2024-07-09 17:22:00 +02:00
|
|
|
self.0
|
|
|
|
|
.user_data()
|
|
|
|
|
.get_or_insert_threadsafe(Minimized::default)
|
|
|
|
|
.0
|
|
|
|
|
.store(minimized, Ordering::SeqCst);
|
2024-07-10 21:56:24 +02:00
|
|
|
if !minimized {
|
|
|
|
|
if let WindowSurface::X11(surface) = self.0.underlying_surface() {
|
|
|
|
|
let _ = surface.set_mapped(false);
|
|
|
|
|
let _ = surface.set_mapped(true);
|
|
|
|
|
}
|
2024-02-23 17:25:40 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-18 16:02:41 +02:00
|
|
|
pub fn is_sticky(&self) -> bool {
|
|
|
|
|
self.0
|
|
|
|
|
.user_data()
|
|
|
|
|
.get_or_insert_threadsafe(Sticky::default)
|
|
|
|
|
.0
|
|
|
|
|
.load(Ordering::SeqCst)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn set_sticky(&self, sticky: bool) {
|
|
|
|
|
self.0
|
|
|
|
|
.user_data()
|
|
|
|
|
.get_or_insert_threadsafe(Sticky::default)
|
|
|
|
|
.0
|
|
|
|
|
.store(sticky, Ordering::SeqCst);
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-23 17:25:40 +01:00
|
|
|
pub fn set_suspended(&self, suspended: bool) {
|
|
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(window) => window.with_pending_state(|state| {
|
|
|
|
|
if suspended {
|
|
|
|
|
state.states.set(ToplevelState::Suspended);
|
|
|
|
|
} else {
|
|
|
|
|
state.states.unset(ToplevelState::Suspended);
|
|
|
|
|
}
|
|
|
|
|
}),
|
2024-07-09 17:22:00 +02:00
|
|
|
WindowSurface::X11(surface) => {
|
2024-08-02 09:31:29 -04:00
|
|
|
let _ = surface.set_suspended(suspended);
|
2024-07-09 17:22:00 +02:00
|
|
|
}
|
2024-02-23 17:25:40 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-25 14:11:22 +01:00
|
|
|
pub fn min_size_without_ssd(&self) -> Option<Size<i32, Logical>> {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => {
|
|
|
|
|
Some(with_states(toplevel.wl_surface(), |states| {
|
2024-06-07 18:58:33 +02:00
|
|
|
states
|
|
|
|
|
.cached_state
|
|
|
|
|
.get::<SurfaceCachedState>()
|
|
|
|
|
.current()
|
|
|
|
|
.min_size
|
2023-01-16 15:12:25 +01:00
|
|
|
}))
|
|
|
|
|
.filter(|size| !(size.w == 0 && size.h == 0))
|
|
|
|
|
}
|
2024-02-21 13:24:56 -08:00
|
|
|
WindowSurface::X11(surface) => surface.min_size(),
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-25 14:11:22 +01:00
|
|
|
pub fn max_size_without_ssd(&self) -> Option<Size<i32, Logical>> {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => {
|
|
|
|
|
Some(with_states(toplevel.wl_surface(), |states| {
|
2024-06-07 18:58:33 +02:00
|
|
|
states
|
|
|
|
|
.cached_state
|
|
|
|
|
.get::<SurfaceCachedState>()
|
|
|
|
|
.current()
|
|
|
|
|
.max_size
|
2023-01-16 15:12:25 +01:00
|
|
|
}))
|
|
|
|
|
.filter(|size| !(size.w == 0 && size.h == 0))
|
|
|
|
|
}
|
2024-02-21 13:24:56 -08:00
|
|
|
WindowSurface::X11(surface) => surface.max_size(),
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-12 20:01:37 +02:00
|
|
|
pub fn serial_acked(&self, serial: &Serial) -> bool {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => with_states(toplevel.wl_surface(), |states| {
|
|
|
|
|
let attrs = states
|
|
|
|
|
.data_map
|
|
|
|
|
.get::<XdgToplevelSurfaceData>()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.lock()
|
|
|
|
|
.unwrap();
|
|
|
|
|
attrs
|
|
|
|
|
.configure_serial
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| s >= serial)
|
|
|
|
|
.unwrap_or(false)
|
|
|
|
|
}),
|
|
|
|
|
WindowSurface::X11(_surface) => true,
|
2023-05-12 20:01:37 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-15 19:55:13 +01:00
|
|
|
pub fn serial_past(&self, serial: &Serial) -> bool {
|
|
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => with_states(toplevel.wl_surface(), |states| {
|
|
|
|
|
let attrs = states
|
|
|
|
|
.data_map
|
|
|
|
|
.get::<XdgToplevelSurfaceData>()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.lock()
|
|
|
|
|
.unwrap();
|
|
|
|
|
attrs
|
|
|
|
|
.current_serial
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| s >= serial)
|
|
|
|
|
.unwrap_or(false)
|
|
|
|
|
}),
|
|
|
|
|
WindowSurface::X11(_surface) => true,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn latest_size_committed(&self) -> bool {
|
|
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => {
|
|
|
|
|
with_states(toplevel.wl_surface(), |states| {
|
|
|
|
|
let attributes = states
|
|
|
|
|
.data_map
|
|
|
|
|
.get::<XdgToplevelSurfaceData>()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.lock()
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
let current_server = attributes.current_server_state();
|
|
|
|
|
if attributes.current.size == current_server.size {
|
|
|
|
|
// The window had committed for our previous size change, so we can
|
|
|
|
|
// change the size again.
|
|
|
|
|
trace!(
|
|
|
|
|
"current size matches server size: {:?}",
|
|
|
|
|
attributes.current.size
|
|
|
|
|
);
|
|
|
|
|
true
|
|
|
|
|
} else {
|
|
|
|
|
// The window had not committed for our previous size change yet.
|
|
|
|
|
// This throttling is done because some clients do not batch size requests,
|
|
|
|
|
// leading to bad behavior with very fast input devices (i.e. a 1000 Hz
|
|
|
|
|
// mouse). This throttling also helps interactive resize transactions
|
|
|
|
|
// preserve visual consistency.
|
|
|
|
|
trace!("throttling resize");
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
WindowSurface::X11(_) => true,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-12 20:01:37 +02:00
|
|
|
pub fn force_configure(&self) -> Option<Serial> {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => Some(toplevel.send_configure()),
|
|
|
|
|
WindowSurface::X11(surface) => {
|
2023-01-16 15:12:25 +01:00
|
|
|
let _ = surface.configure(None);
|
2023-05-12 20:01:37 +02:00
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn send_configure(&self) -> Option<Serial> {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => toplevel.send_pending_configure(),
|
|
|
|
|
WindowSurface::X11(_) => None,
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn close(&self) {
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => toplevel.send_close(),
|
|
|
|
|
WindowSurface::X11(surface) => {
|
2023-01-16 15:12:25 +01:00
|
|
|
let _ = surface.close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-25 17:54:27 +02:00
|
|
|
pub fn has_surface(&self, surface: &WlSurface, surface_type: WindowSurfaceType) -> bool {
|
|
|
|
|
let Some(toplevel) = self.wl_surface() else {
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
2025-10-16 13:50:32 +02:00
|
|
|
if surface_type.contains(WindowSurfaceType::TOPLEVEL) && *toplevel == *surface {
|
|
|
|
|
return true;
|
2025-06-25 17:54:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if surface_type.contains(WindowSurfaceType::SUBSURFACE) {
|
|
|
|
|
use std::sync::atomic::Ordering;
|
|
|
|
|
|
|
|
|
|
let found = AtomicBool::new(false);
|
|
|
|
|
with_surface_tree_downward(
|
|
|
|
|
&toplevel,
|
|
|
|
|
surface,
|
|
|
|
|
|_, _, search| TraversalAction::DoChildren(search),
|
|
|
|
|
|s, _, search| {
|
|
|
|
|
found.fetch_or(s == *search, Ordering::SeqCst);
|
|
|
|
|
},
|
|
|
|
|
|_, _, _| !found.load(Ordering::SeqCst),
|
|
|
|
|
);
|
|
|
|
|
if found.load(Ordering::SeqCst) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if surface_type.contains(WindowSurfaceType::POPUP) {
|
|
|
|
|
PopupManager::popups_for_surface(&toplevel).any(|(p, _)| p.wl_surface() == surface)
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
pub fn on_commit(&self) {
|
2024-02-21 13:24:56 -08:00
|
|
|
self.0.on_commit();
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn send_frame<T, F>(
|
|
|
|
|
&self,
|
|
|
|
|
output: &Output,
|
|
|
|
|
time: T,
|
|
|
|
|
throttle: Option<Duration>,
|
|
|
|
|
primary_scan_out_output: F,
|
|
|
|
|
) where
|
|
|
|
|
T: Into<Duration>,
|
|
|
|
|
F: FnMut(&WlSurface, &SurfaceData) -> Option<Output> + Copy,
|
|
|
|
|
{
|
2024-02-21 13:24:56 -08:00
|
|
|
self.0
|
|
|
|
|
.send_frame(output, time, throttle, primary_scan_out_output);
|
2023-03-31 13:57:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn send_dmabuf_feedback<F1>(
|
|
|
|
|
&self,
|
|
|
|
|
output: &Output,
|
|
|
|
|
feedback: &SurfaceDmabufFeedback,
|
|
|
|
|
render_element_states: &RenderElementStates,
|
|
|
|
|
primary_scan_out_output: F1,
|
|
|
|
|
) where
|
|
|
|
|
F1: FnMut(&WlSurface, &SurfaceData) -> Option<Output> + Copy,
|
|
|
|
|
{
|
2025-01-02 21:32:47 +01:00
|
|
|
let is_fullscreen = self.is_fullscreen(false);
|
|
|
|
|
|
2024-02-21 13:24:56 -08:00
|
|
|
self.0
|
|
|
|
|
.send_dmabuf_feedback(output, primary_scan_out_output, |surface, _| {
|
|
|
|
|
select_dmabuf_feedback(
|
|
|
|
|
surface,
|
|
|
|
|
render_element_states,
|
|
|
|
|
&feedback.render_feedback,
|
2025-01-02 21:32:47 +01:00
|
|
|
if is_fullscreen {
|
|
|
|
|
&feedback.primary_scanout_feedback
|
|
|
|
|
} else {
|
|
|
|
|
&feedback.scanout_feedback
|
|
|
|
|
},
|
2024-02-21 13:24:56 -08:00
|
|
|
)
|
|
|
|
|
})
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn take_presentation_feedback<F1, F2>(
|
|
|
|
|
&self,
|
|
|
|
|
output_feedback: &mut OutputPresentationFeedback,
|
|
|
|
|
primary_scan_out_output: F1,
|
|
|
|
|
presentation_feedback_flags: F2,
|
|
|
|
|
) where
|
|
|
|
|
F1: FnMut(&WlSurface, &SurfaceData) -> Option<Output> + Copy,
|
2025-07-22 16:39:33 +02:00
|
|
|
F2: FnMut(&WlSurface, &SurfaceData) -> PresentationKind + Copy,
|
2023-01-16 15:12:25 +01:00
|
|
|
{
|
2024-02-21 13:24:56 -08:00
|
|
|
self.0.take_presentation_feedback(
|
|
|
|
|
output_feedback,
|
|
|
|
|
primary_scan_out_output,
|
|
|
|
|
presentation_feedback_flags,
|
|
|
|
|
)
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn with_surfaces<F>(&self, processor: F)
|
|
|
|
|
where
|
2023-11-14 17:30:11 +01:00
|
|
|
F: FnMut(&WlSurface, &SurfaceData),
|
2023-01-16 15:12:25 +01:00
|
|
|
{
|
2024-02-21 13:24:56 -08:00
|
|
|
self.0.with_surfaces(processor)
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn user_data(&self) -> &UserDataMap {
|
2024-02-21 13:24:56 -08:00
|
|
|
self.0.user_data()
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
2023-07-13 17:19:29 +02:00
|
|
|
|
2024-09-27 23:41:58 +02:00
|
|
|
pub fn popup_render_elements<R, C>(
|
2023-07-13 17:19:29 +02:00
|
|
|
&self,
|
|
|
|
|
renderer: &mut R,
|
2024-09-27 23:41:58 +02:00
|
|
|
location: Point<i32, Physical>,
|
|
|
|
|
scale: Scale<f64>,
|
2023-07-13 17:19:29 +02:00
|
|
|
alpha: f32,
|
2024-09-27 23:41:58 +02:00
|
|
|
) -> Vec<C>
|
2023-07-13 17:19:29 +02:00
|
|
|
where
|
|
|
|
|
R: Renderer + ImportAll,
|
2025-03-11 19:14:49 +01:00
|
|
|
R::TextureId: Clone + 'static,
|
2023-07-13 17:19:29 +02:00
|
|
|
C: From<WaylandSurfaceRenderElement<R>>,
|
|
|
|
|
{
|
2024-02-21 13:24:56 -08:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => {
|
|
|
|
|
let surface = toplevel.wl_surface();
|
2024-09-27 23:41:58 +02:00
|
|
|
PopupManager::popups_for_surface(surface)
|
|
|
|
|
.flat_map(move |(popup, popup_offset)| {
|
2024-02-21 13:24:56 -08:00
|
|
|
let offset = (self.0.geometry().loc + popup_offset - popup.geometry().loc)
|
2023-07-13 17:19:29 +02:00
|
|
|
.to_physical_precise_round(scale);
|
|
|
|
|
|
|
|
|
|
render_elements_from_surface_tree(
|
|
|
|
|
renderer,
|
|
|
|
|
popup.wl_surface(),
|
|
|
|
|
location + offset,
|
|
|
|
|
scale,
|
|
|
|
|
alpha,
|
2025-07-22 16:31:56 +02:00
|
|
|
FRAME_TIME_FILTER,
|
2023-07-13 17:19:29 +02:00
|
|
|
)
|
|
|
|
|
})
|
2024-09-27 23:41:58 +02:00
|
|
|
.collect()
|
|
|
|
|
}
|
|
|
|
|
WindowSurface::X11(_) => Vec::new(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn render_elements<R, C>(
|
|
|
|
|
&self,
|
|
|
|
|
renderer: &mut R,
|
|
|
|
|
location: Point<i32, Physical>,
|
|
|
|
|
scale: Scale<f64>,
|
|
|
|
|
alpha: f32,
|
2025-07-22 16:39:33 +02:00
|
|
|
scanout_override: Option<bool>,
|
2024-09-27 23:41:58 +02:00
|
|
|
) -> Vec<C>
|
|
|
|
|
where
|
|
|
|
|
R: Renderer + ImportAll,
|
2025-03-11 19:14:49 +01:00
|
|
|
R::TextureId: Clone + 'static,
|
2024-09-27 23:41:58 +02:00
|
|
|
C: From<WaylandSurfaceRenderElement<R>>,
|
|
|
|
|
{
|
|
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => {
|
|
|
|
|
let surface = toplevel.wl_surface();
|
2023-07-13 17:19:29 +02:00
|
|
|
|
2024-09-27 23:41:58 +02:00
|
|
|
render_elements_from_surface_tree(
|
2023-09-13 20:24:11 -07:00
|
|
|
renderer,
|
|
|
|
|
surface,
|
|
|
|
|
location,
|
|
|
|
|
scale,
|
|
|
|
|
alpha,
|
2025-07-22 16:39:33 +02:00
|
|
|
scanout_override
|
|
|
|
|
.map(|val| {
|
|
|
|
|
if val {
|
|
|
|
|
Kind::ScanoutCandidate
|
|
|
|
|
} else {
|
|
|
|
|
Kind::Unspecified
|
|
|
|
|
}
|
|
|
|
|
.into()
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or(FRAME_TIME_FILTER),
|
2024-09-27 23:41:58 +02:00
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
WindowSurface::X11(surface) => {
|
2025-07-22 16:31:56 +02:00
|
|
|
let Some(surface) = surface.wl_surface() else {
|
|
|
|
|
return Vec::new();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
render_elements_from_surface_tree(
|
|
|
|
|
renderer,
|
|
|
|
|
&surface,
|
|
|
|
|
location,
|
|
|
|
|
scale,
|
|
|
|
|
alpha,
|
2025-07-22 16:39:33 +02:00
|
|
|
scanout_override
|
|
|
|
|
.map(|val| {
|
|
|
|
|
if val {
|
|
|
|
|
Kind::ScanoutCandidate
|
|
|
|
|
} else {
|
|
|
|
|
Kind::Unspecified
|
|
|
|
|
}
|
|
|
|
|
.into()
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or(FRAME_TIME_FILTER),
|
2025-07-22 16:31:56 +02:00
|
|
|
)
|
2023-07-13 17:19:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-02-21 13:24:56 -08:00
|
|
|
|
|
|
|
|
pub fn x11_surface(&self) -> Option<&X11Surface> {
|
|
|
|
|
self.0.x11_surface()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl IsAlive for CosmicSurface {
|
|
|
|
|
fn alive(&self) -> bool {
|
|
|
|
|
self.0.alive()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl SpaceElement for CosmicSurface {
|
|
|
|
|
fn geometry(&self) -> Rectangle<i32, Logical> {
|
|
|
|
|
SpaceElement::geometry(&self.0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn bbox(&self) -> Rectangle<i32, Logical> {
|
|
|
|
|
SpaceElement::bbox(&self.0)
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-27 23:41:58 +02:00
|
|
|
fn is_in_input_region(&self, point: &Point<f64, smithay::utils::Logical>) -> bool {
|
2024-02-21 13:24:56 -08:00
|
|
|
SpaceElement::is_in_input_region(&self.0, point)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn z_index(&self) -> u8 {
|
|
|
|
|
SpaceElement::z_index(&self.0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_activate(&self, activated: bool) {
|
|
|
|
|
SpaceElement::set_activate(&self.0, activated)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn output_enter(
|
|
|
|
|
&self,
|
|
|
|
|
output: &Output,
|
|
|
|
|
overlap: smithay::utils::Rectangle<i32, smithay::utils::Logical>,
|
|
|
|
|
) {
|
|
|
|
|
SpaceElement::output_enter(&self.0, output, overlap)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn output_leave(&self, output: &Output) {
|
|
|
|
|
SpaceElement::output_leave(&self.0, output)
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-07 19:15:44 -07:00
|
|
|
#[profiling::function]
|
2024-02-21 13:24:56 -08:00
|
|
|
fn refresh(&self) {
|
|
|
|
|
SpaceElement::refresh(&self.0)
|
|
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
|
2023-09-05 10:55:23 -07:00
|
|
|
impl KeyboardTarget<State> for CosmicSurface {
|
2023-01-16 15:12:25 +01:00
|
|
|
fn enter(
|
|
|
|
|
&self,
|
2023-09-05 10:55:23 -07:00
|
|
|
seat: &Seat<State>,
|
|
|
|
|
data: &mut State,
|
2024-02-21 13:24:56 -08:00
|
|
|
mut keys: Vec<KeysymHandle<'_>>,
|
2023-01-16 15:12:25 +01:00
|
|
|
serial: smithay::utils::Serial,
|
|
|
|
|
) {
|
2024-02-21 13:24:56 -08:00
|
|
|
if self.0.is_x11() {
|
|
|
|
|
keys = vec![];
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
2024-03-26 16:45:30 +01:00
|
|
|
|
|
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => {
|
|
|
|
|
KeyboardTarget::enter(toplevel.wl_surface(), seat, data, keys, serial)
|
|
|
|
|
}
|
|
|
|
|
WindowSurface::X11(x11) => KeyboardTarget::enter(x11, seat, data, keys, serial),
|
|
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
|
2023-09-05 10:55:23 -07:00
|
|
|
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: smithay::utils::Serial) {
|
2024-03-26 16:45:30 +01:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => {
|
|
|
|
|
KeyboardTarget::leave(toplevel.wl_surface(), seat, data, serial)
|
|
|
|
|
}
|
|
|
|
|
WindowSurface::X11(x11) => KeyboardTarget::leave(x11, seat, data, serial),
|
|
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn key(
|
|
|
|
|
&self,
|
2023-09-05 10:55:23 -07:00
|
|
|
seat: &Seat<State>,
|
|
|
|
|
data: &mut State,
|
|
|
|
|
key: KeysymHandle<'_>,
|
2023-01-16 15:12:25 +01:00
|
|
|
state: smithay::backend::input::KeyState,
|
|
|
|
|
serial: smithay::utils::Serial,
|
|
|
|
|
time: u32,
|
|
|
|
|
) {
|
2024-03-26 16:45:30 +01:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => {
|
|
|
|
|
KeyboardTarget::key(toplevel.wl_surface(), seat, data, key, state, serial, time)
|
|
|
|
|
}
|
|
|
|
|
WindowSurface::X11(x11) => {
|
|
|
|
|
KeyboardTarget::key(x11, seat, data, key, state, serial, time)
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn modifiers(
|
|
|
|
|
&self,
|
2023-09-05 10:55:23 -07:00
|
|
|
seat: &Seat<State>,
|
|
|
|
|
data: &mut State,
|
|
|
|
|
modifiers: ModifiersState,
|
2023-01-16 15:12:25 +01:00
|
|
|
serial: smithay::utils::Serial,
|
|
|
|
|
) {
|
2024-03-26 16:45:30 +01:00
|
|
|
match self.0.underlying_surface() {
|
|
|
|
|
WindowSurface::Wayland(toplevel) => {
|
|
|
|
|
KeyboardTarget::modifiers(toplevel.wl_surface(), seat, data, modifiers, serial)
|
|
|
|
|
}
|
|
|
|
|
WindowSurface::X11(x11) => {
|
|
|
|
|
KeyboardTarget::modifiers(x11, seat, data, modifiers, serial)
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-09-05 10:55:23 -07:00
|
|
|
}
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl WaylandFocus for CosmicSurface {
|
2024-05-13 14:16:21 -07:00
|
|
|
fn wl_surface(&self) -> Option<Cow<'_, WlSurface>> {
|
2024-02-21 13:24:56 -08:00
|
|
|
self.0.wl_surface()
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-13 17:19:29 +02:00
|
|
|
impl X11Relatable for CosmicSurface {
|
|
|
|
|
fn is_window(&self, window: &X11Surface) -> bool {
|
2024-02-21 13:24:56 -08:00
|
|
|
self.x11_surface() == Some(window)
|
2023-07-13 17:19:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
impl<R> AsRenderElements<R> for CosmicSurface
|
|
|
|
|
where
|
|
|
|
|
R: Renderer + ImportAll,
|
2025-03-11 19:14:49 +01:00
|
|
|
R::TextureId: Clone + 'static,
|
2023-01-16 15:12:25 +01:00
|
|
|
{
|
|
|
|
|
type RenderElement = WaylandSurfaceRenderElement<R>;
|
|
|
|
|
|
|
|
|
|
fn render_elements<C: From<Self::RenderElement>>(
|
|
|
|
|
&self,
|
|
|
|
|
renderer: &mut R,
|
2024-09-27 23:41:58 +02:00
|
|
|
location: Point<i32, Physical>,
|
|
|
|
|
scale: Scale<f64>,
|
2023-05-12 20:01:37 +02:00
|
|
|
alpha: f32,
|
2023-01-16 15:12:25 +01:00
|
|
|
) -> Vec<C> {
|
2024-02-21 13:24:56 -08:00
|
|
|
self.0.render_elements(renderer, location, scale, alpha)
|
2023-01-16 15:12:25 +01:00
|
|
|
}
|
|
|
|
|
}
|