2022-07-04 15:28:03 +02:00
|
|
|
use crate::{
|
2023-05-19 19:44:57 +02:00
|
|
|
backend::render::{
|
|
|
|
|
element::{AsGlowFrame, AsGlowRenderer},
|
2023-05-26 20:51:10 +02:00
|
|
|
BackdropShader, GlMultiError, GlMultiFrame, GlMultiRenderer,
|
2023-05-19 19:44:57 +02:00
|
|
|
},
|
|
|
|
|
shell::{
|
2023-07-17 21:11:23 +02:00
|
|
|
grabs::MoveGrab,
|
2023-09-15 18:37:34 +02:00
|
|
|
layout::{floating::FloatingLayout, tiling::TilingLayout},
|
|
|
|
|
OverviewMode, ANIMATION_DURATION,
|
2022-09-28 12:01:29 +02:00
|
|
|
},
|
2022-07-04 15:28:03 +02:00
|
|
|
state::State,
|
2023-09-15 18:37:34 +02:00
|
|
|
utils::{prelude::*, tween::EaseRectangle},
|
2022-11-03 18:51:27 +01:00
|
|
|
wayland::{
|
2023-05-22 20:19:11 +02:00
|
|
|
handlers::screencopy::DropableSession,
|
2022-11-03 18:51:27 +01:00
|
|
|
protocols::{
|
|
|
|
|
screencopy::{BufferParams, Session as ScreencopySession},
|
2023-01-24 21:01:11 +01:00
|
|
|
toplevel_info::ToplevelInfoState,
|
2022-11-03 18:51:27 +01:00
|
|
|
workspace::WorkspaceHandle,
|
|
|
|
|
},
|
|
|
|
|
},
|
2023-01-23 22:56:10 +01:00
|
|
|
xwayland::XWaylandState,
|
2022-07-04 15:28:03 +02:00
|
|
|
};
|
|
|
|
|
|
2023-10-10 13:55:34 -04:00
|
|
|
use cosmic::theme::CosmicTheme;
|
2023-09-08 22:16:39 +02:00
|
|
|
use id_tree::Tree;
|
2022-09-28 12:01:29 +02:00
|
|
|
use indexmap::IndexSet;
|
2023-09-15 18:37:34 +02:00
|
|
|
use keyframe::{ease, functions::EaseInOutCubic};
|
2022-03-24 20:32:31 +01:00
|
|
|
use smithay::{
|
2023-05-26 20:51:10 +02:00
|
|
|
backend::renderer::{
|
|
|
|
|
element::{
|
2023-09-15 18:37:34 +02:00
|
|
|
surface::WaylandSurfaceRenderElement, texture::TextureRenderElement,
|
|
|
|
|
utils::RescaleRenderElement, AsRenderElements, Element, Id, RenderElement,
|
2023-05-19 19:44:57 +02:00
|
|
|
},
|
2023-05-26 20:51:10 +02:00
|
|
|
gles::{GlesError, GlesTexture},
|
|
|
|
|
glow::{GlowFrame, GlowRenderer},
|
|
|
|
|
ImportAll, ImportMem, Renderer,
|
2022-09-28 12:01:29 +02:00
|
|
|
},
|
2023-09-15 18:37:34 +02:00
|
|
|
desktop::{layer_map_for_output, space::SpaceElement},
|
2022-08-31 13:01:23 +02:00
|
|
|
input::{pointer::GrabStartData as PointerGrabStartData, Seat},
|
2022-11-03 18:51:27 +01:00
|
|
|
output::Output,
|
2023-09-15 18:37:34 +02:00
|
|
|
reexports::wayland_server::{protocol::wl_surface::WlSurface, Client, Resource},
|
2023-05-22 16:55:29 +02:00
|
|
|
utils::{Buffer as BufferCoords, IsAlive, Logical, Physical, Point, Rectangle, Scale, Size},
|
2023-09-15 18:37:34 +02:00
|
|
|
wayland::{
|
|
|
|
|
compositor::{add_blocker, Blocker, BlockerState},
|
|
|
|
|
seat::WaylandFocus,
|
|
|
|
|
},
|
2023-01-27 19:51:23 +01:00
|
|
|
xwayland::X11Surface,
|
2022-09-28 12:01:29 +02:00
|
|
|
};
|
2023-09-15 18:37:34 +02:00
|
|
|
use std::{
|
2023-10-25 19:41:30 +02:00
|
|
|
collections::{HashMap, VecDeque},
|
2023-09-15 18:37:34 +02:00
|
|
|
sync::{
|
|
|
|
|
atomic::{AtomicBool, Ordering},
|
|
|
|
|
Arc,
|
|
|
|
|
},
|
|
|
|
|
time::{Duration, Instant},
|
|
|
|
|
};
|
2023-02-24 17:41:52 +01:00
|
|
|
use tracing::warn;
|
2023-07-06 00:02:29 +02:00
|
|
|
use wayland_backend::server::ClientId;
|
2022-09-28 12:01:29 +02:00
|
|
|
|
|
|
|
|
use super::{
|
2023-07-06 00:03:26 +02:00
|
|
|
element::{
|
|
|
|
|
resize_indicator::ResizeIndicator, stack::CosmicStackRenderElement,
|
2023-08-11 18:15:22 +02:00
|
|
|
swap_indicator::SwapIndicator, window::CosmicWindowRenderElement, CosmicMapped,
|
2023-10-25 19:41:30 +02:00
|
|
|
MaximizedState,
|
2023-07-06 00:03:26 +02:00
|
|
|
},
|
2023-07-11 16:33:23 +02:00
|
|
|
focus::{
|
2023-08-11 18:15:22 +02:00
|
|
|
target::{KeyboardFocusTarget, PointerFocusTarget, WindowGroup},
|
2023-09-20 16:30:37 +02:00
|
|
|
FocusDirection, FocusStack, FocusStackMut,
|
2023-07-11 16:33:23 +02:00
|
|
|
},
|
2023-01-18 20:23:41 +01:00
|
|
|
grabs::{ResizeEdge, ResizeGrab},
|
2023-09-08 22:16:39 +02:00
|
|
|
layout::tiling::{Data, NodeDesc},
|
2023-07-06 00:02:29 +02:00
|
|
|
CosmicMappedRenderElement, CosmicSurface, ResizeDirection, ResizeMode,
|
2022-03-24 20:32:31 +01:00
|
|
|
};
|
2022-03-30 22:00:44 +02:00
|
|
|
|
2023-09-15 18:37:34 +02:00
|
|
|
const FULLSCREEN_ANIMATION_DURATION: Duration = Duration::from_millis(200);
|
|
|
|
|
|
2022-09-28 12:01:29 +02:00
|
|
|
#[derive(Debug)]
|
2022-03-24 20:32:31 +01:00
|
|
|
pub struct Workspace {
|
2023-10-25 19:40:26 +02:00
|
|
|
pub output: Output,
|
2022-07-04 15:28:03 +02:00
|
|
|
pub tiling_layer: TilingLayout,
|
|
|
|
|
pub floating_layer: FloatingLayout,
|
2022-09-28 12:01:29 +02:00
|
|
|
pub tiling_enabled: bool,
|
2023-10-25 19:41:30 +02:00
|
|
|
pub fullscreen: Option<FullscreenSurface>,
|
|
|
|
|
|
2022-07-04 15:28:03 +02:00
|
|
|
pub handle: WorkspaceHandle,
|
2022-09-28 12:01:29 +02:00
|
|
|
pub focus_stack: FocusStacks,
|
2022-11-03 18:51:27 +01:00
|
|
|
pub pending_buffers: Vec<(ScreencopySession, BufferParams)>,
|
|
|
|
|
pub screencopy_sessions: Vec<DropableSession>,
|
2023-10-25 19:40:26 +02:00
|
|
|
pub output_stack: VecDeque<String>,
|
2023-05-26 20:51:10 +02:00
|
|
|
pub(super) backdrop_id: Id,
|
2023-09-20 14:56:18 +02:00
|
|
|
pub dirty: AtomicBool,
|
2022-03-24 20:32:31 +01:00
|
|
|
}
|
|
|
|
|
|
2023-09-13 20:14:54 +02:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct FullscreenSurface {
|
2023-10-25 19:41:30 +02:00
|
|
|
pub surface: CosmicSurface,
|
2023-10-11 22:00:20 +02:00
|
|
|
pub previously: Option<(ManagedLayer, WorkspaceHandle)>,
|
2023-10-25 19:41:30 +02:00
|
|
|
original_geometry: Rectangle<i32, Global>,
|
2023-09-15 18:37:34 +02:00
|
|
|
start_at: Option<Instant>,
|
|
|
|
|
ended_at: Option<Instant>,
|
|
|
|
|
animation_signal: Option<Arc<AtomicBool>>,
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-25 19:41:30 +02:00
|
|
|
impl PartialEq for FullscreenSurface {
|
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
|
self.surface == other.surface
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 18:37:34 +02:00
|
|
|
struct FullscreenBlocker {
|
|
|
|
|
signal: Arc<AtomicBool>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Blocker for FullscreenBlocker {
|
|
|
|
|
fn state(&self) -> BlockerState {
|
|
|
|
|
if self.signal.load(Ordering::SeqCst) {
|
|
|
|
|
BlockerState::Released
|
|
|
|
|
} else {
|
|
|
|
|
BlockerState::Pending
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl FullscreenSurface {
|
|
|
|
|
pub fn is_animating(&self) -> bool {
|
|
|
|
|
self.start_at.is_some() || self.ended_at.is_some()
|
|
|
|
|
}
|
2023-09-13 20:14:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl IsAlive for FullscreenSurface {
|
|
|
|
|
fn alive(&self) -> bool {
|
2023-10-25 19:41:30 +02:00
|
|
|
self.surface.alive()
|
2023-09-13 20:14:54 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-28 12:01:29 +02:00
|
|
|
#[derive(Debug, Default)]
|
|
|
|
|
pub struct FocusStacks(HashMap<Seat<State>, IndexSet<CosmicMapped>>);
|
|
|
|
|
|
2023-10-25 19:41:30 +02:00
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
2023-09-20 18:57:58 +02:00
|
|
|
pub struct ManagedState {
|
|
|
|
|
pub layer: ManagedLayer,
|
2023-10-25 19:41:30 +02:00
|
|
|
pub was_fullscreen: Option<FullscreenSurface>,
|
2023-09-20 18:57:58 +02:00
|
|
|
}
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
|
|
|
pub enum ManagedLayer {
|
2022-11-14 11:54:22 +01:00
|
|
|
Tiling,
|
|
|
|
|
Floating,
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-20 18:57:58 +02:00
|
|
|
#[derive(Debug, serde::Deserialize, Clone, Copy, PartialEq, Eq)]
|
|
|
|
|
pub enum Direction {
|
|
|
|
|
Left,
|
|
|
|
|
Right,
|
|
|
|
|
Up,
|
|
|
|
|
Down,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl std::ops::Not for Direction {
|
|
|
|
|
type Output = Self;
|
|
|
|
|
fn not(self) -> Self::Output {
|
|
|
|
|
match self {
|
|
|
|
|
Direction::Left => Direction::Right,
|
|
|
|
|
Direction::Right => Direction::Left,
|
|
|
|
|
Direction::Up => Direction::Down,
|
|
|
|
|
Direction::Down => Direction::Up,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-20 16:30:37 +02:00
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub enum FocusResult {
|
|
|
|
|
None,
|
|
|
|
|
Handled,
|
|
|
|
|
Some(KeyboardFocusTarget),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl FocusResult {
|
|
|
|
|
pub fn or_else<F>(self, f: F) -> FocusResult
|
|
|
|
|
where
|
|
|
|
|
F: FnOnce() -> FocusResult,
|
|
|
|
|
{
|
|
|
|
|
match self {
|
|
|
|
|
FocusResult::None => f(),
|
|
|
|
|
x => x,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-20 18:57:58 +02:00
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
pub enum MoveResult {
|
|
|
|
|
None,
|
|
|
|
|
Done,
|
|
|
|
|
MoveFurther(KeyboardFocusTarget),
|
|
|
|
|
ShiftFocus(KeyboardFocusTarget),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl MoveResult {
|
|
|
|
|
pub fn or_else<F>(self, f: F) -> MoveResult
|
|
|
|
|
where
|
|
|
|
|
F: FnOnce() -> MoveResult,
|
|
|
|
|
{
|
|
|
|
|
match self {
|
|
|
|
|
MoveResult::None => f(),
|
|
|
|
|
x => x,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-24 20:32:31 +01:00
|
|
|
impl Workspace {
|
2023-10-25 19:40:26 +02:00
|
|
|
pub fn new(
|
|
|
|
|
handle: WorkspaceHandle,
|
|
|
|
|
output: Output,
|
|
|
|
|
tiling_enabled: bool,
|
2023-10-10 13:55:34 -04:00
|
|
|
theme: cosmic::Theme,
|
2023-10-25 19:40:26 +02:00
|
|
|
) -> Workspace {
|
2023-10-10 13:55:34 -04:00
|
|
|
let tiling_layer = TilingLayout::new(theme, &output);
|
2023-10-25 19:40:26 +02:00
|
|
|
let floating_layer = FloatingLayout::new(&output);
|
|
|
|
|
|
2022-03-24 20:32:31 +01:00
|
|
|
Workspace {
|
2023-10-25 19:40:26 +02:00
|
|
|
output,
|
|
|
|
|
tiling_layer,
|
|
|
|
|
floating_layer,
|
2023-01-27 13:26:28 +01:00
|
|
|
tiling_enabled,
|
2023-10-25 19:41:30 +02:00
|
|
|
fullscreen: None,
|
2022-07-04 15:28:03 +02:00
|
|
|
handle,
|
2022-09-28 12:01:29 +02:00
|
|
|
focus_stack: FocusStacks::default(),
|
2022-11-03 18:51:27 +01:00
|
|
|
pending_buffers: Vec::new(),
|
|
|
|
|
screencopy_sessions: Vec::new(),
|
2023-10-25 19:40:26 +02:00
|
|
|
output_stack: VecDeque::new(),
|
2023-05-26 20:51:10 +02:00
|
|
|
backdrop_id: Id::new(),
|
2023-09-20 14:56:18 +02:00
|
|
|
dirty: AtomicBool::new(false),
|
2022-03-24 20:32:31 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-28 12:01:29 +02:00
|
|
|
pub fn refresh(&mut self) {
|
2023-03-06 18:50:11 +01:00
|
|
|
#[cfg(feature = "debug")]
|
|
|
|
|
puffin::profile_function!();
|
|
|
|
|
|
2023-10-25 19:41:30 +02:00
|
|
|
// TODO: `Option::take_if` once stabilitized
|
|
|
|
|
if self.fullscreen.as_ref().is_some_and(|w| !w.alive()) {
|
|
|
|
|
let _ = self.fullscreen.take();
|
|
|
|
|
};
|
|
|
|
|
|
2022-09-28 12:01:29 +02:00
|
|
|
self.floating_layer.refresh();
|
|
|
|
|
self.tiling_layer.refresh();
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-11 21:11:34 +02:00
|
|
|
pub fn refresh_focus_stack(&mut self) {
|
|
|
|
|
let windows: Vec<CosmicMapped> = self.mapped().cloned().collect();
|
|
|
|
|
for stack in self.focus_stack.0.values_mut() {
|
|
|
|
|
stack.retain(|w| windows.contains(w));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-12 20:01:37 +02:00
|
|
|
pub fn animations_going(&self) -> bool {
|
|
|
|
|
self.tiling_layer.animations_going()
|
2023-09-15 18:37:34 +02:00
|
|
|
|| self
|
|
|
|
|
.fullscreen
|
2023-10-25 19:41:30 +02:00
|
|
|
.as_ref()
|
|
|
|
|
.is_some_and(|f| f.start_at.is_some() || f.ended_at.is_some())
|
2023-09-20 14:56:18 +02:00
|
|
|
|| self.dirty.swap(false, Ordering::SeqCst)
|
2023-05-12 20:01:37 +02:00
|
|
|
}
|
|
|
|
|
|
2023-07-05 23:48:10 +02:00
|
|
|
pub fn update_animations(&mut self) -> HashMap<ClientId, Client> {
|
2023-09-20 14:56:18 +02:00
|
|
|
let mut clients = HashMap::new();
|
2023-09-15 18:37:34 +02:00
|
|
|
|
2023-10-25 19:41:30 +02:00
|
|
|
if let Some(f) = self.fullscreen.as_mut() {
|
2023-09-15 18:37:34 +02:00
|
|
|
if let Some(start) = f.start_at.as_ref() {
|
|
|
|
|
let duration_since = Instant::now().duration_since(*start);
|
|
|
|
|
if duration_since > FULLSCREEN_ANIMATION_DURATION {
|
|
|
|
|
f.start_at.take();
|
2023-09-20 14:56:18 +02:00
|
|
|
self.dirty.store(true, Ordering::SeqCst);
|
2023-09-15 18:37:34 +02:00
|
|
|
}
|
|
|
|
|
if duration_since * 2 > FULLSCREEN_ANIMATION_DURATION {
|
|
|
|
|
if let Some(signal) = f.animation_signal.take() {
|
|
|
|
|
signal.store(true, Ordering::SeqCst);
|
|
|
|
|
if let Some(client) =
|
2023-10-25 19:41:30 +02:00
|
|
|
f.surface.wl_surface().as_ref().and_then(Resource::client)
|
2023-09-15 18:37:34 +02:00
|
|
|
{
|
2023-09-20 14:56:18 +02:00
|
|
|
clients.insert(client.id(), client);
|
2023-09-15 18:37:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-09-20 14:56:18 +02:00
|
|
|
|
2023-10-25 19:41:30 +02:00
|
|
|
if let Some(end) = f.ended_at {
|
|
|
|
|
let duration_since = Instant::now().duration_since(end);
|
2023-09-15 18:37:34 +02:00
|
|
|
if duration_since * 2 > FULLSCREEN_ANIMATION_DURATION {
|
|
|
|
|
if let Some(signal) = f.animation_signal.take() {
|
|
|
|
|
signal.store(true, Ordering::SeqCst);
|
|
|
|
|
if let Some(client) =
|
2023-10-25 19:41:30 +02:00
|
|
|
f.surface.wl_surface().as_ref().and_then(Resource::client)
|
2023-09-15 18:37:34 +02:00
|
|
|
{
|
2023-09-20 14:56:18 +02:00
|
|
|
clients.insert(client.id(), client);
|
2023-09-15 18:37:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-25 19:41:30 +02:00
|
|
|
if duration_since >= FULLSCREEN_ANIMATION_DURATION {
|
|
|
|
|
let _ = self.fullscreen.take();
|
|
|
|
|
self.dirty.store(true, Ordering::SeqCst);
|
|
|
|
|
}
|
2023-09-15 18:37:34 +02:00
|
|
|
}
|
2023-09-20 14:56:18 +02:00
|
|
|
}
|
2023-09-15 18:37:34 +02:00
|
|
|
|
2023-09-20 14:56:18 +02:00
|
|
|
clients.extend(self.tiling_layer.update_animation_state());
|
|
|
|
|
clients
|
2023-05-12 20:01:37 +02:00
|
|
|
}
|
|
|
|
|
|
2022-09-28 12:01:29 +02:00
|
|
|
pub fn commit(&mut self, surface: &WlSurface) {
|
2023-01-18 20:23:41 +01:00
|
|
|
if let Some(mapped) = self.element_for_wl_surface(surface) {
|
2022-09-28 12:01:29 +02:00
|
|
|
mapped
|
|
|
|
|
.windows()
|
2023-01-16 15:12:25 +01:00
|
|
|
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface))
|
2022-09-28 12:01:29 +02:00
|
|
|
.unwrap()
|
|
|
|
|
.0
|
|
|
|
|
.on_commit();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-25 19:40:26 +02:00
|
|
|
pub fn output(&self) -> &Output {
|
|
|
|
|
&self.output
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-25 19:40:26 +02:00
|
|
|
pub fn set_output(
|
2023-01-24 21:01:11 +01:00
|
|
|
&mut self,
|
|
|
|
|
output: &Output,
|
|
|
|
|
toplevel_info: &mut ToplevelInfoState<State, CosmicSurface>,
|
|
|
|
|
) {
|
2023-10-25 19:40:26 +02:00
|
|
|
self.tiling_layer.set_output(output);
|
|
|
|
|
self.floating_layer.set_output(output);
|
|
|
|
|
for mapped in self.mapped() {
|
|
|
|
|
for (surface, _) in mapped.windows() {
|
|
|
|
|
toplevel_info.toplevel_leave_output(&surface, &self.output);
|
|
|
|
|
toplevel_info.toplevel_enter_output(&surface, output);
|
|
|
|
|
}
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
2023-10-25 19:40:26 +02:00
|
|
|
self.output = output.clone();
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
|
2022-11-14 11:54:22 +01:00
|
|
|
pub fn unmap(&mut self, mapped: &CosmicMapped) -> Option<ManagedState> {
|
2023-10-25 19:41:30 +02:00
|
|
|
let was_fullscreen = self
|
|
|
|
|
.fullscreen
|
|
|
|
|
.as_ref()
|
|
|
|
|
.filter(|f| f.ended_at.is_none())
|
|
|
|
|
.map(|f| mapped.windows().any(|(w, _)| w == f.surface))
|
|
|
|
|
.unwrap_or(false)
|
|
|
|
|
.then(|| self.fullscreen.take().unwrap());
|
|
|
|
|
|
2023-10-12 12:05:43 +02:00
|
|
|
if mapped.maximized_state.lock().unwrap().is_some() {
|
2023-10-25 19:41:30 +02:00
|
|
|
// If surface is maximized then unmaximize it, so it is assigned to only one layer
|
|
|
|
|
let _ = self.unmaximize_request(&mapped.active_window());
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-14 11:54:22 +01:00
|
|
|
let was_floating = self.floating_layer.unmap(&mapped);
|
2023-10-25 19:40:26 +02:00
|
|
|
let was_tiling = self.tiling_layer.unmap(&mapped);
|
2022-11-14 11:54:22 +01:00
|
|
|
if was_floating || was_tiling {
|
|
|
|
|
assert!(was_floating != was_tiling);
|
|
|
|
|
}
|
2023-01-27 19:59:54 +01:00
|
|
|
|
2022-11-14 11:54:22 +01:00
|
|
|
self.focus_stack
|
|
|
|
|
.0
|
|
|
|
|
.values_mut()
|
|
|
|
|
.for_each(|set| set.retain(|m| m != mapped));
|
|
|
|
|
if was_floating {
|
2023-09-20 18:57:58 +02:00
|
|
|
Some(ManagedState {
|
|
|
|
|
layer: ManagedLayer::Floating,
|
2023-10-25 19:41:30 +02:00
|
|
|
was_fullscreen,
|
2023-09-20 18:57:58 +02:00
|
|
|
})
|
2022-11-14 11:54:22 +01:00
|
|
|
} else if was_tiling {
|
2023-09-20 18:57:58 +02:00
|
|
|
Some(ManagedState {
|
|
|
|
|
layer: ManagedLayer::Tiling,
|
2023-10-25 19:41:30 +02:00
|
|
|
was_fullscreen,
|
2023-09-20 18:57:58 +02:00
|
|
|
})
|
2022-11-14 11:54:22 +01:00
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-18 20:23:41 +01:00
|
|
|
pub fn element_for_surface(&self, surface: &CosmicSurface) -> Option<&CosmicMapped> {
|
|
|
|
|
self.floating_layer
|
|
|
|
|
.mapped()
|
|
|
|
|
.chain(self.tiling_layer.mapped().map(|(_, w, _)| w))
|
|
|
|
|
.find(|e| e.windows().any(|(w, _)| &w == surface))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn element_for_wl_surface(&self, surface: &WlSurface) -> Option<&CosmicMapped> {
|
2022-09-28 12:01:29 +02:00
|
|
|
self.floating_layer
|
|
|
|
|
.mapped()
|
|
|
|
|
.chain(self.tiling_layer.mapped().map(|(_, w, _)| w))
|
|
|
|
|
.find(|e| {
|
|
|
|
|
e.windows()
|
2023-01-16 15:12:25 +01:00
|
|
|
.any(|(w, _)| w.wl_surface().as_ref() == Some(surface))
|
2023-10-25 19:41:30 +02:00
|
|
|
})
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn element_under(
|
2023-07-21 16:08:55 +02:00
|
|
|
&mut self,
|
2023-10-25 19:40:26 +02:00
|
|
|
location: Point<f64, Global>,
|
2023-07-21 16:08:55 +02:00
|
|
|
overview: OverviewMode,
|
2023-10-25 19:40:26 +02:00
|
|
|
) -> Option<(PointerFocusTarget, Point<i32, Global>)> {
|
|
|
|
|
let location = location.to_local(&self.output);
|
2022-09-28 12:01:29 +02:00
|
|
|
self.floating_layer
|
|
|
|
|
.space
|
2023-10-25 19:40:26 +02:00
|
|
|
.element_under(location.as_logical())
|
|
|
|
|
.map(|(mapped, p)| (mapped.clone().into(), p.as_local()))
|
2023-07-21 16:08:55 +02:00
|
|
|
.or_else(|| self.tiling_layer.element_under(location, overview))
|
2023-10-25 19:40:26 +02:00
|
|
|
.map(|(m, p)| (m, p.to_global(&self.output)))
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-25 19:40:26 +02:00
|
|
|
pub fn element_geometry(&self, elem: &CosmicMapped) -> Option<Rectangle<i32, Local>> {
|
2022-09-28 12:01:29 +02:00
|
|
|
self.floating_layer
|
|
|
|
|
.element_geometry(elem)
|
|
|
|
|
.or_else(|| self.tiling_layer.element_geometry(elem))
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-25 19:40:26 +02:00
|
|
|
pub fn recalculate(&mut self) {
|
|
|
|
|
self.tiling_layer.recalculate();
|
|
|
|
|
self.floating_layer.refresh();
|
2023-09-13 20:14:54 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-25 19:41:30 +02:00
|
|
|
pub fn maximize_request(&mut self, window: &CosmicSurface) {
|
|
|
|
|
if self.fullscreen.is_some() {
|
2022-04-22 15:18:28 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2022-10-24 18:32:53 +02:00
|
|
|
|
2023-10-25 19:41:30 +02:00
|
|
|
if let Some(elem) = self.element_for_surface(window).cloned() {
|
|
|
|
|
let mut state = elem.maximized_state.lock().unwrap();
|
|
|
|
|
if state.is_none() {
|
|
|
|
|
*state = Some(MaximizedState {
|
|
|
|
|
original_geometry: self.element_geometry(&elem).unwrap(),
|
|
|
|
|
original_layer: if self.is_floating(&elem) {
|
|
|
|
|
ManagedLayer::Floating
|
|
|
|
|
} else {
|
|
|
|
|
ManagedLayer::Tiling
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
std::mem::drop(state);
|
|
|
|
|
self.floating_layer.map_maximized(elem);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-03-24 20:32:31 +01:00
|
|
|
}
|
2023-09-20 18:57:58 +02:00
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
pub fn unmaximize_request(&mut self, window: &CosmicSurface) -> Option<Size<i32, Logical>> {
|
2023-10-25 19:41:30 +02:00
|
|
|
if let Some(elem) = self.element_for_surface(window).cloned() {
|
|
|
|
|
let mut state = elem.maximized_state.lock().unwrap();
|
|
|
|
|
if let Some(state) = state.take() {
|
|
|
|
|
match state.original_layer {
|
|
|
|
|
ManagedLayer::Tiling => {
|
|
|
|
|
// should still be mapped in tiling
|
|
|
|
|
self.floating_layer.unmap(&elem);
|
|
|
|
|
elem.output_enter(&self.output, elem.bbox());
|
|
|
|
|
elem.set_maximized(false);
|
|
|
|
|
elem.set_geometry(state.original_geometry.to_global(&self.output));
|
|
|
|
|
elem.configure();
|
|
|
|
|
self.tiling_layer.recalculate();
|
|
|
|
|
return self
|
|
|
|
|
.tiling_layer
|
|
|
|
|
.element_geometry(&elem)
|
|
|
|
|
.map(|geo| geo.size.as_logical());
|
|
|
|
|
}
|
|
|
|
|
ManagedLayer::Floating => {
|
|
|
|
|
elem.set_maximized(false);
|
|
|
|
|
self.floating_layer.map_internal(
|
|
|
|
|
elem.clone(),
|
|
|
|
|
Some(state.original_geometry.loc),
|
|
|
|
|
Some(state.original_geometry.size.as_logical()),
|
|
|
|
|
);
|
|
|
|
|
return Some(state.original_geometry.size.as_logical());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-08 15:20:29 +02:00
|
|
|
}
|
2023-10-25 19:41:30 +02:00
|
|
|
None
|
2022-07-08 15:20:29 +02:00
|
|
|
}
|
2022-03-24 20:32:31 +01:00
|
|
|
|
2023-10-11 22:00:20 +02:00
|
|
|
pub fn fullscreen_request(
|
|
|
|
|
&mut self,
|
|
|
|
|
window: &CosmicSurface,
|
|
|
|
|
previously: Option<(ManagedLayer, WorkspaceHandle)>,
|
|
|
|
|
) {
|
2023-10-24 15:58:53 +02:00
|
|
|
if self
|
|
|
|
|
.fullscreen
|
|
|
|
|
.as_ref()
|
|
|
|
|
.filter(|f| f.ended_at.is_none())
|
|
|
|
|
.is_some()
|
|
|
|
|
{
|
2022-04-22 15:18:28 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2022-10-24 18:32:53 +02:00
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
window.set_fullscreen(true);
|
2023-10-25 19:41:30 +02:00
|
|
|
let geo = self.output.geometry();
|
|
|
|
|
let original_geometry = window.geometry().as_global();
|
2023-09-15 18:37:34 +02:00
|
|
|
let signal = if let Some(surface) = window.wl_surface() {
|
|
|
|
|
let signal = Arc::new(AtomicBool::new(false));
|
|
|
|
|
add_blocker(
|
|
|
|
|
&surface,
|
|
|
|
|
FullscreenBlocker {
|
|
|
|
|
signal: signal.clone(),
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
Some(signal)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
2023-09-18 18:29:13 +02:00
|
|
|
window.set_geometry(geo);
|
2023-10-25 19:41:30 +02:00
|
|
|
window.send_configure();
|
|
|
|
|
|
|
|
|
|
self.fullscreen = Some(FullscreenSurface {
|
|
|
|
|
surface: window.clone(),
|
2023-10-11 22:00:20 +02:00
|
|
|
previously,
|
2023-10-25 19:41:30 +02:00
|
|
|
original_geometry,
|
|
|
|
|
start_at: Some(Instant::now()),
|
|
|
|
|
ended_at: None,
|
|
|
|
|
animation_signal: signal,
|
|
|
|
|
});
|
2022-04-22 15:18:28 +02:00
|
|
|
}
|
2022-05-03 13:37:51 +02:00
|
|
|
|
2023-10-11 22:00:20 +02:00
|
|
|
#[must_use]
|
|
|
|
|
pub fn unfullscreen_request(
|
|
|
|
|
&mut self,
|
|
|
|
|
window: &CosmicSurface,
|
|
|
|
|
) -> Option<(ManagedLayer, WorkspaceHandle)> {
|
2023-10-24 15:58:53 +02:00
|
|
|
if let Some(f) = self
|
|
|
|
|
.fullscreen
|
|
|
|
|
.as_mut()
|
|
|
|
|
.filter(|f| &f.surface == window && f.ended_at.is_none())
|
|
|
|
|
{
|
2023-01-16 15:12:25 +01:00
|
|
|
window.set_fullscreen(false);
|
2023-10-25 19:41:30 +02:00
|
|
|
window.set_geometry(f.original_geometry);
|
|
|
|
|
|
2023-01-03 19:17:51 +01:00
|
|
|
self.floating_layer.refresh();
|
2023-10-25 19:41:30 +02:00
|
|
|
self.tiling_layer.recalculate();
|
2023-01-03 19:17:51 +01:00
|
|
|
self.tiling_layer.refresh();
|
2023-10-25 19:41:30 +02:00
|
|
|
|
2023-09-15 18:37:34 +02:00
|
|
|
let signal = if let Some(surface) = window.wl_surface() {
|
|
|
|
|
let signal = Arc::new(AtomicBool::new(false));
|
|
|
|
|
add_blocker(
|
|
|
|
|
&surface,
|
|
|
|
|
FullscreenBlocker {
|
|
|
|
|
signal: signal.clone(),
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
Some(signal)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
2023-01-16 15:12:25 +01:00
|
|
|
window.send_configure();
|
2023-09-15 18:37:34 +02:00
|
|
|
|
|
|
|
|
f.ended_at = Some(
|
|
|
|
|
Instant::now()
|
|
|
|
|
- (FULLSCREEN_ANIMATION_DURATION
|
|
|
|
|
- f.start_at
|
|
|
|
|
.take()
|
|
|
|
|
.map(|earlier| {
|
|
|
|
|
Instant::now()
|
|
|
|
|
.duration_since(earlier)
|
|
|
|
|
.min(FULLSCREEN_ANIMATION_DURATION)
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or(FULLSCREEN_ANIMATION_DURATION)),
|
|
|
|
|
);
|
|
|
|
|
if let Some(new_signal) = signal {
|
|
|
|
|
if let Some(old_signal) = f.animation_signal.replace(new_signal) {
|
|
|
|
|
old_signal.store(true, Ordering::SeqCst);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-09-20 18:57:58 +02:00
|
|
|
|
2023-10-11 22:00:20 +02:00
|
|
|
f.previously
|
2023-09-20 18:57:58 +02:00
|
|
|
} else {
|
|
|
|
|
None
|
2023-09-13 20:14:54 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-11 22:00:20 +02:00
|
|
|
#[must_use]
|
|
|
|
|
pub fn remove_fullscreen(&mut self) -> Option<(CosmicMapped, ManagedLayer, WorkspaceHandle)> {
|
2023-10-25 19:41:30 +02:00
|
|
|
if let Some(surface) = self.fullscreen.as_ref().map(|f| f.surface.clone()) {
|
2023-10-11 22:00:20 +02:00
|
|
|
self.unfullscreen_request(&surface)
|
|
|
|
|
.map(|(l, h)| (self.element_for_surface(&surface).unwrap().clone(), l, h))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
2022-04-22 15:18:28 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-25 19:41:30 +02:00
|
|
|
pub fn maximize_toggle(&mut self, window: &CosmicSurface) {
|
|
|
|
|
if window.is_maximized(true) {
|
2023-01-16 15:12:25 +01:00
|
|
|
self.unmaximize_request(window);
|
2022-04-22 15:18:28 +02:00
|
|
|
} else {
|
2023-10-25 19:41:30 +02:00
|
|
|
self.maximize_request(window);
|
2022-04-22 15:18:28 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-25 19:41:30 +02:00
|
|
|
pub fn get_fullscreen(&self) -> Option<&CosmicSurface> {
|
2023-09-13 20:14:54 +02:00
|
|
|
self.fullscreen
|
2023-10-25 19:41:30 +02:00
|
|
|
.as_ref()
|
|
|
|
|
.filter(|f| f.alive())
|
2023-09-18 18:29:13 +02:00
|
|
|
.filter(|f| f.ended_at.is_none() && f.start_at.is_none())
|
2023-10-25 19:41:30 +02:00
|
|
|
.map(|f| &f.surface)
|
2022-04-22 15:18:28 +02:00
|
|
|
}
|
2022-07-07 22:41:17 +02:00
|
|
|
|
2022-10-24 18:32:53 +02:00
|
|
|
pub fn resize_request(
|
2022-10-25 14:43:50 +02:00
|
|
|
&mut self,
|
|
|
|
|
mapped: &CosmicMapped,
|
2022-10-24 18:32:53 +02:00
|
|
|
seat: &Seat<State>,
|
|
|
|
|
start_data: PointerGrabStartData<State>,
|
|
|
|
|
edges: ResizeEdge,
|
2022-10-27 20:40:55 +02:00
|
|
|
) -> Option<ResizeGrab> {
|
2023-06-09 16:26:13 +02:00
|
|
|
if mapped.is_fullscreen(true) || mapped.is_maximized(true) {
|
2022-10-25 14:43:50 +02:00
|
|
|
return None;
|
2022-10-24 18:32:53 +02:00
|
|
|
}
|
2022-10-27 20:40:55 +02:00
|
|
|
|
2022-10-25 14:43:50 +02:00
|
|
|
if self.floating_layer.mapped().any(|m| m == mapped) {
|
|
|
|
|
self.floating_layer
|
2023-01-18 20:23:41 +01:00
|
|
|
.resize_request(mapped, seat, start_data.clone(), edges)
|
2022-10-27 20:40:55 +02:00
|
|
|
.map(Into::into)
|
2022-10-25 14:43:50 +02:00
|
|
|
} else {
|
|
|
|
|
None
|
2022-10-24 18:32:53 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-06 00:02:29 +02:00
|
|
|
pub fn resize(
|
|
|
|
|
&mut self,
|
|
|
|
|
focused: &KeyboardFocusTarget,
|
|
|
|
|
direction: ResizeDirection,
|
|
|
|
|
edge: ResizeEdge,
|
|
|
|
|
amount: i32,
|
|
|
|
|
) -> bool {
|
|
|
|
|
if let Some(toplevel) = focused.toplevel() {
|
|
|
|
|
if self
|
|
|
|
|
.fullscreen
|
2023-10-25 19:41:30 +02:00
|
|
|
.as_ref()
|
|
|
|
|
.is_some_and(|f| f.surface.wl_surface().as_ref() == Some(&toplevel))
|
2023-07-06 00:02:29 +02:00
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-06-28 21:29:39 +02:00
|
|
|
}
|
|
|
|
|
|
2023-07-06 00:02:29 +02:00
|
|
|
if !self.floating_layer.resize(focused, direction, edge, amount) {
|
|
|
|
|
self.tiling_layer.resize(focused, direction, edge, amount)
|
|
|
|
|
} else {
|
|
|
|
|
true
|
2023-06-28 21:29:39 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-26 15:26:07 +02:00
|
|
|
pub fn move_request(
|
|
|
|
|
&mut self,
|
2023-01-16 15:12:25 +01:00
|
|
|
window: &CosmicSurface,
|
2022-10-26 15:26:07 +02:00
|
|
|
seat: &Seat<State>,
|
|
|
|
|
output: &Output,
|
|
|
|
|
start_data: PointerGrabStartData<State>,
|
2023-03-09 18:27:11 +01:00
|
|
|
indicator_thickness: u8,
|
2023-07-17 21:11:23 +02:00
|
|
|
) -> Option<MoveGrab> {
|
2022-10-26 15:26:07 +02:00
|
|
|
let pointer = seat.get_pointer().unwrap();
|
2023-10-25 19:41:30 +02:00
|
|
|
let pos = pointer.current_location().as_global();
|
|
|
|
|
|
|
|
|
|
if self
|
|
|
|
|
.fullscreen
|
|
|
|
|
.as_ref()
|
|
|
|
|
.is_some_and(|f| &f.surface == window)
|
|
|
|
|
{
|
2023-10-11 22:00:20 +02:00
|
|
|
let _ = self.remove_fullscreen(); // We are moving this window, we don't need to send it back to it's original workspace
|
2023-10-25 19:41:30 +02:00
|
|
|
}
|
2022-10-26 15:26:07 +02:00
|
|
|
|
2023-01-18 20:23:41 +01:00
|
|
|
let mapped = self.element_for_surface(&window)?.clone();
|
2023-10-25 19:41:30 +02:00
|
|
|
let mut initial_window_location = self
|
|
|
|
|
.element_geometry(&mapped)
|
|
|
|
|
.unwrap()
|
|
|
|
|
.loc
|
|
|
|
|
.to_global(&self.output);
|
2022-10-26 15:26:07 +02:00
|
|
|
|
2023-10-12 12:05:43 +02:00
|
|
|
if mapped.maximized_state.lock().unwrap().is_some() {
|
2022-10-26 15:26:07 +02:00
|
|
|
// If surface is maximized then unmaximize it
|
2023-01-16 15:12:25 +01:00
|
|
|
let new_size = self.unmaximize_request(window);
|
2023-10-25 18:48:48 +02:00
|
|
|
let ratio = pos.to_local(&self.output).x / output.geometry().size.w as f64;
|
2022-10-26 15:26:07 +02:00
|
|
|
|
|
|
|
|
initial_window_location = new_size
|
|
|
|
|
.map(|size| (pos.x - (size.w as f64 * ratio), pos.y).into())
|
|
|
|
|
.unwrap_or_else(|| pos)
|
|
|
|
|
.to_i32_round();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let was_floating = self.floating_layer.unmap(&mapped);
|
2023-10-12 12:05:43 +02:00
|
|
|
let was_tiled = self.tiling_layer.unmap_as_placeholder(&mapped);
|
2023-07-17 21:11:23 +02:00
|
|
|
assert!(was_floating != was_tiled.is_some());
|
|
|
|
|
|
|
|
|
|
Some(MoveGrab::new(
|
|
|
|
|
start_data,
|
|
|
|
|
mapped,
|
|
|
|
|
seat,
|
|
|
|
|
pos,
|
|
|
|
|
initial_window_location,
|
|
|
|
|
indicator_thickness,
|
|
|
|
|
was_tiled.is_some(),
|
|
|
|
|
))
|
2022-10-26 15:26:07 +02:00
|
|
|
}
|
|
|
|
|
|
2022-07-07 22:41:17 +02:00
|
|
|
pub fn toggle_tiling(&mut self, seat: &Seat<State>) {
|
|
|
|
|
if self.tiling_enabled {
|
2022-09-28 12:01:29 +02:00
|
|
|
for window in self
|
|
|
|
|
.tiling_layer
|
|
|
|
|
.mapped()
|
|
|
|
|
.map(|(_, m, _)| m.clone())
|
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
|
.into_iter()
|
|
|
|
|
{
|
|
|
|
|
self.tiling_layer.unmap(&window);
|
2023-10-25 19:40:26 +02:00
|
|
|
self.floating_layer.map(window, None);
|
2022-07-07 22:41:17 +02:00
|
|
|
}
|
|
|
|
|
self.tiling_enabled = false;
|
|
|
|
|
} else {
|
2022-09-28 12:01:29 +02:00
|
|
|
let focus_stack = self.focus_stack.get(seat);
|
|
|
|
|
for window in self
|
|
|
|
|
.floating_layer
|
|
|
|
|
.mapped()
|
|
|
|
|
.cloned()
|
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
|
.into_iter()
|
|
|
|
|
{
|
|
|
|
|
self.floating_layer.unmap(&window);
|
2023-10-11 22:00:20 +02:00
|
|
|
self.tiling_layer
|
|
|
|
|
.map(window, Some(focus_stack.iter()), None)
|
2022-07-07 22:41:17 +02:00
|
|
|
}
|
|
|
|
|
self.tiling_enabled = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn toggle_floating_window(&mut self, seat: &Seat<State>) {
|
|
|
|
|
if self.tiling_enabled {
|
2022-09-28 12:01:29 +02:00
|
|
|
if let Some(window) = self.focus_stack.get(seat).iter().next().cloned() {
|
|
|
|
|
if self.tiling_layer.mapped().any(|(_, m, _)| m == &window) {
|
|
|
|
|
self.tiling_layer.unmap(&window);
|
2023-10-25 19:40:26 +02:00
|
|
|
self.floating_layer.map(window, None);
|
2022-09-28 12:01:29 +02:00
|
|
|
} else if self.floating_layer.mapped().any(|w| w == &window) {
|
|
|
|
|
let focus_stack = self.focus_stack.get(seat);
|
|
|
|
|
self.floating_layer.unmap(&window);
|
2023-10-11 22:00:20 +02:00
|
|
|
self.tiling_layer
|
|
|
|
|
.map(window, Some(focus_stack.iter()), None)
|
2022-07-07 22:41:17 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-09-28 12:01:29 +02:00
|
|
|
|
|
|
|
|
pub fn mapped(&self) -> impl Iterator<Item = &CosmicMapped> {
|
|
|
|
|
self.floating_layer
|
|
|
|
|
.mapped()
|
|
|
|
|
.chain(self.tiling_layer.mapped().map(|(_, w, _)| w))
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-10 16:20:17 -08:00
|
|
|
pub fn outputs(&self) -> impl Iterator<Item = &Output> {
|
|
|
|
|
self.floating_layer.space.outputs()
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 15:12:25 +01:00
|
|
|
pub fn windows(&self) -> impl Iterator<Item = CosmicSurface> + '_ {
|
2022-09-28 12:01:29 +02:00
|
|
|
self.floating_layer
|
|
|
|
|
.windows()
|
|
|
|
|
.chain(self.tiling_layer.windows().map(|(_, w, _)| w))
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-13 20:27:12 +01:00
|
|
|
pub fn is_fullscreen(&self, mapped: &CosmicMapped) -> bool {
|
|
|
|
|
self.fullscreen
|
2023-10-25 19:41:30 +02:00
|
|
|
.as_ref()
|
|
|
|
|
.is_some_and(|f| f.surface == mapped.active_window())
|
2023-02-13 20:27:12 +01:00
|
|
|
}
|
|
|
|
|
|
2023-01-18 20:23:41 +01:00
|
|
|
pub fn is_floating(&self, mapped: &CosmicMapped) -> bool {
|
2023-10-25 19:41:30 +02:00
|
|
|
!self.is_fullscreen(mapped) && self.floating_layer.mapped().any(|m| m == mapped)
|
2023-02-13 20:27:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn is_tiled(&self, mapped: &CosmicMapped) -> bool {
|
2023-10-25 19:41:30 +02:00
|
|
|
!self.is_fullscreen(mapped) && self.tiling_layer.mapped().any(|(_, m, _)| m == mapped)
|
2023-01-18 20:23:41 +01:00
|
|
|
}
|
|
|
|
|
|
2023-08-11 18:15:22 +02:00
|
|
|
pub fn node_desc(&self, focus: KeyboardFocusTarget) -> Option<NodeDesc> {
|
|
|
|
|
match focus {
|
|
|
|
|
KeyboardFocusTarget::Element(mapped) => {
|
2023-10-25 19:40:26 +02:00
|
|
|
self.tiling_layer.mapped().find_map(|(_, m, _)| {
|
|
|
|
|
if m == &mapped {
|
2023-08-11 18:15:22 +02:00
|
|
|
mapped
|
|
|
|
|
.tiling_node_id
|
|
|
|
|
.lock()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.clone()
|
|
|
|
|
.map(|node_id| NodeDesc {
|
|
|
|
|
handle: self.handle.clone(),
|
|
|
|
|
node: node_id,
|
|
|
|
|
stack_window: if mapped
|
|
|
|
|
.stack_ref()
|
|
|
|
|
.map(|stack| !stack.whole_stack_focused())
|
|
|
|
|
.unwrap_or(false)
|
|
|
|
|
{
|
|
|
|
|
Some(mapped.active_window())
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
},
|
|
|
|
|
})
|
2023-10-25 19:40:26 +02:00
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
2023-08-11 18:15:22 +02:00
|
|
|
})
|
|
|
|
|
}
|
2023-10-25 19:40:26 +02:00
|
|
|
KeyboardFocusTarget::Group(WindowGroup { node, .. }) => Some(NodeDesc {
|
2023-08-11 18:15:22 +02:00
|
|
|
handle: self.handle.clone(),
|
|
|
|
|
node,
|
|
|
|
|
stack_window: None,
|
|
|
|
|
}),
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-20 16:30:37 +02:00
|
|
|
pub fn next_focus<'a>(
|
|
|
|
|
&mut self,
|
|
|
|
|
direction: FocusDirection,
|
|
|
|
|
seat: &Seat<State>,
|
|
|
|
|
swap_desc: Option<NodeDesc>,
|
|
|
|
|
) -> FocusResult {
|
2023-10-25 19:41:30 +02:00
|
|
|
if self.fullscreen.is_some() {
|
2023-09-20 16:30:37 +02:00
|
|
|
return FocusResult::None;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let focus_stack = self.focus_stack.get(seat);
|
|
|
|
|
self.floating_layer
|
|
|
|
|
.next_focus(direction, seat, focus_stack.iter())
|
|
|
|
|
.or_else(|| {
|
|
|
|
|
self.tiling_layer
|
|
|
|
|
.next_focus(direction, seat, focus_stack.iter(), swap_desc)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-20 18:57:58 +02:00
|
|
|
pub fn move_current_element<'a>(
|
|
|
|
|
&mut self,
|
|
|
|
|
direction: Direction,
|
|
|
|
|
seat: &Seat<State>,
|
|
|
|
|
) -> MoveResult {
|
2023-10-25 19:41:30 +02:00
|
|
|
if let Some(f) = self.fullscreen.as_ref() {
|
|
|
|
|
MoveResult::MoveFurther(KeyboardFocusTarget::Fullscreen(f.surface.clone()))
|
2023-09-20 18:57:58 +02:00
|
|
|
} else {
|
|
|
|
|
self.floating_layer
|
2023-10-10 13:55:34 -04:00
|
|
|
.move_current_element(direction, seat, self.tiling_layer.theme.clone())
|
2023-09-20 18:57:58 +02:00
|
|
|
.or_else(|| self.tiling_layer.move_current_node(direction, seat))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-25 19:40:26 +02:00
|
|
|
pub fn render<'a, R>(
|
2022-09-28 12:01:29 +02:00
|
|
|
&self,
|
2022-11-28 17:48:50 +01:00
|
|
|
renderer: &mut R,
|
2023-01-27 19:51:23 +01:00
|
|
|
override_redirect_windows: &[X11Surface],
|
2023-03-07 20:28:41 +01:00
|
|
|
xwm_state: Option<&'a mut XWaylandState>,
|
2023-02-25 00:17:54 +01:00
|
|
|
draw_focus_indicator: Option<&Seat<State>>,
|
2023-09-08 22:16:39 +02:00
|
|
|
overview: (OverviewMode, Option<(SwapIndicator, Option<&Tree<Data>>)>),
|
2023-07-06 00:03:26 +02:00
|
|
|
resize_indicator: Option<(ResizeMode, ResizeIndicator)>,
|
2023-03-09 18:27:11 +01:00
|
|
|
indicator_thickness: u8,
|
2023-10-10 13:55:34 -04:00
|
|
|
theme: &CosmicTheme,
|
2023-07-13 17:19:29 +02:00
|
|
|
) -> Result<
|
|
|
|
|
(
|
|
|
|
|
Vec<WorkspaceRenderElement<R>>,
|
|
|
|
|
Vec<WorkspaceRenderElement<R>>,
|
|
|
|
|
),
|
|
|
|
|
OutputNotMapped,
|
|
|
|
|
>
|
2022-09-28 12:01:29 +02:00
|
|
|
where
|
2023-01-16 15:12:25 +01:00
|
|
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
2022-09-28 12:01:29 +02:00
|
|
|
<R as Renderer>::TextureId: 'static,
|
2022-11-22 10:28:30 +01:00
|
|
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
2023-03-07 22:20:44 +01:00
|
|
|
CosmicWindowRenderElement<R>: RenderElement<R>,
|
2023-06-08 13:19:30 +02:00
|
|
|
CosmicStackRenderElement<R>: RenderElement<R>,
|
2023-05-19 19:44:57 +02:00
|
|
|
WorkspaceRenderElement<R>: RenderElement<R>,
|
2022-09-28 12:01:29 +02:00
|
|
|
{
|
2023-03-06 18:50:11 +01:00
|
|
|
#[cfg(feature = "debug")]
|
|
|
|
|
puffin::profile_function!();
|
|
|
|
|
|
2023-07-13 17:19:29 +02:00
|
|
|
let mut window_elements = Vec::new();
|
|
|
|
|
let mut popup_elements = Vec::new();
|
2022-09-28 12:01:29 +02:00
|
|
|
|
2023-10-25 19:24:51 +02:00
|
|
|
let output_scale = self.output.current_scale().fractional_scale();
|
|
|
|
|
let zone = {
|
|
|
|
|
let layer_map = layer_map_for_output(&self.output);
|
|
|
|
|
layer_map.non_exclusive_zone().as_local()
|
|
|
|
|
};
|
2022-09-28 12:01:29 +02:00
|
|
|
|
2023-09-13 20:14:54 +02:00
|
|
|
// OR windows above all
|
|
|
|
|
popup_elements.extend(
|
|
|
|
|
override_redirect_windows
|
|
|
|
|
.iter()
|
2023-10-25 19:24:51 +02:00
|
|
|
.filter(|or| {
|
|
|
|
|
(*or)
|
|
|
|
|
.geometry()
|
|
|
|
|
.as_global()
|
|
|
|
|
.intersection(self.output.geometry())
|
|
|
|
|
.is_some()
|
|
|
|
|
})
|
2023-09-13 20:14:54 +02:00
|
|
|
.flat_map(|or| {
|
|
|
|
|
AsRenderElements::<R>::render_elements::<WorkspaceRenderElement<R>>(
|
|
|
|
|
or,
|
|
|
|
|
renderer,
|
2023-10-25 19:24:51 +02:00
|
|
|
(or.geometry().loc - self.output.geometry().loc.as_logical())
|
2023-09-13 20:14:54 +02:00
|
|
|
.to_physical_precise_round(output_scale),
|
|
|
|
|
Scale::from(output_scale),
|
|
|
|
|
1.0,
|
|
|
|
|
)
|
|
|
|
|
}),
|
|
|
|
|
);
|
2023-01-23 22:54:05 +01:00
|
|
|
|
2023-10-25 19:41:30 +02:00
|
|
|
if let Some(fullscreen) = self.fullscreen.as_ref() {
|
2022-09-28 12:01:29 +02:00
|
|
|
// fullscreen window
|
2023-10-25 19:41:30 +02:00
|
|
|
let bbox = fullscreen.surface.bbox().as_local();
|
2023-09-15 18:37:34 +02:00
|
|
|
let element_geo = Rectangle::from_loc_and_size(
|
2023-10-25 19:41:30 +02:00
|
|
|
self.element_for_surface(&fullscreen.surface)
|
2023-09-15 18:37:34 +02:00
|
|
|
.and_then(|elem| {
|
|
|
|
|
self.floating_layer
|
|
|
|
|
.element_geometry(elem)
|
|
|
|
|
.or_else(|| self.tiling_layer.element_geometry(elem))
|
|
|
|
|
.map(|mut geo| {
|
2023-10-25 19:41:30 +02:00
|
|
|
geo.loc -= elem.geometry().loc.as_local();
|
2023-09-15 18:37:34 +02:00
|
|
|
geo
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or(bbox)
|
|
|
|
|
.loc,
|
2023-10-25 19:41:30 +02:00
|
|
|
fullscreen.original_geometry.size.as_local(),
|
2023-09-15 18:37:34 +02:00
|
|
|
);
|
|
|
|
|
|
2023-10-25 19:41:30 +02:00
|
|
|
let mut full_geo =
|
|
|
|
|
Rectangle::from_loc_and_size((0, 0), self.output.geometry().size.as_local());
|
2023-09-15 18:37:34 +02:00
|
|
|
if fullscreen.start_at.is_none() {
|
|
|
|
|
if bbox != full_geo {
|
|
|
|
|
if bbox.size.w < full_geo.size.w {
|
|
|
|
|
full_geo.loc.x += (full_geo.size.w - bbox.size.w) / 2;
|
|
|
|
|
full_geo.size.w = bbox.size.w;
|
|
|
|
|
}
|
|
|
|
|
if bbox.size.h < full_geo.size.h {
|
|
|
|
|
full_geo.loc.y += (full_geo.size.h - bbox.size.h) / 2;
|
|
|
|
|
full_geo.size.h = bbox.size.h;
|
|
|
|
|
}
|
2023-01-23 22:56:10 +01:00
|
|
|
}
|
|
|
|
|
}
|
2023-09-15 18:37:34 +02:00
|
|
|
|
|
|
|
|
let (target_geo, alpha) = match (fullscreen.start_at, fullscreen.ended_at) {
|
|
|
|
|
(Some(started), _) => {
|
|
|
|
|
let duration = Instant::now().duration_since(started).as_secs_f64()
|
|
|
|
|
/ FULLSCREEN_ANIMATION_DURATION.as_secs_f64();
|
|
|
|
|
(
|
|
|
|
|
ease(
|
|
|
|
|
EaseInOutCubic,
|
|
|
|
|
EaseRectangle(element_geo),
|
|
|
|
|
EaseRectangle(full_geo),
|
|
|
|
|
duration,
|
|
|
|
|
)
|
|
|
|
|
.0,
|
|
|
|
|
ease(EaseInOutCubic, 0.0, 1.0, duration),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
(_, Some(ended)) => {
|
|
|
|
|
let duration = Instant::now().duration_since(ended).as_secs_f64()
|
|
|
|
|
/ FULLSCREEN_ANIMATION_DURATION.as_secs_f64();
|
|
|
|
|
(
|
|
|
|
|
ease(
|
|
|
|
|
EaseInOutCubic,
|
|
|
|
|
EaseRectangle(full_geo),
|
|
|
|
|
EaseRectangle(element_geo),
|
|
|
|
|
duration,
|
|
|
|
|
)
|
|
|
|
|
.0,
|
|
|
|
|
ease(EaseInOutCubic, 1.0, 0.0, duration),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
(None, None) => (full_geo, 1.0),
|
|
|
|
|
};
|
|
|
|
|
|
2023-10-25 19:24:51 +02:00
|
|
|
let render_loc = target_geo
|
|
|
|
|
.loc
|
|
|
|
|
.as_logical()
|
|
|
|
|
.to_physical_precise_round(output_scale);
|
2023-09-15 18:37:34 +02:00
|
|
|
let scale = Scale {
|
|
|
|
|
x: target_geo.size.w as f64 / bbox.size.w as f64,
|
|
|
|
|
y: target_geo.size.h as f64 / bbox.size.h as f64,
|
|
|
|
|
};
|
|
|
|
|
|
2023-09-18 18:29:13 +02:00
|
|
|
let (w_elements, p_elements) = fullscreen
|
2023-10-25 19:41:30 +02:00
|
|
|
.surface
|
2023-09-18 18:29:13 +02:00
|
|
|
.split_render_elements::<R, CosmicWindowRenderElement<R>>(
|
2023-09-15 18:37:34 +02:00
|
|
|
renderer,
|
|
|
|
|
render_loc,
|
|
|
|
|
output_scale.into(),
|
|
|
|
|
alpha,
|
2023-09-18 18:29:13 +02:00
|
|
|
);
|
|
|
|
|
window_elements.extend(
|
|
|
|
|
w_elements
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|elem| RescaleRenderElement::from_element(elem, render_loc, scale))
|
|
|
|
|
.map(Into::into),
|
2023-09-15 18:37:34 +02:00
|
|
|
);
|
2023-09-18 18:29:13 +02:00
|
|
|
popup_elements.extend(p_elements.into_iter().map(Into::into));
|
2023-09-15 18:37:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if self
|
|
|
|
|
.fullscreen
|
2023-10-25 19:41:30 +02:00
|
|
|
.as_ref()
|
2023-09-15 18:37:34 +02:00
|
|
|
.map(|f| f.start_at.is_some() || f.ended_at.is_some())
|
|
|
|
|
.unwrap_or(true)
|
|
|
|
|
{
|
2023-09-20 14:56:18 +02:00
|
|
|
let focused = draw_focus_indicator
|
2023-10-25 19:41:30 +02:00
|
|
|
.filter(|_| !self.fullscreen.is_some())
|
2023-09-20 14:56:18 +02:00
|
|
|
.and_then(|seat| self.focus_stack.get(seat).last().cloned());
|
2023-05-22 20:19:11 +02:00
|
|
|
|
2022-09-28 12:01:29 +02:00
|
|
|
// floating surfaces
|
2023-08-11 18:15:22 +02:00
|
|
|
let alpha = match &overview.0 {
|
2023-05-19 19:44:57 +02:00
|
|
|
OverviewMode::Started(_, started) => {
|
|
|
|
|
(1.0 - (Instant::now().duration_since(*started).as_millis()
|
|
|
|
|
/ ANIMATION_DURATION.as_millis()) as f32)
|
|
|
|
|
.max(0.0)
|
|
|
|
|
* 0.4
|
|
|
|
|
+ 0.6
|
|
|
|
|
}
|
2023-08-11 18:15:22 +02:00
|
|
|
OverviewMode::Ended(_, ended) => {
|
2023-05-19 19:44:57 +02:00
|
|
|
((Instant::now().duration_since(*ended).as_millis()
|
|
|
|
|
/ ANIMATION_DURATION.as_millis()) as f32)
|
|
|
|
|
* 0.4
|
|
|
|
|
+ 0.6
|
|
|
|
|
}
|
|
|
|
|
OverviewMode::None => 1.0,
|
|
|
|
|
};
|
2023-07-13 17:19:29 +02:00
|
|
|
|
2023-10-25 19:40:26 +02:00
|
|
|
let (w_elements, p_elements) = self.floating_layer.render::<R>(
|
2023-07-13 17:19:29 +02:00
|
|
|
renderer,
|
|
|
|
|
focused.as_ref(),
|
|
|
|
|
resize_indicator.clone(),
|
|
|
|
|
indicator_thickness,
|
|
|
|
|
alpha,
|
2023-10-10 13:55:34 -04:00
|
|
|
theme,
|
2022-09-28 12:01:29 +02:00
|
|
|
);
|
2023-07-13 17:19:29 +02:00
|
|
|
popup_elements.extend(p_elements.into_iter().map(WorkspaceRenderElement::from));
|
|
|
|
|
window_elements.extend(w_elements.into_iter().map(WorkspaceRenderElement::from));
|
2022-09-28 12:01:29 +02:00
|
|
|
|
2023-09-08 22:16:39 +02:00
|
|
|
let alpha = match &overview.0 {
|
|
|
|
|
OverviewMode::Started(_, start) => Some(
|
|
|
|
|
(Instant::now().duration_since(*start).as_millis() as f64 / 100.0).min(1.0)
|
|
|
|
|
as f32,
|
|
|
|
|
),
|
|
|
|
|
OverviewMode::Ended(_, ended) => Some(
|
|
|
|
|
1.0 - (Instant::now().duration_since(*ended).as_millis() as f64 / 100.0)
|
|
|
|
|
.min(1.0) as f32,
|
|
|
|
|
),
|
|
|
|
|
_ => None,
|
|
|
|
|
};
|
|
|
|
|
|
2022-09-28 12:01:29 +02:00
|
|
|
//tiling surfaces
|
2023-10-25 19:40:26 +02:00
|
|
|
let (w_elements, p_elements) = self.tiling_layer.render::<R>(
|
2023-07-13 17:19:29 +02:00
|
|
|
renderer,
|
|
|
|
|
draw_focus_indicator,
|
2023-10-25 19:40:26 +02:00
|
|
|
zone,
|
2023-09-08 22:16:39 +02:00
|
|
|
overview,
|
2023-07-13 17:19:29 +02:00
|
|
|
resize_indicator,
|
|
|
|
|
indicator_thickness,
|
2023-10-10 13:55:34 -04:00
|
|
|
theme,
|
2023-07-13 17:19:29 +02:00
|
|
|
)?;
|
|
|
|
|
popup_elements.extend(p_elements.into_iter().map(WorkspaceRenderElement::from));
|
|
|
|
|
window_elements.extend(w_elements.into_iter().map(WorkspaceRenderElement::from));
|
2022-09-28 12:01:29 +02:00
|
|
|
|
2023-05-26 20:51:10 +02:00
|
|
|
if let Some(alpha) = alpha {
|
2023-07-13 17:19:29 +02:00
|
|
|
window_elements.push(
|
2023-05-26 20:51:10 +02:00
|
|
|
Into::<CosmicMappedRenderElement<R>>::into(BackdropShader::element(
|
|
|
|
|
renderer,
|
|
|
|
|
self.backdrop_id.clone(),
|
|
|
|
|
zone,
|
|
|
|
|
0.,
|
2023-06-01 17:03:55 +02:00
|
|
|
alpha * 0.85,
|
2023-05-26 20:51:10 +02:00
|
|
|
[0.0, 0.0, 0.0],
|
|
|
|
|
))
|
2023-05-19 19:44:57 +02:00
|
|
|
.into(),
|
|
|
|
|
)
|
|
|
|
|
}
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-15 18:37:34 +02:00
|
|
|
if let Some(xwm) = xwm_state.and_then(|state| state.xwm.as_mut()) {
|
|
|
|
|
if let Err(err) =
|
2023-10-25 15:28:40 +02:00
|
|
|
xwm.update_stacking_order_upwards(window_elements.iter().rev().map(|e| e.id()))
|
2023-09-15 18:37:34 +02:00
|
|
|
{
|
|
|
|
|
warn!(
|
|
|
|
|
wm_id = ?xwm.id(),
|
|
|
|
|
?err,
|
|
|
|
|
"Failed to update Xwm stacking order.",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-13 17:19:29 +02:00
|
|
|
Ok((window_elements, popup_elements))
|
2022-09-28 12:01:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl FocusStacks {
|
|
|
|
|
pub fn get<'a>(&'a self, seat: &Seat<State>) -> FocusStack<'a> {
|
|
|
|
|
FocusStack(self.0.get(seat))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn get_mut<'a>(&'a mut self, seat: &Seat<State>) -> FocusStackMut<'a> {
|
|
|
|
|
FocusStackMut(self.0.entry(seat.clone()).or_default())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct OutputNotMapped;
|
|
|
|
|
|
2022-11-22 10:28:30 +01:00
|
|
|
pub enum WorkspaceRenderElement<R>
|
|
|
|
|
where
|
2023-01-16 15:12:25 +01:00
|
|
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
2022-11-22 10:28:30 +01:00
|
|
|
<R as Renderer>::TextureId: 'static,
|
|
|
|
|
{
|
2023-09-18 18:29:13 +02:00
|
|
|
OverrideRedirect(WaylandSurfaceRenderElement<R>),
|
|
|
|
|
Fullscreen(RescaleRenderElement<CosmicWindowRenderElement<R>>),
|
|
|
|
|
FullscreenPopup(CosmicWindowRenderElement<R>),
|
2022-11-22 10:28:30 +01:00
|
|
|
Window(CosmicMappedRenderElement<R>),
|
2023-05-19 19:44:57 +02:00
|
|
|
Backdrop(TextureRenderElement<GlesTexture>),
|
2022-11-22 10:28:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<R> Element for WorkspaceRenderElement<R>
|
|
|
|
|
where
|
2023-01-16 15:12:25 +01:00
|
|
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
2022-11-22 10:28:30 +01:00
|
|
|
<R as Renderer>::TextureId: 'static,
|
|
|
|
|
{
|
|
|
|
|
fn id(&self) -> &smithay::backend::renderer::element::Id {
|
|
|
|
|
match self {
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::OverrideRedirect(elem) => elem.id(),
|
2023-09-15 18:37:34 +02:00
|
|
|
WorkspaceRenderElement::Fullscreen(elem) => elem.id(),
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::FullscreenPopup(elem) => elem.id(),
|
2022-11-22 10:28:30 +01:00
|
|
|
WorkspaceRenderElement::Window(elem) => elem.id(),
|
2023-05-19 19:44:57 +02:00
|
|
|
WorkspaceRenderElement::Backdrop(elem) => elem.id(),
|
2022-11-22 10:28:30 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn current_commit(&self) -> smithay::backend::renderer::utils::CommitCounter {
|
|
|
|
|
match self {
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::OverrideRedirect(elem) => elem.current_commit(),
|
2023-09-15 18:37:34 +02:00
|
|
|
WorkspaceRenderElement::Fullscreen(elem) => elem.current_commit(),
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::FullscreenPopup(elem) => elem.current_commit(),
|
2022-11-22 10:28:30 +01:00
|
|
|
WorkspaceRenderElement::Window(elem) => elem.current_commit(),
|
2023-05-19 19:44:57 +02:00
|
|
|
WorkspaceRenderElement::Backdrop(elem) => elem.current_commit(),
|
2022-11-22 10:28:30 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn src(&self) -> Rectangle<f64, smithay::utils::Buffer> {
|
|
|
|
|
match self {
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::OverrideRedirect(elem) => elem.src(),
|
2023-09-15 18:37:34 +02:00
|
|
|
WorkspaceRenderElement::Fullscreen(elem) => elem.src(),
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::FullscreenPopup(elem) => elem.src(),
|
2022-11-22 10:28:30 +01:00
|
|
|
WorkspaceRenderElement::Window(elem) => elem.src(),
|
2023-05-19 19:44:57 +02:00
|
|
|
WorkspaceRenderElement::Backdrop(elem) => elem.src(),
|
2022-11-22 10:28:30 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn geometry(&self, scale: Scale<f64>) -> Rectangle<i32, smithay::utils::Physical> {
|
|
|
|
|
match self {
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::OverrideRedirect(elem) => elem.geometry(scale),
|
2023-09-15 18:37:34 +02:00
|
|
|
WorkspaceRenderElement::Fullscreen(elem) => elem.geometry(scale),
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::FullscreenPopup(elem) => elem.geometry(scale),
|
2022-11-22 10:28:30 +01:00
|
|
|
WorkspaceRenderElement::Window(elem) => elem.geometry(scale),
|
2023-05-19 19:44:57 +02:00
|
|
|
WorkspaceRenderElement::Backdrop(elem) => elem.geometry(scale),
|
2022-11-22 10:28:30 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn location(&self, scale: Scale<f64>) -> Point<i32, smithay::utils::Physical> {
|
|
|
|
|
match self {
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::OverrideRedirect(elem) => elem.location(scale),
|
2023-09-15 18:37:34 +02:00
|
|
|
WorkspaceRenderElement::Fullscreen(elem) => elem.location(scale),
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::FullscreenPopup(elem) => elem.location(scale),
|
2022-11-22 10:28:30 +01:00
|
|
|
WorkspaceRenderElement::Window(elem) => elem.location(scale),
|
2023-05-19 19:44:57 +02:00
|
|
|
WorkspaceRenderElement::Backdrop(elem) => elem.location(scale),
|
2022-11-22 10:28:30 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn transform(&self) -> smithay::utils::Transform {
|
|
|
|
|
match self {
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::OverrideRedirect(elem) => elem.transform(),
|
2023-09-15 18:37:34 +02:00
|
|
|
WorkspaceRenderElement::Fullscreen(elem) => elem.transform(),
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::FullscreenPopup(elem) => elem.transform(),
|
2022-11-22 10:28:30 +01:00
|
|
|
WorkspaceRenderElement::Window(elem) => elem.transform(),
|
2023-05-19 19:44:57 +02:00
|
|
|
WorkspaceRenderElement::Backdrop(elem) => elem.transform(),
|
2022-11-22 10:28:30 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn damage_since(
|
|
|
|
|
&self,
|
|
|
|
|
scale: Scale<f64>,
|
|
|
|
|
commit: Option<smithay::backend::renderer::utils::CommitCounter>,
|
|
|
|
|
) -> Vec<Rectangle<i32, smithay::utils::Physical>> {
|
|
|
|
|
match self {
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::OverrideRedirect(elem) => elem.damage_since(scale, commit),
|
2023-09-15 18:37:34 +02:00
|
|
|
WorkspaceRenderElement::Fullscreen(elem) => elem.damage_since(scale, commit),
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::FullscreenPopup(elem) => elem.damage_since(scale, commit),
|
2022-11-22 10:28:30 +01:00
|
|
|
WorkspaceRenderElement::Window(elem) => elem.damage_since(scale, commit),
|
2023-05-19 19:44:57 +02:00
|
|
|
WorkspaceRenderElement::Backdrop(elem) => elem.damage_since(scale, commit),
|
2022-11-22 10:28:30 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn opaque_regions(&self, scale: Scale<f64>) -> Vec<Rectangle<i32, smithay::utils::Physical>> {
|
|
|
|
|
match self {
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::OverrideRedirect(elem) => elem.opaque_regions(scale),
|
2023-09-15 18:37:34 +02:00
|
|
|
WorkspaceRenderElement::Fullscreen(elem) => elem.opaque_regions(scale),
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::FullscreenPopup(elem) => elem.opaque_regions(scale),
|
2022-11-22 10:28:30 +01:00
|
|
|
WorkspaceRenderElement::Window(elem) => elem.opaque_regions(scale),
|
2023-05-19 19:44:57 +02:00
|
|
|
WorkspaceRenderElement::Backdrop(elem) => elem.opaque_regions(scale),
|
2022-11-22 10:28:30 +01:00
|
|
|
}
|
|
|
|
|
}
|
2023-05-12 20:01:37 +02:00
|
|
|
|
|
|
|
|
fn alpha(&self) -> f32 {
|
|
|
|
|
match self {
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::OverrideRedirect(elem) => elem.alpha(),
|
2023-09-15 18:37:34 +02:00
|
|
|
WorkspaceRenderElement::Fullscreen(elem) => elem.alpha(),
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::FullscreenPopup(elem) => elem.alpha(),
|
2023-05-12 20:01:37 +02:00
|
|
|
WorkspaceRenderElement::Window(elem) => elem.alpha(),
|
2023-05-19 19:44:57 +02:00
|
|
|
WorkspaceRenderElement::Backdrop(elem) => elem.alpha(),
|
2023-05-12 20:01:37 +02:00
|
|
|
}
|
|
|
|
|
}
|
2022-11-22 10:28:30 +01:00
|
|
|
}
|
|
|
|
|
|
2023-05-19 19:44:57 +02:00
|
|
|
impl RenderElement<GlowRenderer> for WorkspaceRenderElement<GlowRenderer> {
|
|
|
|
|
fn draw<'frame>(
|
|
|
|
|
&self,
|
|
|
|
|
frame: &mut GlowFrame<'frame>,
|
|
|
|
|
src: Rectangle<f64, BufferCoords>,
|
|
|
|
|
dst: Rectangle<i32, Physical>,
|
|
|
|
|
damage: &[Rectangle<i32, smithay::utils::Physical>],
|
|
|
|
|
) -> Result<(), GlesError> {
|
|
|
|
|
match self {
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::OverrideRedirect(elem) => elem.draw(frame, src, dst, damage),
|
2023-09-15 18:37:34 +02:00
|
|
|
WorkspaceRenderElement::Fullscreen(elem) => elem.draw(frame, src, dst, damage),
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::FullscreenPopup(elem) => elem.draw(frame, src, dst, damage),
|
2023-05-19 19:44:57 +02:00
|
|
|
WorkspaceRenderElement::Window(elem) => elem.draw(frame, src, dst, damage),
|
|
|
|
|
WorkspaceRenderElement::Backdrop(elem) => {
|
|
|
|
|
RenderElement::<GlowRenderer>::draw(elem, frame, src, dst, damage)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn underlying_storage(
|
|
|
|
|
&self,
|
|
|
|
|
renderer: &mut GlowRenderer,
|
|
|
|
|
) -> Option<smithay::backend::renderer::element::UnderlyingStorage> {
|
|
|
|
|
match self {
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::OverrideRedirect(elem) => elem.underlying_storage(renderer),
|
2023-09-15 18:37:34 +02:00
|
|
|
WorkspaceRenderElement::Fullscreen(elem) => elem.underlying_storage(renderer),
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::FullscreenPopup(elem) => elem.underlying_storage(renderer),
|
2023-05-19 19:44:57 +02:00
|
|
|
WorkspaceRenderElement::Window(elem) => elem.underlying_storage(renderer),
|
|
|
|
|
WorkspaceRenderElement::Backdrop(elem) => elem.underlying_storage(renderer),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a, 'b> RenderElement<GlMultiRenderer<'a, 'b>>
|
|
|
|
|
for WorkspaceRenderElement<GlMultiRenderer<'a, 'b>>
|
2022-11-22 10:28:30 +01:00
|
|
|
{
|
2022-11-28 17:48:50 +01:00
|
|
|
fn draw<'frame>(
|
2022-11-22 10:28:30 +01:00
|
|
|
&self,
|
2023-05-19 19:44:57 +02:00
|
|
|
frame: &mut GlMultiFrame<'a, 'b, 'frame>,
|
2022-12-27 18:27:29 +01:00
|
|
|
src: Rectangle<f64, BufferCoords>,
|
|
|
|
|
dst: Rectangle<i32, Physical>,
|
2022-11-22 10:28:30 +01:00
|
|
|
damage: &[Rectangle<i32, smithay::utils::Physical>],
|
2023-05-19 19:44:57 +02:00
|
|
|
) -> Result<(), GlMultiError> {
|
2022-11-22 10:28:30 +01:00
|
|
|
match self {
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::OverrideRedirect(elem) => elem.draw(frame, src, dst, damage),
|
2023-09-15 18:37:34 +02:00
|
|
|
WorkspaceRenderElement::Fullscreen(elem) => elem.draw(frame, src, dst, damage),
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::FullscreenPopup(elem) => elem.draw(frame, src, dst, damage),
|
2023-02-24 17:41:52 +01:00
|
|
|
WorkspaceRenderElement::Window(elem) => elem.draw(frame, src, dst, damage),
|
2023-05-19 19:44:57 +02:00
|
|
|
WorkspaceRenderElement::Backdrop(elem) => {
|
|
|
|
|
RenderElement::<GlowRenderer>::draw(elem, frame.glow_frame_mut(), src, dst, damage)
|
|
|
|
|
.map_err(GlMultiError::Render)
|
|
|
|
|
}
|
2022-11-22 10:28:30 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn underlying_storage(
|
|
|
|
|
&self,
|
2023-05-19 19:44:57 +02:00
|
|
|
renderer: &mut GlMultiRenderer<'a, 'b>,
|
2023-02-24 14:07:40 +01:00
|
|
|
) -> Option<smithay::backend::renderer::element::UnderlyingStorage> {
|
2022-11-22 10:28:30 +01:00
|
|
|
match self {
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::OverrideRedirect(elem) => elem.underlying_storage(renderer),
|
2023-09-15 18:37:34 +02:00
|
|
|
WorkspaceRenderElement::Fullscreen(elem) => elem.underlying_storage(renderer),
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::FullscreenPopup(elem) => elem.underlying_storage(renderer),
|
2022-11-22 10:28:30 +01:00
|
|
|
WorkspaceRenderElement::Window(elem) => elem.underlying_storage(renderer),
|
2023-05-19 19:44:57 +02:00
|
|
|
WorkspaceRenderElement::Backdrop(elem) => {
|
|
|
|
|
elem.underlying_storage(renderer.glow_renderer_mut())
|
|
|
|
|
}
|
2022-11-22 10:28:30 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-18 18:29:13 +02:00
|
|
|
impl<R> From<RescaleRenderElement<CosmicWindowRenderElement<R>>> for WorkspaceRenderElement<R>
|
2023-09-15 18:37:34 +02:00
|
|
|
where
|
|
|
|
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
|
|
|
|
<R as Renderer>::TextureId: 'static,
|
|
|
|
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
|
|
|
|
{
|
2023-09-18 18:29:13 +02:00
|
|
|
fn from(elem: RescaleRenderElement<CosmicWindowRenderElement<R>>) -> Self {
|
2023-09-15 18:37:34 +02:00
|
|
|
WorkspaceRenderElement::Fullscreen(elem)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-18 18:29:13 +02:00
|
|
|
impl<R> From<CosmicWindowRenderElement<R>> for WorkspaceRenderElement<R>
|
|
|
|
|
where
|
|
|
|
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
|
|
|
|
<R as Renderer>::TextureId: 'static,
|
|
|
|
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
|
|
|
|
{
|
|
|
|
|
fn from(elem: CosmicWindowRenderElement<R>) -> Self {
|
|
|
|
|
WorkspaceRenderElement::FullscreenPopup(elem)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-28 17:48:50 +01:00
|
|
|
impl<R> From<WaylandSurfaceRenderElement<R>> for WorkspaceRenderElement<R>
|
2022-11-22 10:28:30 +01:00
|
|
|
where
|
2023-01-16 15:12:25 +01:00
|
|
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
2022-11-22 10:28:30 +01:00
|
|
|
<R as Renderer>::TextureId: 'static,
|
|
|
|
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
|
|
|
|
{
|
2022-11-28 17:48:50 +01:00
|
|
|
fn from(elem: WaylandSurfaceRenderElement<R>) -> Self {
|
2023-09-18 18:29:13 +02:00
|
|
|
WorkspaceRenderElement::OverrideRedirect(elem)
|
2022-11-22 10:28:30 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<R> From<CosmicMappedRenderElement<R>> for WorkspaceRenderElement<R>
|
|
|
|
|
where
|
2023-01-16 15:12:25 +01:00
|
|
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
2022-11-22 10:28:30 +01:00
|
|
|
<R as Renderer>::TextureId: 'static,
|
|
|
|
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
|
|
|
|
{
|
|
|
|
|
fn from(elem: CosmicMappedRenderElement<R>) -> Self {
|
|
|
|
|
WorkspaceRenderElement::Window(elem)
|
|
|
|
|
}
|
2022-03-24 20:32:31 +01:00
|
|
|
}
|
2023-05-19 19:44:57 +02:00
|
|
|
|
|
|
|
|
impl<R> From<TextureRenderElement<GlesTexture>> for WorkspaceRenderElement<R>
|
|
|
|
|
where
|
|
|
|
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
|
|
|
|
<R as Renderer>::TextureId: 'static,
|
|
|
|
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
|
|
|
|
{
|
|
|
|
|
fn from(elem: TextureRenderElement<GlesTexture>) -> Self {
|
|
|
|
|
WorkspaceRenderElement::Backdrop(elem)
|
|
|
|
|
}
|
|
|
|
|
}
|