mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-23 02:05:33 +07:00
Split layout mod into files
No functional change intended.
This commit is contained in:
@@ -0,0 +1,108 @@
|
|||||||
|
use std::iter::zip;
|
||||||
|
|
||||||
|
use arrayvec::ArrayVec;
|
||||||
|
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
|
||||||
|
use smithay::backend::renderer::element::Kind;
|
||||||
|
use smithay::utils::{Logical, Point, Scale, Size};
|
||||||
|
|
||||||
|
use crate::config::{self, Color};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FocusRing {
|
||||||
|
buffers: [SolidColorBuffer; 4],
|
||||||
|
locations: [Point<i32, Logical>; 4],
|
||||||
|
is_off: bool,
|
||||||
|
is_border: bool,
|
||||||
|
width: i32,
|
||||||
|
active_color: Color,
|
||||||
|
inactive_color: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type FocusRingRenderElement = SolidColorRenderElement;
|
||||||
|
|
||||||
|
impl FocusRing {
|
||||||
|
pub fn new(config: config::FocusRing) -> Self {
|
||||||
|
Self {
|
||||||
|
buffers: Default::default(),
|
||||||
|
locations: Default::default(),
|
||||||
|
is_off: config.off,
|
||||||
|
is_border: false,
|
||||||
|
width: config.width.into(),
|
||||||
|
active_color: config.active_color,
|
||||||
|
inactive_color: config.inactive_color,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_config(&mut self, config: config::FocusRing) {
|
||||||
|
self.is_off = config.off;
|
||||||
|
self.width = config.width.into();
|
||||||
|
self.active_color = config.active_color;
|
||||||
|
self.inactive_color = config.inactive_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(
|
||||||
|
&mut self,
|
||||||
|
win_pos: Point<i32, Logical>,
|
||||||
|
win_size: Size<i32, Logical>,
|
||||||
|
is_border: bool,
|
||||||
|
) {
|
||||||
|
if is_border {
|
||||||
|
self.buffers[0].resize((win_size.w + self.width * 2, self.width));
|
||||||
|
self.buffers[1].resize((win_size.w + self.width * 2, self.width));
|
||||||
|
self.buffers[2].resize((self.width, win_size.h));
|
||||||
|
self.buffers[3].resize((self.width, win_size.h));
|
||||||
|
|
||||||
|
self.locations[0] = win_pos + Point::from((-self.width, -self.width));
|
||||||
|
self.locations[1] = win_pos + Point::from((-self.width, win_size.h));
|
||||||
|
self.locations[2] = win_pos + Point::from((-self.width, 0));
|
||||||
|
self.locations[3] = win_pos + Point::from((win_size.w, 0));
|
||||||
|
} else {
|
||||||
|
let size = win_size + Size::from((self.width * 2, self.width * 2));
|
||||||
|
self.buffers[0].resize(size);
|
||||||
|
self.locations[0] = win_pos - Point::from((self.width, self.width));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.is_border = is_border;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_active(&mut self, is_active: bool) {
|
||||||
|
let color = if is_active {
|
||||||
|
self.active_color.into()
|
||||||
|
} else {
|
||||||
|
self.inactive_color.into()
|
||||||
|
};
|
||||||
|
|
||||||
|
for buf in &mut self.buffers {
|
||||||
|
buf.set_color(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&self, scale: Scale<f64>) -> impl Iterator<Item = SolidColorRenderElement> {
|
||||||
|
let mut rv = ArrayVec::<_, 4>::new();
|
||||||
|
|
||||||
|
if self.is_off {
|
||||||
|
return rv.into_iter();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut push = |buffer, location: Point<i32, Logical>| {
|
||||||
|
let elem = SolidColorRenderElement::from_buffer(
|
||||||
|
buffer,
|
||||||
|
location.to_physical_precise_round(scale),
|
||||||
|
scale,
|
||||||
|
1.,
|
||||||
|
Kind::Unspecified,
|
||||||
|
);
|
||||||
|
rv.push(elem);
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.is_border {
|
||||||
|
for (buf, loc) in zip(&self.buffers, self.locations) {
|
||||||
|
push(buf, loc);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
push(&self.buffers[0], self.locations[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
rv.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
-2068
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,565 @@
|
|||||||
|
use std::cmp::min;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use smithay::backend::renderer::element::utils::{
|
||||||
|
CropRenderElement, Relocate, RelocateRenderElement,
|
||||||
|
};
|
||||||
|
use smithay::backend::renderer::gles::GlesRenderer;
|
||||||
|
use smithay::desktop::Window;
|
||||||
|
use smithay::output::Output;
|
||||||
|
use smithay::utils::{Logical, Point, Rectangle, Scale};
|
||||||
|
|
||||||
|
use super::workspace::{
|
||||||
|
compute_working_area, ColumnWidth, OutputId, Workspace, WorkspaceRenderElement,
|
||||||
|
};
|
||||||
|
use super::{LayoutElement, Options};
|
||||||
|
use crate::animation::Animation;
|
||||||
|
use crate::config::SizeChange;
|
||||||
|
use crate::utils::output_size;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Monitor<W: LayoutElement> {
|
||||||
|
/// Output for this monitor.
|
||||||
|
pub output: Output,
|
||||||
|
// Must always contain at least one.
|
||||||
|
pub workspaces: Vec<Workspace<W>>,
|
||||||
|
/// Index of the currently active workspace.
|
||||||
|
pub active_workspace_idx: usize,
|
||||||
|
/// In-progress switch between workspaces.
|
||||||
|
pub workspace_switch: Option<WorkspaceSwitch>,
|
||||||
|
/// Configurable properties of the layout.
|
||||||
|
pub options: Rc<Options>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum WorkspaceSwitch {
|
||||||
|
Animation(Animation),
|
||||||
|
Gesture(WorkspaceSwitchGesture),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct WorkspaceSwitchGesture {
|
||||||
|
/// Index of the workspace where the gesture was started.
|
||||||
|
pub center_idx: usize,
|
||||||
|
/// Current, fractional workspace index.
|
||||||
|
pub current_idx: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type MonitorRenderElement<R> =
|
||||||
|
RelocateRenderElement<CropRenderElement<WorkspaceRenderElement<R>>>;
|
||||||
|
|
||||||
|
impl WorkspaceSwitch {
|
||||||
|
pub fn current_idx(&self) -> f64 {
|
||||||
|
match self {
|
||||||
|
WorkspaceSwitch::Animation(anim) => anim.value(),
|
||||||
|
WorkspaceSwitch::Gesture(gesture) => gesture.current_idx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the workspace switch is [`Animation`].
|
||||||
|
///
|
||||||
|
/// [`Animation`]: WorkspaceSwitch::Animation
|
||||||
|
#[must_use]
|
||||||
|
fn is_animation(&self) -> bool {
|
||||||
|
matches!(self, Self::Animation(..))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: LayoutElement> Monitor<W> {
|
||||||
|
pub fn new(output: Output, workspaces: Vec<Workspace<W>>, options: Rc<Options>) -> Self {
|
||||||
|
Self {
|
||||||
|
output,
|
||||||
|
workspaces,
|
||||||
|
active_workspace_idx: 0,
|
||||||
|
workspace_switch: None,
|
||||||
|
options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn active_workspace(&mut self) -> &mut Workspace<W> {
|
||||||
|
&mut self.workspaces[self.active_workspace_idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn activate_workspace(&mut self, idx: usize) {
|
||||||
|
if self.active_workspace_idx == idx {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let current_idx = self
|
||||||
|
.workspace_switch
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| s.current_idx())
|
||||||
|
.unwrap_or(self.active_workspace_idx as f64);
|
||||||
|
|
||||||
|
self.active_workspace_idx = idx;
|
||||||
|
|
||||||
|
self.workspace_switch = Some(WorkspaceSwitch::Animation(Animation::new(
|
||||||
|
current_idx,
|
||||||
|
idx as f64,
|
||||||
|
Duration::from_millis(250),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_window(
|
||||||
|
&mut self,
|
||||||
|
workspace_idx: usize,
|
||||||
|
window: W,
|
||||||
|
activate: bool,
|
||||||
|
width: ColumnWidth,
|
||||||
|
is_full_width: bool,
|
||||||
|
) {
|
||||||
|
let workspace = &mut self.workspaces[workspace_idx];
|
||||||
|
|
||||||
|
workspace.add_window(window.clone(), activate, width, is_full_width);
|
||||||
|
|
||||||
|
// After adding a new window, workspace becomes this output's own.
|
||||||
|
workspace.original_output = OutputId::new(&self.output);
|
||||||
|
|
||||||
|
if workspace_idx == self.workspaces.len() - 1 {
|
||||||
|
// Insert a new empty workspace.
|
||||||
|
let ws = Workspace::new(self.output.clone(), self.options.clone());
|
||||||
|
self.workspaces.push(ws);
|
||||||
|
}
|
||||||
|
|
||||||
|
if activate {
|
||||||
|
self.activate_workspace(workspace_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clean_up_workspaces(&mut self) {
|
||||||
|
assert!(self.workspace_switch.is_none());
|
||||||
|
|
||||||
|
for idx in (0..self.workspaces.len() - 1).rev() {
|
||||||
|
if self.active_workspace_idx == idx {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.workspaces[idx].has_windows() {
|
||||||
|
self.workspaces.remove(idx);
|
||||||
|
if self.active_workspace_idx > idx {
|
||||||
|
self.active_workspace_idx -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_left(&mut self) {
|
||||||
|
self.active_workspace().move_left();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_right(&mut self) {
|
||||||
|
self.active_workspace().move_right();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_down(&mut self) {
|
||||||
|
self.active_workspace().move_down();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_up(&mut self) {
|
||||||
|
self.active_workspace().move_up();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_down_or_to_workspace_down(&mut self) {
|
||||||
|
let workspace = self.active_workspace();
|
||||||
|
if workspace.columns.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let column = &mut workspace.columns[workspace.active_column_idx];
|
||||||
|
let curr_idx = column.active_window_idx;
|
||||||
|
let new_idx = min(column.active_window_idx + 1, column.windows.len() - 1);
|
||||||
|
if curr_idx == new_idx {
|
||||||
|
self.move_to_workspace_down();
|
||||||
|
} else {
|
||||||
|
workspace.move_down();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_up_or_to_workspace_up(&mut self) {
|
||||||
|
let workspace = self.active_workspace();
|
||||||
|
if workspace.columns.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let curr_idx = workspace.columns[workspace.active_column_idx].active_window_idx;
|
||||||
|
let new_idx = curr_idx.saturating_sub(1);
|
||||||
|
if curr_idx == new_idx {
|
||||||
|
self.move_to_workspace_up();
|
||||||
|
} else {
|
||||||
|
workspace.move_up();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_left(&mut self) {
|
||||||
|
self.active_workspace().focus_left();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_right(&mut self) {
|
||||||
|
self.active_workspace().focus_right();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_down(&mut self) {
|
||||||
|
self.active_workspace().focus_down();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_up(&mut self) {
|
||||||
|
self.active_workspace().focus_up();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_window_or_workspace_down(&mut self) {
|
||||||
|
let workspace = self.active_workspace();
|
||||||
|
if workspace.columns.is_empty() {
|
||||||
|
self.switch_workspace_down();
|
||||||
|
} else {
|
||||||
|
let column = &workspace.columns[workspace.active_column_idx];
|
||||||
|
let curr_idx = column.active_window_idx;
|
||||||
|
let new_idx = min(column.active_window_idx + 1, column.windows.len() - 1);
|
||||||
|
if curr_idx == new_idx {
|
||||||
|
self.switch_workspace_down();
|
||||||
|
} else {
|
||||||
|
workspace.focus_down();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_window_or_workspace_up(&mut self) {
|
||||||
|
let workspace = self.active_workspace();
|
||||||
|
if workspace.columns.is_empty() {
|
||||||
|
self.switch_workspace_up();
|
||||||
|
} else {
|
||||||
|
let curr_idx = workspace.columns[workspace.active_column_idx].active_window_idx;
|
||||||
|
let new_idx = curr_idx.saturating_sub(1);
|
||||||
|
if curr_idx == new_idx {
|
||||||
|
self.switch_workspace_up();
|
||||||
|
} else {
|
||||||
|
workspace.focus_up();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_to_workspace_up(&mut self) {
|
||||||
|
let source_workspace_idx = self.active_workspace_idx;
|
||||||
|
|
||||||
|
let new_idx = source_workspace_idx.saturating_sub(1);
|
||||||
|
if new_idx == source_workspace_idx {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let workspace = &mut self.workspaces[source_workspace_idx];
|
||||||
|
if workspace.columns.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let column = &mut workspace.columns[workspace.active_column_idx];
|
||||||
|
let width = column.width;
|
||||||
|
let is_full_width = column.is_full_width;
|
||||||
|
let window = column.windows[column.active_window_idx].clone();
|
||||||
|
workspace.remove_window(&window);
|
||||||
|
|
||||||
|
self.add_window(new_idx, window, true, width, is_full_width);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_to_workspace_down(&mut self) {
|
||||||
|
let source_workspace_idx = self.active_workspace_idx;
|
||||||
|
|
||||||
|
let new_idx = min(source_workspace_idx + 1, self.workspaces.len() - 1);
|
||||||
|
if new_idx == source_workspace_idx {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let workspace = &mut self.workspaces[source_workspace_idx];
|
||||||
|
if workspace.columns.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let column = &mut workspace.columns[workspace.active_column_idx];
|
||||||
|
let width = column.width;
|
||||||
|
let is_full_width = column.is_full_width;
|
||||||
|
let window = column.windows[column.active_window_idx].clone();
|
||||||
|
workspace.remove_window(&window);
|
||||||
|
|
||||||
|
self.add_window(new_idx, window, true, width, is_full_width);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_to_workspace(&mut self, idx: usize) {
|
||||||
|
let source_workspace_idx = self.active_workspace_idx;
|
||||||
|
|
||||||
|
let new_idx = min(idx, self.workspaces.len() - 1);
|
||||||
|
if new_idx == source_workspace_idx {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let workspace = &mut self.workspaces[source_workspace_idx];
|
||||||
|
if workspace.columns.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let column = &mut workspace.columns[workspace.active_column_idx];
|
||||||
|
let width = column.width;
|
||||||
|
let is_full_width = column.is_full_width;
|
||||||
|
let window = column.windows[column.active_window_idx].clone();
|
||||||
|
workspace.remove_window(&window);
|
||||||
|
|
||||||
|
self.add_window(new_idx, window, true, width, is_full_width);
|
||||||
|
|
||||||
|
// Don't animate this action.
|
||||||
|
self.workspace_switch = None;
|
||||||
|
|
||||||
|
self.clean_up_workspaces();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn switch_workspace_up(&mut self) {
|
||||||
|
self.activate_workspace(self.active_workspace_idx.saturating_sub(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn switch_workspace_down(&mut self) {
|
||||||
|
self.activate_workspace(min(
|
||||||
|
self.active_workspace_idx + 1,
|
||||||
|
self.workspaces.len() - 1,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn switch_workspace(&mut self, idx: usize) {
|
||||||
|
self.activate_workspace(min(idx, self.workspaces.len() - 1));
|
||||||
|
// Don't animate this action.
|
||||||
|
self.workspace_switch = None;
|
||||||
|
|
||||||
|
self.clean_up_workspaces();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn consume_into_column(&mut self) {
|
||||||
|
self.active_workspace().consume_into_column();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expel_from_column(&mut self) {
|
||||||
|
self.active_workspace().expel_from_column();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn center_column(&mut self) {
|
||||||
|
self.active_workspace().center_column();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus(&self) -> Option<&W> {
|
||||||
|
let workspace = &self.workspaces[self.active_workspace_idx];
|
||||||
|
if !workspace.has_windows() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let column = &workspace.columns[workspace.active_column_idx];
|
||||||
|
Some(&column.windows[column.active_window_idx])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn advance_animations(&mut self, current_time: Duration, is_active: bool) {
|
||||||
|
if let Some(WorkspaceSwitch::Animation(anim)) = &mut self.workspace_switch {
|
||||||
|
anim.set_current_time(current_time);
|
||||||
|
if anim.is_done() {
|
||||||
|
self.workspace_switch = None;
|
||||||
|
self.clean_up_workspaces();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ws in &mut self.workspaces {
|
||||||
|
ws.advance_animations(current_time, is_active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn are_animations_ongoing(&self) -> bool {
|
||||||
|
self.workspace_switch
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|s| s.is_animation())
|
||||||
|
|| self.workspaces.iter().any(|ws| ws.are_animations_ongoing())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn are_transitions_ongoing(&self) -> bool {
|
||||||
|
self.workspace_switch.is_some()
|
||||||
|
|| self.workspaces.iter().any(|ws| ws.are_animations_ongoing())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_config(&mut self, options: Rc<Options>) {
|
||||||
|
for ws in &mut self.workspaces {
|
||||||
|
ws.update_config(options.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.options.struts != options.struts {
|
||||||
|
let view_size = output_size(&self.output);
|
||||||
|
let working_area = compute_working_area(&self.output, options.struts);
|
||||||
|
|
||||||
|
for ws in &mut self.workspaces {
|
||||||
|
ws.set_view_size(view_size, working_area);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toggle_width(&mut self) {
|
||||||
|
self.active_workspace().toggle_width();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toggle_full_width(&mut self) {
|
||||||
|
self.active_workspace().toggle_full_width();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_column_width(&mut self, change: SizeChange) {
|
||||||
|
self.active_workspace().set_column_width(change);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_window_height(&mut self, change: SizeChange) {
|
||||||
|
self.active_workspace().set_window_height(change);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_workspace_down(&mut self) {
|
||||||
|
let new_idx = min(self.active_workspace_idx + 1, self.workspaces.len() - 1);
|
||||||
|
if new_idx == self.active_workspace_idx {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.workspaces.swap(self.active_workspace_idx, new_idx);
|
||||||
|
|
||||||
|
if new_idx == self.workspaces.len() - 1 {
|
||||||
|
// Insert a new empty workspace.
|
||||||
|
let ws = Workspace::new(self.output.clone(), self.options.clone());
|
||||||
|
self.workspaces.push(ws);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.activate_workspace(new_idx);
|
||||||
|
self.workspace_switch = None;
|
||||||
|
|
||||||
|
self.clean_up_workspaces();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_workspace_up(&mut self) {
|
||||||
|
let new_idx = self.active_workspace_idx.saturating_sub(1);
|
||||||
|
if new_idx == self.active_workspace_idx {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.workspaces.swap(self.active_workspace_idx, new_idx);
|
||||||
|
|
||||||
|
if self.active_workspace_idx == self.workspaces.len() - 1 {
|
||||||
|
// Insert a new empty workspace.
|
||||||
|
let ws = Workspace::new(self.output.clone(), self.options.clone());
|
||||||
|
self.workspaces.push(ws);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.activate_workspace(new_idx);
|
||||||
|
self.workspace_switch = None;
|
||||||
|
|
||||||
|
self.clean_up_workspaces();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn window_under(
|
||||||
|
&self,
|
||||||
|
pos_within_output: Point<f64, Logical>,
|
||||||
|
) -> Option<(&W, Point<i32, Logical>)> {
|
||||||
|
match &self.workspace_switch {
|
||||||
|
Some(switch) => {
|
||||||
|
let size = output_size(&self.output);
|
||||||
|
|
||||||
|
let render_idx = switch.current_idx();
|
||||||
|
let before_idx = render_idx.floor() as usize;
|
||||||
|
let after_idx = render_idx.ceil() as usize;
|
||||||
|
|
||||||
|
let offset = ((render_idx - before_idx as f64) * size.h as f64).round() as i32;
|
||||||
|
|
||||||
|
let (idx, ws_offset) = if pos_within_output.y < (size.h - offset) as f64 {
|
||||||
|
(before_idx, Point::from((0, offset)))
|
||||||
|
} else {
|
||||||
|
(after_idx, Point::from((0, -size.h + offset)))
|
||||||
|
};
|
||||||
|
|
||||||
|
let ws = &self.workspaces[idx];
|
||||||
|
let (win, win_pos) = ws.window_under(pos_within_output + ws_offset.to_f64())?;
|
||||||
|
Some((win, win_pos - ws_offset))
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let ws = &self.workspaces[self.active_workspace_idx];
|
||||||
|
ws.window_under(pos_within_output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_above_top_layer(&self) -> bool {
|
||||||
|
// Render above the top layer only if the view is stationary.
|
||||||
|
if self.workspace_switch.is_some() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ws = &self.workspaces[self.active_workspace_idx];
|
||||||
|
ws.render_above_top_layer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Monitor<Window> {
|
||||||
|
pub fn render_elements(
|
||||||
|
&self,
|
||||||
|
renderer: &mut GlesRenderer,
|
||||||
|
) -> Vec<MonitorRenderElement<GlesRenderer>> {
|
||||||
|
let _span = tracy_client::span!("Monitor::render_elements");
|
||||||
|
|
||||||
|
let output_scale = Scale::from(self.output.current_scale().fractional_scale());
|
||||||
|
let output_transform = self.output.current_transform();
|
||||||
|
let output_mode = self.output.current_mode().unwrap();
|
||||||
|
let size = output_transform.transform_size(output_mode.size);
|
||||||
|
|
||||||
|
match &self.workspace_switch {
|
||||||
|
Some(switch) => {
|
||||||
|
let render_idx = switch.current_idx();
|
||||||
|
let before_idx = render_idx.floor() as usize;
|
||||||
|
let after_idx = render_idx.ceil() as usize;
|
||||||
|
|
||||||
|
let offset = ((render_idx - before_idx as f64) * size.h as f64).round() as i32;
|
||||||
|
|
||||||
|
let before = self.workspaces[before_idx].render_elements(renderer);
|
||||||
|
let after = self.workspaces[after_idx].render_elements(renderer);
|
||||||
|
|
||||||
|
let before = before.into_iter().filter_map(|elem| {
|
||||||
|
Some(RelocateRenderElement::from_element(
|
||||||
|
CropRenderElement::from_element(
|
||||||
|
elem,
|
||||||
|
output_scale,
|
||||||
|
Rectangle::from_extemities((0, offset), (size.w, size.h)),
|
||||||
|
)?,
|
||||||
|
(0, -offset),
|
||||||
|
Relocate::Relative,
|
||||||
|
))
|
||||||
|
});
|
||||||
|
let after = after.into_iter().filter_map(|elem| {
|
||||||
|
Some(RelocateRenderElement::from_element(
|
||||||
|
CropRenderElement::from_element(
|
||||||
|
elem,
|
||||||
|
output_scale,
|
||||||
|
Rectangle::from_extemities((0, 0), (size.w, offset)),
|
||||||
|
)?,
|
||||||
|
(0, -offset + size.h),
|
||||||
|
Relocate::Relative,
|
||||||
|
))
|
||||||
|
});
|
||||||
|
before.chain(after).collect()
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let elements = self.workspaces[self.active_workspace_idx].render_elements(renderer);
|
||||||
|
elements
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|elem| {
|
||||||
|
Some(RelocateRenderElement::from_element(
|
||||||
|
CropRenderElement::from_element(
|
||||||
|
elem,
|
||||||
|
output_scale,
|
||||||
|
// HACK: set infinite crop bounds due to a damage tracking bug
|
||||||
|
// which causes glitched rendering for maximized GTK windows.
|
||||||
|
// FIXME: use proper bounds after fixing the Crop element.
|
||||||
|
Rectangle::from_loc_and_size(
|
||||||
|
(-i32::MAX / 2, -i32::MAX / 2),
|
||||||
|
(i32::MAX, i32::MAX),
|
||||||
|
),
|
||||||
|
// Rectangle::from_loc_and_size((0, 0), size),
|
||||||
|
)?,
|
||||||
|
(0, 0),
|
||||||
|
Relocate::Relative,
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user