aboutsummaryrefslogtreecommitdiff
path: root/src/layout/monitor.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/layout/monitor.rs')
-rw-r--r--src/layout/monitor.rs147
1 files changed, 91 insertions, 56 deletions
diff --git a/src/layout/monitor.rs b/src/layout/monitor.rs
index 4c20d533..ab5384a8 100644
--- a/src/layout/monitor.rs
+++ b/src/layout/monitor.rs
@@ -25,7 +25,9 @@ use crate::render_helpers::renderer::NiriRenderer;
use crate::render_helpers::RenderTarget;
use crate::rubber_band::RubberBand;
use crate::utils::transaction::Transaction;
-use crate::utils::{output_size, ResizeEdge};
+use crate::utils::{
+ output_size, round_logical_in_physical, round_logical_in_physical_max1, ResizeEdge,
+};
/// Amount of touchpad movement to scroll the height of one workspace.
const WORKSPACE_GESTURE_MOVEMENT: f64 = 300.;
@@ -943,6 +945,23 @@ impl<W: LayoutElement> Monitor<W> {
self.active_workspace_ref().active_tile_visual_rectangle()
}
+ fn workspace_size(&self, zoom: f64) -> Size<f64, Logical> {
+ let ws_size = self.view_size.upscale(zoom);
+ let scale = self.scale.fractional_scale();
+ ws_size.to_physical_precise_ceil(scale).to_logical(scale)
+ }
+
+ fn workspace_gap(&self, zoom: f64) -> f64 {
+ let scale = self.scale.fractional_scale();
+ let gap = self.view_size.h * 0.1 * zoom;
+ round_logical_in_physical_max1(scale, gap)
+ }
+
+ fn workspace_size_with_gap(&self, zoom: f64) -> Size<f64, Logical> {
+ let gap = self.workspace_gap(zoom);
+ self.workspace_size(zoom) + Size::from((0., gap))
+ }
+
pub fn workspace_render_idx(&self) -> f64 {
if let Some(switch) = &self.workspace_switch {
switch.current_idx()
@@ -953,17 +972,19 @@ impl<W: LayoutElement> Monitor<W> {
pub fn workspaces_render_geo(&self) -> impl Iterator<Item = Rectangle<f64, Logical>> {
let scale = self.scale.fractional_scale();
- let size = self.view_size;
+ let zoom = 1.;
- // Ceil the workspace size in physical pixels.
- let ws_size = size.to_physical_precise_ceil(scale).to_logical(scale);
+ let ws_size = self.workspace_size(zoom);
+ let gap = self.workspace_gap(zoom);
+ let ws_height_with_gap = ws_size.h + gap;
- let first_ws_y = -self.workspace_render_idx() * ws_size.h;
+ let first_ws_y = -self.workspace_render_idx() * ws_height_with_gap;
+ let first_ws_y = round_logical_in_physical(scale, first_ws_y);
- (0..self.workspaces.len()).map(move |idx| {
- let y = first_ws_y + idx as f64 * ws_size.h;
+ // Return position for one-past-last workspace too.
+ (0..=self.workspaces.len()).map(move |idx| {
+ let y = first_ws_y + idx as f64 * ws_height_with_gap;
let loc = Point::from((0., y));
- let loc = loc.to_physical_precise_round(scale).to_logical(scale);
Rectangle::new(loc, ws_size)
})
}
@@ -1031,7 +1052,12 @@ impl<W: LayoutElement> Monitor<W> {
renderer: &'a mut R,
target: RenderTarget,
focus_ring: bool,
- ) -> impl Iterator<Item = MonitorRenderElement<R>> + 'a {
+ ) -> impl Iterator<
+ Item = (
+ Rectangle<f64, Logical>,
+ impl Iterator<Item = MonitorRenderElement<R>> + 'a,
+ ),
+ > {
let _span = tracy_client::span!("Monitor::render_elements");
let scale = self.scale.fractional_scale();
@@ -1072,45 +1098,45 @@ impl<W: LayoutElement> Monitor<W> {
}
}
- self.workspaces_with_render_geo()
- .flat_map(move |(ws, geo)| {
- let map_ws_contents = move |elem: WorkspaceRenderElement<R>| {
+ self.workspaces_with_render_geo().map(move |(ws, geo)| {
+ let map_ws_contents = move |elem: WorkspaceRenderElement<R>| {
+ let elem = CropRenderElement::from_element(elem, scale, crop_bounds)?;
+ let elem = MonitorInnerRenderElement::Workspace(elem);
+ Some(elem)
+ };
+
+ let (floating, scrolling) = ws.render_elements(renderer, target, focus_ring);
+ let floating = floating.filter_map(map_ws_contents);
+ let scrolling = scrolling.filter_map(map_ws_contents);
+
+ let hint = if matches!(insert_hint, Some((hint_ws_id, _)) if hint_ws_id == ws.id()) {
+ let iter = insert_hint.take().unwrap().1;
+ let iter = iter.filter_map(move |elem| {
let elem = CropRenderElement::from_element(elem, scale, crop_bounds)?;
- let elem = MonitorInnerRenderElement::Workspace(elem);
+ let elem = MonitorInnerRenderElement::InsertHint(elem);
Some(elem)
- };
-
- let (floating, scrolling) = ws.render_elements(renderer, target, focus_ring);
- let floating = floating.filter_map(map_ws_contents);
- let scrolling = scrolling.filter_map(map_ws_contents);
-
- let hint = if matches!(insert_hint, Some((hint_ws_id, _)) if hint_ws_id == ws.id())
- {
- let iter = insert_hint.take().unwrap().1;
- let iter = iter.filter_map(move |elem| {
- let elem = CropRenderElement::from_element(elem, scale, crop_bounds)?;
- let elem = MonitorInnerRenderElement::InsertHint(elem);
- Some(elem)
- });
- Some(iter)
- } else {
- None
- };
- let hint = hint.into_iter().flatten();
-
- let iter = floating.chain(hint).chain(scrolling);
-
- iter.map(move |elem| {
- RelocateRenderElement::from_element(
- elem,
- // The offset we get from workspaces_with_render_positions() is already
- // rounded to physical pixels, but it's in the logical coordinate
- // space, so we need to convert it to physical.
- geo.loc.to_physical_precise_round(scale),
- Relocate::Relative,
- )
- })
- })
+ });
+ Some(iter)
+ } else {
+ None
+ };
+ let hint = hint.into_iter().flatten();
+
+ let iter = floating.chain(hint).chain(scrolling);
+
+ let iter = iter.map(move |elem| {
+ RelocateRenderElement::from_element(
+ elem,
+ // The offset we get from workspaces_with_render_positions() is already
+ // rounded to physical pixels, but it's in the logical coordinate
+ // space, so we need to convert it to physical.
+ geo.loc.to_physical_precise_round(scale),
+ Relocate::Relative,
+ )
+ });
+
+ (geo, iter)
+ })
}
pub fn workspace_switch_gesture_begin(&mut self, is_touchpad: bool) {
@@ -1133,7 +1159,7 @@ impl<W: LayoutElement> Monitor<W> {
timestamp: Duration,
is_touchpad: bool,
) -> Option<bool> {
- let Some(WorkspaceSwitch::Gesture(gesture)) = &mut self.workspace_switch else {
+ let Some(WorkspaceSwitch::Gesture(gesture)) = &self.workspace_switch else {
return None;
};
@@ -1141,13 +1167,18 @@ impl<W: LayoutElement> Monitor<W> {
return None;
}
- gesture.tracker.push(delta_y, timestamp);
-
let total_height = if gesture.is_touchpad {
WORKSPACE_GESTURE_MOVEMENT
} else {
- self.workspaces[0].view_size().h
+ self.workspace_size_with_gap(1.).h
+ };
+
+ let Some(WorkspaceSwitch::Gesture(gesture)) = &mut self.workspace_switch else {
+ return None;
};
+
+ gesture.tracker.push(delta_y, timestamp);
+
let pos = gesture.tracker.pos() / total_height;
let (min, max) = gesture.min_max(self.workspaces.len());
@@ -1163,7 +1194,7 @@ impl<W: LayoutElement> Monitor<W> {
}
pub fn workspace_switch_gesture_end(&mut self, is_touchpad: Option<bool>) -> bool {
- let Some(WorkspaceSwitch::Gesture(gesture)) = &mut self.workspace_switch else {
+ let Some(WorkspaceSwitch::Gesture(gesture)) = &self.workspace_switch else {
return false;
};
@@ -1171,16 +1202,20 @@ impl<W: LayoutElement> Monitor<W> {
return false;
}
- // Take into account any idle time between the last event and now.
- let now = self.clock.now_unadjusted();
- gesture.tracker.push(0., now);
-
let total_height = if gesture.is_touchpad {
WORKSPACE_GESTURE_MOVEMENT
} else {
- self.workspaces[0].view_size().h
+ self.workspace_size_with_gap(1.).h
+ };
+
+ let Some(WorkspaceSwitch::Gesture(gesture)) = &mut self.workspace_switch else {
+ return false;
};
+ // Take into account any idle time between the last event and now.
+ let now = self.clock.now_unadjusted();
+ gesture.tracker.push(0., now);
+
let mut velocity = gesture.tracker.velocity() / total_height;
let current_pos = gesture.tracker.pos() / total_height;
let pos = gesture.tracker.projected_end_pos() / total_height;