feat: support multiple fullscreen windows per workspace
This commit is contained in:
parent
9f28a764a7
commit
28ef6bdbc8
12 changed files with 381 additions and 308 deletions
|
|
@ -108,7 +108,7 @@ pub struct Workspace {
|
|||
pub floating_layer: FloatingLayout,
|
||||
pub minimized_windows: Vec<MinimizedWindow>,
|
||||
pub tiling_enabled: bool,
|
||||
pub fullscreen: Option<FullscreenSurface>,
|
||||
pub fullscreen_surfaces: Vec<FullscreenSurface>,
|
||||
pub pinned: bool,
|
||||
pub id: Option<String>,
|
||||
|
||||
|
|
@ -383,7 +383,7 @@ impl Workspace {
|
|||
floating_layer,
|
||||
tiling_enabled,
|
||||
minimized_windows: Vec::new(),
|
||||
fullscreen: None,
|
||||
fullscreen_surfaces: Vec::new(),
|
||||
pinned: false,
|
||||
id: None,
|
||||
handle,
|
||||
|
|
@ -416,7 +416,7 @@ impl Workspace {
|
|||
floating_layer,
|
||||
tiling_enabled: pinned.tiling_enabled,
|
||||
minimized_windows: Vec::new(),
|
||||
fullscreen: None,
|
||||
fullscreen_surfaces: Vec::new(),
|
||||
pinned: true,
|
||||
id: pinned.id.clone(),
|
||||
handle,
|
||||
|
|
@ -454,7 +454,10 @@ impl Workspace {
|
|||
|
||||
#[profiling::function]
|
||||
pub fn refresh(&mut self) {
|
||||
self.fullscreen.take_if(|w| !w.alive());
|
||||
// seems it removes dead windows
|
||||
// self.fullscreen.take_if(|w| !w.alive());
|
||||
self.fullscreen_surfaces.retain(|w| w.alive());
|
||||
|
||||
self.floating_layer.refresh();
|
||||
self.tiling_layer.refresh();
|
||||
}
|
||||
|
|
@ -478,14 +481,15 @@ impl Workspace {
|
|||
self.is_empty() && !self.has_activation_token(xdg_activation_state) && !self.pinned
|
||||
}
|
||||
|
||||
/// cleans up any window that is not alive anymore
|
||||
pub fn refresh_focus_stack(&mut self) {
|
||||
for (seat, stack) in self.focus_stack.0.iter_mut() {
|
||||
let fullscreen = self
|
||||
.fullscreen
|
||||
.as_ref()
|
||||
.filter(|f| f.alive())
|
||||
.filter(|f| f.ended_at.is_none())
|
||||
.map(|f| &f.surface);
|
||||
let fullscreen_surfaces: Vec<&CosmicSurface> = self
|
||||
.fullscreen_surfaces
|
||||
.iter()
|
||||
.filter(|f| f.alive() && f.ended_at.is_none())
|
||||
.map(|f| &f.surface)
|
||||
.collect();
|
||||
|
||||
// Move grab is treated as focused, so don't change focus to a
|
||||
// window while grab exists.
|
||||
|
|
@ -506,7 +510,7 @@ impl Workspace {
|
|||
.chain(move_mapped.iter())
|
||||
};
|
||||
stack.retain(|w| match w {
|
||||
FocusTarget::Fullscreen(s) => fullscreen.is_some_and(|f| f == s),
|
||||
FocusTarget::Fullscreen(s) => fullscreen_surfaces.contains(&s),
|
||||
FocusTarget::Window(w) => mapped().any(|m| w == m),
|
||||
});
|
||||
}
|
||||
|
|
@ -515,15 +519,12 @@ impl Workspace {
|
|||
pub fn animations_going(&self) -> bool {
|
||||
self.tiling_layer.animations_going()
|
||||
|| self.floating_layer.animations_going()
|
||||
|| self
|
||||
.fullscreen
|
||||
.as_ref()
|
||||
.is_some_and(|f| f.start_at.is_some() || f.ended_at.is_some())
|
||||
|| self.fullscreen_surfaces.iter().any(|f| f.is_animating())
|
||||
|| self.dirty.swap(false, Ordering::SeqCst)
|
||||
}
|
||||
|
||||
pub fn update_animations(&mut self) -> HashMap<ClientId, Client> {
|
||||
if let Some(f) = self.fullscreen.as_mut() {
|
||||
for f in self.fullscreen_surfaces.iter_mut() {
|
||||
if let Some(start) = f.start_at.as_ref() {
|
||||
let duration_since = Instant::now().duration_since(*start);
|
||||
if duration_since > FULLSCREEN_ANIMATION_DURATION {
|
||||
|
|
@ -531,16 +532,18 @@ impl Workspace {
|
|||
self.dirty.store(true, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(end) = f.ended_at {
|
||||
let duration_since = Instant::now().duration_since(end);
|
||||
if duration_since >= FULLSCREEN_ANIMATION_DURATION {
|
||||
let _ = self.fullscreen.take();
|
||||
self.dirty.store(true, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.fullscreen_surfaces.retain(|f| {
|
||||
if let Some(end) = f.ended_at
|
||||
&& Instant::now().duration_since(end) >= FULLSCREEN_ANIMATION_DURATION
|
||||
{
|
||||
self.dirty.store(true, Ordering::SeqCst);
|
||||
return false;
|
||||
}
|
||||
true
|
||||
});
|
||||
|
||||
let clients = self.tiling_layer.update_animation_state();
|
||||
self.floating_layer.update_animation_state();
|
||||
clients
|
||||
|
|
@ -574,7 +577,11 @@ impl Workspace {
|
|||
toplevel_enter_output(&surface, output);
|
||||
}
|
||||
}
|
||||
if let Some(f) = self.fullscreen.as_ref().filter(|f| f.ended_at.is_none()) {
|
||||
for f in self
|
||||
.fullscreen_surfaces
|
||||
.iter()
|
||||
.filter(|f| f.ended_at.is_none())
|
||||
{
|
||||
toplevel_leave_output(&f.surface, &self.output);
|
||||
toplevel_enter_output(&f.surface, output);
|
||||
}
|
||||
|
|
@ -665,12 +672,13 @@ impl Workspace {
|
|||
where
|
||||
CosmicSurface: PartialEq<S>,
|
||||
{
|
||||
if self
|
||||
.fullscreen
|
||||
.as_ref()
|
||||
.is_some_and(|f| f.ended_at.is_none() && &f.surface == surface)
|
||||
if let Some(idx) = self
|
||||
.fullscreen_surfaces
|
||||
.iter()
|
||||
.position(|f| f.ended_at.is_none() && &f.surface == surface)
|
||||
{
|
||||
let (surface, previous_state, previous_geometry) = self.remove_fullscreen().unwrap();
|
||||
let (surface, previous_state, previous_geometry) =
|
||||
self.remove_fullscreen_at(idx).unwrap();
|
||||
return Some((
|
||||
surface,
|
||||
WorkspaceRestoreData::Fullscreen(previous_state.zip(previous_geometry).map(
|
||||
|
|
@ -723,24 +731,28 @@ impl Workspace {
|
|||
Some((mapped.active_window(), layer))
|
||||
}
|
||||
|
||||
pub fn fullscreen_geometry(&self) -> Option<Rectangle<i32, Local>> {
|
||||
self.fullscreen.as_ref().map(|fullscreen| {
|
||||
let bbox = fullscreen.surface.bbox().as_local();
|
||||
pub fn fullscreen_geometry_for_surface(
|
||||
&self,
|
||||
surface: &CosmicSurface,
|
||||
) -> Rectangle<i32, Local> {
|
||||
let bbox = surface.bbox().as_local();
|
||||
|
||||
let mut full_geo = Rectangle::from_size(self.output.geometry().size.as_local());
|
||||
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;
|
||||
}
|
||||
let mut full_geo = Rectangle::from_size(self.output.geometry().size.as_local());
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
full_geo
|
||||
})
|
||||
full_geo
|
||||
}
|
||||
pub fn fullscreen_geometry_for(&self, fullscreen: &FullscreenSurface) -> Rectangle<i32, Local> {
|
||||
self.fullscreen_geometry_for_surface(&fullscreen.surface)
|
||||
}
|
||||
|
||||
pub fn element_for_surface<S>(&self, surface: &S) -> Option<&CosmicMapped>
|
||||
|
|
@ -780,13 +792,12 @@ impl Workspace {
|
|||
let stack = self.focus_stack.get(seat);
|
||||
let last_focused = stack.last();
|
||||
|
||||
if let Some(fullscreen) = self.fullscreen.as_ref()
|
||||
&& last_focused.is_some_and(
|
||||
|t| matches!(t, FocusTarget::Fullscreen(f) if f == &fullscreen.surface),
|
||||
)
|
||||
&& !fullscreen.is_animating()
|
||||
{
|
||||
let geometry = self.fullscreen_geometry().unwrap();
|
||||
if let Some(fullscreen) = self.fullscreen_surfaces.iter().find(|f| {
|
||||
!f.is_animating()
|
||||
&& last_focused
|
||||
.is_some_and(|t| matches!(t, FocusTarget::Fullscreen(s) if s == &f.surface))
|
||||
}) {
|
||||
let geometry = self.fullscreen_geometry_for(fullscreen);
|
||||
return fullscreen_element_under(fullscreen, geometry);
|
||||
}
|
||||
|
||||
|
|
@ -795,9 +806,9 @@ impl Workspace {
|
|||
.or_else(|| self.tiling_layer.popup_element_under(location, seat))
|
||||
.or_else(|| {
|
||||
if last_focused.is_none_or(|t| !matches!(t, FocusTarget::Fullscreen(_)))
|
||||
&& let Some(fullscreen) = self.fullscreen.as_ref()
|
||||
&& let Some(fullscreen) = self.get_fullscreen(seat)
|
||||
{
|
||||
let geometry = self.fullscreen_geometry().unwrap();
|
||||
let geometry = self.fullscreen_geometry_for(fullscreen);
|
||||
return fullscreen_element_under(fullscreen, geometry);
|
||||
}
|
||||
None
|
||||
|
|
@ -830,13 +841,12 @@ impl Workspace {
|
|||
let stack = self.focus_stack.get(seat);
|
||||
let last_focused = stack.last();
|
||||
|
||||
if let Some(fullscreen) = self.fullscreen.as_ref()
|
||||
&& last_focused.is_some_and(
|
||||
|t| matches!(t, FocusTarget::Fullscreen(f) if f == &fullscreen.surface),
|
||||
)
|
||||
&& !fullscreen.is_animating()
|
||||
{
|
||||
let geometry = self.fullscreen_geometry().unwrap();
|
||||
if let Some(fullscreen) = self.fullscreen_surfaces.iter().find(|fs| {
|
||||
!fs.is_animating()
|
||||
&& last_focused
|
||||
.is_some_and(|t| matches!(t, FocusTarget::Fullscreen(f) if f == &fs.surface))
|
||||
}) {
|
||||
let geometry = self.fullscreen_geometry_for(fullscreen);
|
||||
return fullscreen_element_under(fullscreen, geometry);
|
||||
}
|
||||
|
||||
|
|
@ -845,9 +855,9 @@ impl Workspace {
|
|||
.or_else(|| self.tiling_layer.toplevel_element_under(location, seat))
|
||||
.or_else(|| {
|
||||
if last_focused.is_none_or(|t| !matches!(t, FocusTarget::Fullscreen(_)))
|
||||
&& let Some(fullscreen) = self.fullscreen.as_ref()
|
||||
&& let Some(fullscreen) = self.get_fullscreen(seat)
|
||||
{
|
||||
let geometry = self.fullscreen_geometry().unwrap();
|
||||
let geometry = self.fullscreen_geometry_for(fullscreen);
|
||||
return fullscreen_element_under(fullscreen, geometry);
|
||||
}
|
||||
None
|
||||
|
|
@ -867,7 +877,7 @@ impl Workspace {
|
|||
|
||||
let check_fullscreen = |fullscreen: &FullscreenSurface| {
|
||||
if !fullscreen.is_animating() {
|
||||
let geometry = self.fullscreen_geometry().unwrap();
|
||||
let geometry = self.fullscreen_geometry_for(fullscreen);
|
||||
return fullscreen
|
||||
.surface
|
||||
.0
|
||||
|
|
@ -891,21 +901,16 @@ impl Workspace {
|
|||
let stack = self.focus_stack.get(seat);
|
||||
let last_focused = stack.last();
|
||||
|
||||
self.fullscreen
|
||||
.as_ref()
|
||||
.filter(|f| last_focused.is_some_and(|t| t == &f.surface))
|
||||
self.fullscreen_surfaces
|
||||
.iter()
|
||||
.find(|f| last_focused.is_some_and(|t| t == &f.surface))
|
||||
.and_then(check_fullscreen)
|
||||
.or_else(|| self.floating_layer.popup_surface_under(location, seat))
|
||||
.or_else(|| {
|
||||
self.tiling_layer
|
||||
.popup_surface_under(location, overview, seat)
|
||||
})
|
||||
.or_else(|| {
|
||||
self.fullscreen
|
||||
.as_ref()
|
||||
.filter(|f| last_focused.is_none_or(|t| t != &f.surface))
|
||||
.and_then(check_fullscreen)
|
||||
})
|
||||
.or_else(|| self.get_fullscreen(seat).and_then(check_fullscreen))
|
||||
.map(|(m, p)| (m, p.to_global(&self.output)))
|
||||
}
|
||||
|
||||
|
|
@ -922,7 +927,7 @@ impl Workspace {
|
|||
|
||||
let check_fullscreen = |fullscreen: &FullscreenSurface| {
|
||||
if !fullscreen.is_animating() {
|
||||
let geometry = self.fullscreen_geometry().unwrap();
|
||||
let geometry = self.fullscreen_geometry_for(fullscreen);
|
||||
return fullscreen
|
||||
.surface
|
||||
.focus_under(
|
||||
|
|
@ -940,21 +945,16 @@ impl Workspace {
|
|||
let stack = self.focus_stack.get(seat);
|
||||
let last_focused = stack.last();
|
||||
|
||||
self.fullscreen
|
||||
.as_ref()
|
||||
.filter(|f| last_focused.is_some_and(|t| t == &f.surface))
|
||||
self.fullscreen_surfaces
|
||||
.iter()
|
||||
.find(|f| last_focused.is_some_and(|t| t == &f.surface))
|
||||
.and_then(check_fullscreen)
|
||||
.or_else(|| self.floating_layer.toplevel_surface_under(location, seat))
|
||||
.or_else(|| {
|
||||
self.tiling_layer
|
||||
.toplevel_surface_under(location, overview, seat)
|
||||
})
|
||||
.or_else(|| {
|
||||
self.fullscreen
|
||||
.as_ref()
|
||||
.filter(|f| last_focused.is_none_or(|t| t != &f.surface))
|
||||
.and_then(check_fullscreen)
|
||||
})
|
||||
.or_else(|| self.get_fullscreen(seat).and_then(check_fullscreen))
|
||||
.map(|(m, p)| (m, p.to_global(&self.output)))
|
||||
}
|
||||
|
||||
|
|
@ -1026,10 +1026,14 @@ impl Workspace {
|
|||
where
|
||||
CosmicSurface: PartialEq<S>,
|
||||
{
|
||||
if self.get_fullscreen().is_some_and(|s| s == surface) {
|
||||
let fullscreen_state = self.fullscreen.clone().unwrap();
|
||||
if let Some(idx) = self
|
||||
.fullscreen_surfaces
|
||||
.iter()
|
||||
.position(|f| f.ended_at.is_none() && &f.surface == surface)
|
||||
{
|
||||
let fullscreen_state = self.fullscreen_surfaces.get(idx)?.clone();
|
||||
{
|
||||
let f = self.fullscreen.as_mut().unwrap();
|
||||
let f = self.fullscreen_surfaces.get_mut(idx)?;
|
||||
f.previous_geometry = Some(to);
|
||||
f.ended_at = Some(
|
||||
Instant::now()
|
||||
|
|
@ -1133,16 +1137,20 @@ impl Workspace {
|
|||
)> {
|
||||
match window {
|
||||
MinimizedWindow::Fullscreen { previous, surface } => {
|
||||
let old_fullscreen = self.remove_fullscreen();
|
||||
surface.set_minimized(false);
|
||||
self.fullscreen = Some(FullscreenSurface {
|
||||
// focus it so it's the top fullscreen window
|
||||
self.focus_stack
|
||||
.get_mut(seat)
|
||||
.append(FocusTarget::Fullscreen(surface.clone()));
|
||||
self.fullscreen_surfaces.push(FullscreenSurface {
|
||||
surface,
|
||||
previous_state: previous.clone().map(|p| p.previous_state),
|
||||
previous_geometry: previous.map(|p| p.previous_geometry),
|
||||
start_at: None,
|
||||
ended_at: None,
|
||||
});
|
||||
old_fullscreen
|
||||
self.dirty.store(true, Ordering::SeqCst);
|
||||
None
|
||||
}
|
||||
MinimizedWindow::Floating { window, previous } => {
|
||||
let current_output_size = self.output.geometry().size.as_logical();
|
||||
|
|
@ -1230,13 +1238,7 @@ impl Workspace {
|
|||
seat: impl Into<Option<&'a Seat<State>>>,
|
||||
restore: Option<FullscreenRestoreState>,
|
||||
previous_geometry: Option<Rectangle<i32, Local>>,
|
||||
) -> Option<(
|
||||
CosmicSurface,
|
||||
Option<FullscreenRestoreState>,
|
||||
Option<Rectangle<i32, Local>>,
|
||||
)> {
|
||||
let res = self.remove_fullscreen();
|
||||
|
||||
) {
|
||||
window.set_fullscreen(true);
|
||||
window.set_geometry(self.output.geometry(), 0);
|
||||
window.send_configure();
|
||||
|
|
@ -1249,96 +1251,137 @@ impl Workspace {
|
|||
self.focus_stack.get_mut(seat).append(window.clone());
|
||||
}
|
||||
|
||||
self.fullscreen = Some(FullscreenSurface {
|
||||
self.dirty.store(true, Ordering::SeqCst);
|
||||
self.fullscreen_surfaces.push(FullscreenSurface {
|
||||
surface: window.clone(),
|
||||
previous_state: restore,
|
||||
previous_geometry,
|
||||
start_at: Some(Instant::now()),
|
||||
ended_at: None,
|
||||
});
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn take_fullscreen(
|
||||
pub fn take_fullscreen<S>(
|
||||
&mut self,
|
||||
surface: &S,
|
||||
) -> Option<(
|
||||
CosmicSurface,
|
||||
Option<FullscreenRestoreState>,
|
||||
Option<Rectangle<i32, Local>>,
|
||||
)>
|
||||
where
|
||||
CosmicSurface: PartialEq<S>,
|
||||
{
|
||||
let idx = self
|
||||
.fullscreen_surfaces
|
||||
.iter()
|
||||
.position(|f| f.ended_at.is_none() && &f.surface == surface)?;
|
||||
let fs = self.fullscreen_surfaces.remove(idx);
|
||||
|
||||
for focus_stack in self.focus_stack.0.values_mut() {
|
||||
focus_stack.retain(|t| t != &fs.surface);
|
||||
}
|
||||
|
||||
Some((fs.surface, fs.previous_state, fs.previous_geometry))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn remove_fullscreen_at(
|
||||
&mut self,
|
||||
idx: usize,
|
||||
) -> Option<(
|
||||
CosmicSurface,
|
||||
Option<FullscreenRestoreState>,
|
||||
Option<Rectangle<i32, Local>>,
|
||||
)> {
|
||||
let surface = self.fullscreen.take_if(|s| s.ended_at.is_none())?;
|
||||
// if it doesn't exist we move on.
|
||||
let surface = self.fullscreen_surfaces.get_mut(idx)?;
|
||||
// if already being removed, do nothing
|
||||
if surface.ended_at.is_some() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if surface.surface.alive() {
|
||||
surface.surface.output_leave(&self.output);
|
||||
surface.surface.set_fullscreen(false);
|
||||
if let Some(previous_geometry) = surface.previous_geometry.as_ref() {
|
||||
surface
|
||||
.surface
|
||||
.set_geometry(previous_geometry.to_global(&self.output), 0);
|
||||
}
|
||||
surface.surface.send_configure();
|
||||
}
|
||||
|
||||
for focus_stack in self.focus_stack.0.values_mut() {
|
||||
focus_stack.retain(|t| t != &surface.surface);
|
||||
}
|
||||
|
||||
surface.ended_at = Some(
|
||||
Instant::now()
|
||||
- (FULLSCREEN_ANIMATION_DURATION
|
||||
- surface
|
||||
.start_at
|
||||
.take()
|
||||
.map(|earlier| {
|
||||
Instant::now()
|
||||
.duration_since(earlier)
|
||||
.min(FULLSCREEN_ANIMATION_DURATION)
|
||||
})
|
||||
.unwrap_or(FULLSCREEN_ANIMATION_DURATION)),
|
||||
);
|
||||
|
||||
Some((
|
||||
surface.surface,
|
||||
surface.previous_state,
|
||||
surface.surface.clone(),
|
||||
surface.previous_state.clone(),
|
||||
surface.previous_geometry,
|
||||
))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn remove_fullscreen(
|
||||
pub fn remove_fullscreen_surface<S>(
|
||||
&mut self,
|
||||
surface: &S,
|
||||
) -> Option<(
|
||||
CosmicSurface,
|
||||
Option<FullscreenRestoreState>,
|
||||
Option<Rectangle<i32, Local>>,
|
||||
)> {
|
||||
if let Some(surface) = self.fullscreen.as_mut() {
|
||||
if surface.ended_at.is_some() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if surface.surface.alive() {
|
||||
surface.surface.output_leave(&self.output);
|
||||
surface.surface.set_fullscreen(false);
|
||||
if let Some(previous_geometry) = surface.previous_geometry.as_ref() {
|
||||
surface
|
||||
.surface
|
||||
.set_geometry(previous_geometry.to_global(&self.output), 0);
|
||||
}
|
||||
surface.surface.send_configure();
|
||||
}
|
||||
|
||||
for focus_stack in self.focus_stack.0.values_mut() {
|
||||
focus_stack.retain(|t| t != &surface.surface);
|
||||
}
|
||||
|
||||
surface.ended_at = Some(
|
||||
Instant::now()
|
||||
- (FULLSCREEN_ANIMATION_DURATION
|
||||
- surface
|
||||
.start_at
|
||||
.take()
|
||||
.map(|earlier| {
|
||||
Instant::now()
|
||||
.duration_since(earlier)
|
||||
.min(FULLSCREEN_ANIMATION_DURATION)
|
||||
})
|
||||
.unwrap_or(FULLSCREEN_ANIMATION_DURATION)),
|
||||
);
|
||||
|
||||
Some((
|
||||
surface.surface.clone(),
|
||||
surface.previous_state.clone(),
|
||||
surface.previous_geometry,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
)>
|
||||
where
|
||||
CosmicSurface: PartialEq<S>,
|
||||
{
|
||||
let idx = self
|
||||
.fullscreen_surfaces
|
||||
.iter()
|
||||
.position(|f| f.ended_at.is_none() && &f.surface == surface)?;
|
||||
self.remove_fullscreen_at(idx)
|
||||
}
|
||||
|
||||
pub fn get_fullscreen(&self) -> Option<&CosmicSurface> {
|
||||
self.fullscreen
|
||||
.as_ref()
|
||||
.filter(|f| f.alive())
|
||||
.filter(|f| f.ended_at.is_none())
|
||||
.map(|f| &f.surface)
|
||||
pub fn get_fullscreen(&self, seat: &Seat<State>) -> Option<&FullscreenSurface> {
|
||||
let stack = self.focus_stack.get(seat);
|
||||
stack
|
||||
.iter()
|
||||
.find_map(|t| {
|
||||
if let FocusTarget::Fullscreen(s) = t {
|
||||
self.fullscreen_surfaces
|
||||
.iter()
|
||||
.find(|f| f.alive() && f.ended_at.is_none() && &f.surface == s)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.or_else(|| {
|
||||
self.fullscreen_surfaces
|
||||
.iter()
|
||||
.rev()
|
||||
.find(|f| f.alive() && f.ended_at.is_none())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_fullscreen_surfaces(&self) -> impl Iterator<Item = &FullscreenSurface> {
|
||||
self.fullscreen_surfaces
|
||||
.iter()
|
||||
.filter(|f| f.alive() && f.ended_at.is_none())
|
||||
}
|
||||
|
||||
pub fn resize(
|
||||
|
|
@ -1465,14 +1508,18 @@ impl Workspace {
|
|||
self.floating_layer.mapped().count()
|
||||
+ self.tiling_layer.mapped().count()
|
||||
+ self.minimized_windows.len()
|
||||
+ if self.fullscreen.is_some() { 1 } else { 0 }
|
||||
+ self
|
||||
.fullscreen_surfaces
|
||||
.iter()
|
||||
.filter(|f| f.ended_at.is_none())
|
||||
.count()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.floating_layer.mapped().next().is_none()
|
||||
&& self.tiling_layer.mapped().next().is_none()
|
||||
&& self.minimized_windows.is_empty()
|
||||
&& self.fullscreen.is_none()
|
||||
&& self.fullscreen_surfaces.is_empty()
|
||||
}
|
||||
|
||||
pub fn is_floating<S>(&self, surface: &S) -> bool
|
||||
|
|
@ -1579,8 +1626,11 @@ impl Workspace {
|
|||
};
|
||||
let focused = self.focus_stack.get(last_active_seat).last().cloned();
|
||||
|
||||
let mut fullscreen_elements = if let Some(fullscreen) = self.fullscreen.as_ref() {
|
||||
let fullscreen_geo = self.fullscreen_geometry().unwrap();
|
||||
let render_fullscreen = |fullscreen: &FullscreenSurface,
|
||||
renderer: &mut R,
|
||||
output_scale: f64|
|
||||
-> Vec<WorkspaceRenderElement<R>> {
|
||||
let fullscreen_geo = self.fullscreen_geometry_for(fullscreen);
|
||||
let previous_geo = fullscreen
|
||||
.previous_geometry
|
||||
.as_ref()
|
||||
|
|
@ -1650,20 +1700,35 @@ impl Workspace {
|
|||
.into_iter()
|
||||
.map(animation_rescale)
|
||||
.collect::<Vec<_>>()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
let top_fullscreen = self.get_fullscreen(last_active_seat);
|
||||
|
||||
let mut fullscreen_elements: Vec<WorkspaceRenderElement<R>> = Vec::new();
|
||||
if let Some(fs) = top_fullscreen {
|
||||
fullscreen_elements.extend(render_fullscreen(fs, renderer, output_scale));
|
||||
}
|
||||
// Also render any animating (entering/exiting) fullscreens
|
||||
for fs in self.fullscreen_surfaces.iter().filter(|f| f.is_animating()) {
|
||||
if top_fullscreen.is_none_or(|top| top.surface != fs.surface) {
|
||||
fullscreen_elements.extend(render_fullscreen(fs, renderer, output_scale));
|
||||
};
|
||||
}
|
||||
|
||||
if matches!(focused, Some(FocusTarget::Fullscreen(_))) {
|
||||
elements.append(&mut fullscreen_elements);
|
||||
}
|
||||
|
||||
let any_fullscreen_animating = self
|
||||
.fullscreen_surfaces
|
||||
.iter()
|
||||
.any(|f| f.start_at.is_some() || f.ended_at.is_some());
|
||||
if !matches!(focused, Some(FocusTarget::Fullscreen(_)))
|
||||
|| any_fullscreen_animating
|
||||
|| self
|
||||
.fullscreen
|
||||
.as_ref()
|
||||
.map(|f| f.start_at.is_some() || f.ended_at.is_some())
|
||||
.unwrap_or(true)
|
||||
.fullscreen_surfaces
|
||||
.iter()
|
||||
.all(|f| !f.alive() || f.ended_at.is_some())
|
||||
{
|
||||
// floating surfaces
|
||||
let alpha = match &overview.0 {
|
||||
|
|
@ -1780,8 +1845,12 @@ impl Workspace {
|
|||
layer_map.non_exclusive_zone().as_local()
|
||||
};
|
||||
|
||||
if let Some(fullscreen) = self.fullscreen.as_ref() {
|
||||
let fullscreen_geo = self.fullscreen_geometry().unwrap();
|
||||
// Render popups for the top (most recently focused) fullscreen
|
||||
let focus_stack = self.focus_stack.get(last_active_seat);
|
||||
let top_fullscreen = self.get_fullscreen(last_active_seat);
|
||||
|
||||
if let Some(fullscreen) = top_fullscreen {
|
||||
let fullscreen_geo = self.fullscreen_geometry_for(fullscreen);
|
||||
let previous_geo = fullscreen
|
||||
.previous_geometry
|
||||
.as_ref()
|
||||
|
|
@ -1838,13 +1907,16 @@ impl Workspace {
|
|||
);
|
||||
}
|
||||
|
||||
let focus_stack = self.focus_stack.get(last_active_seat);
|
||||
let any_fullscreen_animating = self
|
||||
.fullscreen_surfaces
|
||||
.iter()
|
||||
.any(|f| f.start_at.is_some() || f.ended_at.is_some());
|
||||
if !matches!(focus_stack.last(), Some(FocusTarget::Fullscreen(_)))
|
||||
|| any_fullscreen_animating
|
||||
|| self
|
||||
.fullscreen
|
||||
.as_ref()
|
||||
.map(|f| f.start_at.is_some() || f.ended_at.is_some())
|
||||
.unwrap_or(true)
|
||||
.fullscreen_surfaces
|
||||
.iter()
|
||||
.all(|f| !f.alive() || f.ended_at.is_some())
|
||||
{
|
||||
// floating surfaces
|
||||
let alpha = match &overview.0 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue