diff --git a/src/backend/kms/mod.rs b/src/backend/kms/mod.rs index af103b26..8cb229b9 100644 --- a/src/backend/kms/mod.rs +++ b/src/backend/kms/mod.rs @@ -1041,13 +1041,20 @@ impl Surface { ); } - let handle = state.shell.workspaces.active(&self.output).handle; + let (previous_workspace, workspace) = state.shell.workspaces.active(&self.output); + let (previous_idx, idx) = state.shell.workspaces.active_num(&self.output); + let previous_workspace = previous_workspace + .zip(previous_idx) + .map(|((w, start), idx)| (w.handle, idx, start)); + let workspace = (workspace.handle, idx); + let elements = workspace_elements( Some(&render_node), &mut renderer, state, &self.output, - &handle, + previous_workspace, + workspace, CursorMode::All, &mut Some(&mut self.fps), false, diff --git a/src/backend/render/element.rs b/src/backend/render/element.rs index 07f5ad11..25ef71a3 100644 --- a/src/backend/render/element.rs +++ b/src/backend/render/element.rs @@ -2,7 +2,10 @@ use crate::shell::{CosmicMappedRenderElement, WorkspaceRenderElement}; use smithay::{ backend::renderer::{ - element::{Element, RenderElement, UnderlyingStorage}, + element::{ + utils::{Relocate, RelocateRenderElement}, + Element, RenderElement, UnderlyingStorage, + }, glow::{GlowFrame, GlowRenderer}, Frame, ImportAll, ImportMem, Renderer, }, @@ -20,7 +23,7 @@ where ::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { - Workspace(WorkspaceRenderElement), + Workspace(RelocateRenderElement>), Cursor(CursorRenderElement), MoveGrab(CosmicMappedRenderElement), #[cfg(feature = "debug")] @@ -211,7 +214,11 @@ where CosmicMappedRenderElement: RenderElement, { fn from(elem: WorkspaceRenderElement) -> Self { - Self::Workspace(elem) + Self::Workspace(RelocateRenderElement::from_element( + elem, + (0, 0), + Relocate::Relative, + )) } } diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index 1155acaf..ec765b6d 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -5,23 +5,24 @@ use std::{ cell::RefCell, collections::HashMap, sync::Weak, + time::Instant, }; -#[cfg(feature = "debug")] -use crate::{ - debug::{fps_ui, profiler_ui}, - utils::prelude::*, -}; use crate::{ + config::WorkspaceLayout, shell::{ - element::window::CosmicWindowRenderElement, focus::target::WindowGroup, - layout::floating::SeatMoveGrabState, CosmicMapped, CosmicMappedRenderElement, - WorkspaceRenderElement, + element::window::CosmicWindowRenderElement, + focus::target::WindowGroup, + layout::{floating::SeatMoveGrabState, tiling::ANIMATION_DURATION}, + CosmicMapped, CosmicMappedRenderElement, WorkspaceRenderElement, }, state::{Common, Fps}, - utils::prelude::SeatExt, + utils::prelude::{OutputExt, SeatExt}, wayland::{ - handlers::{data_device::get_dnd_icon, screencopy::render_session}, + handlers::{ + data_device::get_dnd_icon, + screencopy::{render_session, WORKSPACE_OVERVIEW_NAMESPACE}, + }, protocols::{ screencopy::{ BufferParams, CursorMode as ScreencopyCursorMode, Session as ScreencopySession, @@ -30,8 +31,14 @@ use crate::{ }, }, }; +#[cfg(feature = "debug")] +use crate::{ + debug::{fps_ui, profiler_ui}, + utils::prelude::*, +}; use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::FailureReason; +use cosmic_time::{Cubic, Ease, Tween}; use smithay::{ backend::{ allocator::dmabuf::Dmabuf, @@ -39,7 +46,10 @@ use smithay::{ renderer::{ buffer_dimensions, damage::{Error as RenderError, OutputDamageTracker, OutputNoMode}, - element::{Element, RenderElement, RenderElementStates}, + element::{ + utils::{Relocate, RelocateRenderElement}, + AsRenderElements, Element, RenderElement, RenderElementStates, + }, gles::{ element::PixelShaderElement, GlesError, GlesPixelProgram, GlesRenderer, Uniform, UniformName, UniformType, @@ -49,10 +59,12 @@ use smithay::{ Bind, Blit, ExportMem, ImportAll, ImportMem, Offscreen, Renderer, TextureFilter, }, }, + desktop::layer_map_for_output, output::Output, - utils::{IsAlive, Logical, Physical, Point, Rectangle, Size}, + utils::{IsAlive, Logical, Physical, Point, Rectangle, Scale, Size}, wayland::{ dmabuf::get_dmabuf, + shell::wlr_layer::Layer, shm::{shm_format_to_fourcc, with_buffer_contents}, }, }; @@ -289,7 +301,8 @@ pub fn workspace_elements( renderer: &mut R, state: &mut Common, output: &Output, - handle: &WorkspaceHandle, + previous: Option<(WorkspaceHandle, usize, Instant)>, + current: (WorkspaceHandle, usize), cursor_mode: CursorMode, _fps: &mut Option<&mut Fps>, exclude_workspace_overview: bool, @@ -346,11 +359,17 @@ where state .shell - .space_for_handle_mut(&handle) + .space_for_handle_mut(¤t.0) .ok_or(OutputNoMode)? .update_animations(&state.event_loop_handle); + if let Some((previous, _, _)) = previous.as_ref() { + state + .shell + .space_for_handle_mut(&previous) + .ok_or(OutputNoMode)? + .update_animations(&state.event_loop_handle); + } let overview = state.shell.overview_mode(); - let workspace = state.shell.space_for_handle(&handle).ok_or(OutputNoMode)?; let last_active_seat = state.last_active_seat().clone(); let move_active = last_active_seat .user_data() @@ -359,6 +378,96 @@ where .borrow() .is_some(); let active_output = last_active_seat.active_output(); + let output_size = output.geometry().size; + let output_scale = output.current_scale().fractional_scale(); + + let workspace = state + .shell + .space_for_handle(¤t.0) + .ok_or(OutputNoMode)?; + let has_fullscreen = workspace.fullscreen.contains_key(output); + + // foreground layers are static + elements.extend( + foreground_layer_elements(renderer, output, has_fullscreen, exclude_workspace_overview) + .into_iter() + .map(Into::into), + ); + + let offset = match previous.as_ref() { + Some((previous, previous_idx, start)) => { + let layout = WorkspaceLayout::Vertical; + + let workspace = state + .shell + .space_for_handle(&previous) + .ok_or(OutputNoMode)?; + let is_active_space = workspace.outputs().any(|o| o == &active_output); + + let percentage = { + let percentage = Instant::now().duration_since(*start).as_millis() as f32 + / ANIMATION_DURATION.as_millis() as f32; + Ease::Cubic(Cubic::InOut).tween(percentage) + }; + let offset = Point::::from(match (layout, *previous_idx < current.1) { + (WorkspaceLayout::Vertical, true) => { + (0, (-output_size.h as f32 * percentage).round() as i32) + } + (WorkspaceLayout::Vertical, false) => { + (0, (output_size.h as f32 * percentage).round() as i32) + } + (WorkspaceLayout::Horizontal, true) => { + ((-output_size.w as f32 * percentage).round() as i32, 0) + } + (WorkspaceLayout::Horizontal, false) => { + ((output_size.w as f32 * percentage).round() as i32, 0) + } + }); + + elements.extend( + workspace + .render_output::( + renderer, + output, + &state.shell.override_redirect_windows, + state.xwayland_state.as_mut(), + (!move_active && is_active_space).then_some(&last_active_seat), + overview.clone(), + state.config.static_conf.active_hint, + ) + .map_err(|_| OutputNoMode)? + .into_iter() + .map(|w_element| { + CosmicElement::Workspace(RelocateRenderElement::from_element( + w_element, + offset.to_physical_precise_round(output_scale), + Relocate::Relative, + )) + }), + ); + + elements.extend( + background_layer_elements(renderer, output, exclude_workspace_overview) + .into_iter() + .map(|w_element| { + CosmicElement::Workspace(RelocateRenderElement::from_element( + w_element, + offset.to_physical_precise_round(output_scale), + Relocate::Relative, + )) + }), + ); + + Point::::from(match (layout, *previous_idx < current.1) { + (WorkspaceLayout::Vertical, true) => (0, output_size.h + offset.y), + (WorkspaceLayout::Vertical, false) => (0, -(output_size.h - offset.y)), + (WorkspaceLayout::Horizontal, true) => (output_size.w + offset.x, 0), + (WorkspaceLayout::Horizontal, false) => (-(output_size.w - offset.y), 0), + }) + } + None => (0, 0).into(), + }; + let is_active_space = workspace.outputs().any(|o| o == &active_output); elements.extend( @@ -371,16 +480,118 @@ where (!move_active && is_active_space).then_some(&last_active_seat), overview, state.config.static_conf.active_hint, - exclude_workspace_overview, ) .map_err(|_| OutputNoMode)? .into_iter() - .map(Into::into), + .map(|w_element| { + CosmicElement::Workspace(RelocateRenderElement::from_element( + w_element, + offset.to_physical_precise_round(output_scale), + Relocate::Relative, + )) + }), + ); + + elements.extend( + background_layer_elements(renderer, output, exclude_workspace_overview) + .into_iter() + .map(|w_element| { + CosmicElement::Workspace(RelocateRenderElement::from_element( + w_element, + offset.to_physical_precise_round(output_scale), + Relocate::Relative, + )) + }), ); Ok(elements) } +// bottom and background layer surfaces +pub fn foreground_layer_elements( + renderer: &mut R, + output: &Output, + has_fullscreen: bool, + exclude_workspace_overview: bool, +) -> Vec> +where + R: Renderer + ImportAll + ImportMem + AsGlowRenderer, + ::TextureId: Clone + 'static, + ::Error: From, + CosmicMappedRenderElement: RenderElement, + CosmicWindowRenderElement: RenderElement, + WorkspaceRenderElement: RenderElement, +{ + let layer_map = layer_map_for_output(output); + let output_scale = output.current_scale().fractional_scale(); + + layer_map + .layers() + .rev() + .filter(|s| !(exclude_workspace_overview && s.namespace() == WORKSPACE_OVERVIEW_NAMESPACE)) + .filter(|s| { + if has_fullscreen { + matches!(s.layer(), Layer::Overlay) + } else { + matches!(s.layer(), Layer::Top | Layer::Overlay) + } + }) + .filter_map(|surface| { + layer_map + .layer_geometry(surface) + .map(|geo| (geo.loc, surface)) + }) + .flat_map(|(loc, surface)| { + AsRenderElements::::render_elements::>( + surface, + renderer, + loc.to_physical_precise_round(output_scale), + Scale::from(output_scale), + 1.0, + ) + }) + .collect() +} + +// bottom and background layer surfaces +pub fn background_layer_elements( + renderer: &mut R, + output: &Output, + exclude_workspace_overview: bool, +) -> Vec> +where + R: Renderer + ImportAll + ImportMem + AsGlowRenderer, + ::TextureId: Clone + 'static, + ::Error: From, + CosmicMappedRenderElement: RenderElement, + CosmicWindowRenderElement: RenderElement, + WorkspaceRenderElement: RenderElement, +{ + let layer_map = layer_map_for_output(output); + let output_scale = output.current_scale().fractional_scale(); + + layer_map + .layers() + .rev() + .filter(|s| !(exclude_workspace_overview && s.namespace() == WORKSPACE_OVERVIEW_NAMESPACE)) + .filter(|s| matches!(s.layer(), Layer::Background | Layer::Bottom)) + .filter_map(|surface| { + layer_map + .layer_geometry(surface) + .map(|geo| (geo.loc, surface)) + }) + .flat_map(|(loc, surface)| { + AsRenderElements::::render_elements::>( + surface, + renderer, + loc.to_physical_precise_round(output_scale), + Scale::from(output_scale), + 1.0, + ) + }) + .collect() +} + pub fn render_output( gpu: Option<&DrmNode>, renderer: &mut R, @@ -411,7 +622,13 @@ where WorkspaceRenderElement: RenderElement, Source: Clone, { - let handle = state.shell.workspaces.active(output).handle; + let (previous_workspace, workspace) = state.shell.workspaces.active(output); + let (previous_idx, idx) = state.shell.workspaces.active_num(output); + let previous_workspace = previous_workspace + .zip(previous_idx) + .map(|((w, start), idx)| (w.handle, idx, start)); + let workspace = (workspace.handle, idx); + let result = render_workspace( gpu, renderer, @@ -420,7 +637,8 @@ where age, state, output, - &handle, + previous_workspace, + workspace, cursor_mode, screencopy, fps, @@ -438,7 +656,8 @@ pub fn render_workspace( age: usize, state: &mut Common, output: &Output, - handle: &WorkspaceHandle, + previous: Option<(WorkspaceHandle, usize, Instant)>, + current: (WorkspaceHandle, usize), mut cursor_mode: CursorMode, screencopy: Option<(Source, &[(ScreencopySession, BufferParams)])>, mut fps: Option<&mut Fps>, @@ -496,7 +715,8 @@ where renderer, state, output, - handle, + previous, + current, cursor_mode, &mut fps, exclude_workspace_overview, diff --git a/src/config/mod.rs b/src/config/mod.rs index 1feb854e..19657c55 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -49,6 +49,12 @@ pub enum WorkspaceMode { Global, } +#[derive(Debug, Deserialize, Clone, Copy, PartialEq, Eq)] +pub enum WorkspaceLayout { + Vertical, + Horizontal, +} + pub struct DynamicConfig { outputs: (Option, OutputsConfig), inputs: (Option, InputsConfig), diff --git a/src/input/mod.rs b/src/input/mod.rs index 93f9615f..8640fe78 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -708,6 +708,7 @@ impl State { .shell .workspaces .active_num(¤t_output) + .1 .saturating_add(1); // TODO: Possibly move to next output, if idx to large let _ = self.common.shell.activate(¤t_output, workspace); @@ -719,6 +720,7 @@ impl State { .shell .workspaces .active_num(¤t_output) + .1 .saturating_sub(1); // TODO: Possibly move to prev output, if idx < 0 let _ = self.common.shell.activate(¤t_output, workspace); @@ -756,6 +758,7 @@ impl State { .shell .workspaces .active_num(¤t_output) + .1 .saturating_add(1); // TODO: Possibly move to next output, if idx too large Shell::move_current_window( @@ -773,6 +776,7 @@ impl State { .shell .workspaces .active_num(¤t_output) + .1 .saturating_sub(1); // TODO: Possibly move to prev output, if idx < 0 Shell::move_current_window( @@ -811,7 +815,7 @@ impl State { .next() .cloned() { - let idx = self.common.shell.workspaces.active_num(&next_output); + let idx = self.common.shell.workspaces.active_num(&next_output).1; if let Some(new_pos) = self.common.shell.activate(&next_output, idx) { seat.set_active_output(&next_output); if let Some(ptr) = seat.get_pointer() { @@ -841,7 +845,7 @@ impl State { .next() .cloned() { - let idx = self.common.shell.workspaces.active_num(&prev_output); + let idx = self.common.shell.workspaces.active_num(&prev_output).1; if let Some(new_pos) = self.common.shell.activate(&prev_output, idx) { seat.set_active_output(&prev_output); if let Some(ptr) = seat.get_pointer() { diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 2d704c20..e19fba27 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -87,6 +87,7 @@ pub struct Shell { #[derive(Debug)] pub struct WorkspaceSet { + previously_active: Option<(usize, Instant)>, active: usize, amount: WorkspaceAmount, group: WorkspaceGroupHandle, @@ -155,6 +156,7 @@ impl WorkspaceSet { }; WorkspaceSet { + previously_active: None, active: 0, amount, group: group_handle, @@ -170,6 +172,7 @@ impl WorkspaceSet { let old_active = self.active; state.remove_workspace_state(&self.workspaces[old_active].handle, WState::Active); state.add_workspace_state(&self.workspaces[idx].handle, WState::Active); + self.previously_active = Some((old_active, Instant::now())); self.active = idx; } } @@ -180,12 +183,19 @@ impl WorkspaceSet { toplevel_info: &mut ToplevelInfoState, outputs: impl Iterator)>, ) { + if let Some((_, start)) = self.previously_active { + if Instant::now().duration_since(start).as_millis() >= ANIMATION_DURATION.as_millis() { + self.previously_active = None; + } + } + match self.amount { WorkspaceAmount::Dynamic => self.ensure_last_empty(state, outputs), WorkspaceAmount::Static(len) => { self.ensure_static(len as usize, state, toplevel_info, outputs) } } + self.workspaces[self.active].refresh(); } @@ -371,12 +381,20 @@ impl WorkspaceMode { } } - pub fn active(&self, output: &Output) -> &Workspace { + pub fn active(&self, output: &Output) -> (Option<(&Workspace, Instant)>, &Workspace) { match self { - WorkspaceMode::Global(set) => &set.workspaces[set.active], + WorkspaceMode::Global(set) => ( + set.previously_active + .map(|(idx, start)| (&set.workspaces[idx], start)), + &set.workspaces[set.active], + ), WorkspaceMode::OutputBound(sets, _) => { let set = sets.get(output).unwrap(); - &set.workspaces[set.active] + ( + set.previously_active + .map(|(idx, start)| (&set.workspaces[idx], start)), + &set.workspaces[set.active], + ) } } } @@ -391,12 +409,12 @@ impl WorkspaceMode { } } - pub fn active_num(&self, output: &Output) -> usize { + pub fn active_num(&self, output: &Output) -> (Option, usize) { match self { - WorkspaceMode::Global(set) => set.active, + WorkspaceMode::Global(set) => (set.previously_active.map(|(idx, _)| idx), set.active), WorkspaceMode::OutputBound(sets, _) => { let set = sets.get(output).unwrap(); - set.active + (set.previously_active.map(|(idx, _)| idx), set.active) } } } @@ -1050,7 +1068,12 @@ impl Shell { } pub fn animations_going(&self) -> bool { - matches!(self.overview_mode, OverviewMode::None) + (match &self.workspaces { + WorkspaceMode::Global(set) => set.previously_active.is_some(), + WorkspaceMode::OutputBound(sets, _) => { + sets.values().any(|set| set.previously_active.is_some()) + } + }) || matches!(self.overview_mode, OverviewMode::None) || self .workspaces .spaces() @@ -1233,7 +1256,7 @@ impl Shell { follow: bool, ) -> Option> { let (to_output, to_idx) = to; - let to_idx = to_idx.unwrap_or(state.common.shell.workspaces.active_num(to_output)); + let to_idx = to_idx.unwrap_or(state.common.shell.workspaces.active_num(to_output).1); if state .common .shell @@ -1245,7 +1268,7 @@ impl Shell { } if from_output == to_output - && to_idx == state.common.shell.workspaces.active_num(from_output) + && to_idx == state.common.shell.workspaces.active_num(from_output).1 { return None; } diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index e03abacc..832f7b6f 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -13,7 +13,7 @@ use crate::{ state::State, utils::prelude::*, wayland::{ - handlers::screencopy::{DropableSession, WORKSPACE_OVERVIEW_NAMESPACE}, + handlers::screencopy::DropableSession, protocols::{ screencopy::{BufferParams, Session as ScreencopySession}, toplevel_info::ToplevelInfoState, @@ -38,12 +38,12 @@ use smithay::{ ImportAll, ImportMem, Renderer, }, }, - desktop::{layer_map_for_output, space::SpaceElement, LayerSurface}, + desktop::{layer_map_for_output, space::SpaceElement}, input::{pointer::GrabStartData as PointerGrabStartData, Seat}, output::Output, reexports::wayland_server::protocol::wl_surface::WlSurface, utils::{Buffer as BufferCoords, IsAlive, Logical, Physical, Point, Rectangle, Scale, Size}, - wayland::{seat::WaylandFocus, shell::wlr_layer::Layer}, + wayland::seat::WaylandFocus, xwayland::X11Surface, }; use std::{collections::HashMap, time::Instant}; @@ -470,7 +470,6 @@ impl Workspace { draw_focus_indicator: Option<&Seat>, overview: OverviewMode, indicator_thickness: u8, - exclude_workspace_overview: bool, ) -> Result>, OutputNotMapped> where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, @@ -488,32 +487,6 @@ impl Workspace { let layer_map = layer_map_for_output(output); if let Some(fullscreen) = self.fullscreen.get(output) { - // overlay layer surfaces - render_elements.extend( - layer_map - .layers() - .rev() - .filter(|s| { - s.layer() == Layer::Overlay - && !(exclude_workspace_overview - && s.namespace() == WORKSPACE_OVERVIEW_NAMESPACE) - }) - .filter_map(|surface| { - layer_map - .layer_geometry(surface) - .map(|geo| (geo.loc, surface)) - }) - .flat_map(|(loc, surface)| { - AsRenderElements::::render_elements::>( - surface, - renderer, - loc.to_physical_precise_round(output_scale), - Scale::from(output_scale), - 1.0, - ) - }), - ); - render_elements.extend( override_redirect_windows .iter() @@ -557,39 +530,6 @@ impl Workspace { // - keyboard window swapping // - resizing in tiling - // overlay and top layer surfaces - let lower = { - let (lower, upper): (Vec<&LayerSurface>, Vec<&LayerSurface>) = layer_map - .layers() - .rev() - .filter(|s| { - !(exclude_workspace_overview - && s.namespace() == "cosmic-workspace-overview") - }) - .partition(|s| matches!(s.layer(), Layer::Background | Layer::Bottom)); - - render_elements.extend( - upper - .into_iter() - .filter_map(|surface| { - layer_map - .layer_geometry(surface) - .map(|geo| (geo.loc, surface)) - }) - .flat_map(|(loc, surface)| { - AsRenderElements::::render_elements::>( - surface, - renderer, - loc.to_physical_precise_round(output_scale), - Scale::from(output_scale), - 1.0, - ) - }), - ); - - lower - }; - // OR windows above all render_elements.extend( override_redirect_windows @@ -609,6 +549,7 @@ impl Workspace { let focused = draw_focus_indicator.and_then(|seat| self.focus_stack.get(seat).last().cloned()); + // floating surfaces let alpha = match &overview { OverviewMode::Started(_, started) => { @@ -716,28 +657,6 @@ impl Workspace { .into(), ) } - - // bottom and background layer surfaces - { - render_elements.extend( - lower - .into_iter() - .filter_map(|surface| { - layer_map - .layer_geometry(surface) - .map(|geo| (geo.loc, surface)) - }) - .flat_map(|(loc, surface)| { - AsRenderElements::::render_elements::>( - surface, - renderer, - loc.to_physical_precise_round(output_scale), - Scale::from(output_scale), - 1.0, - ) - }), - ); - } } Ok(render_elements) diff --git a/src/wayland/handlers/screencopy.rs b/src/wayland/handlers/screencopy.rs index 467d9d9e..cc920b65 100644 --- a/src/wayland/handlers/screencopy.rs +++ b/src/wayland/handlers/screencopy.rs @@ -372,7 +372,13 @@ impl ScreencopyHandler for State { render_output_to_buffer(self, &session, params, &output) } SessionType::Workspace(output, handle) => { - render_workspace_to_buffer(self, &session, params, &output, &handle) + render_workspace_to_buffer( + self, + &session, + params, + &output, + (handle, 0), /* TODO: hack, we should have the index */ + ) } SessionType::Window(window) => { render_window_to_buffer(self, &session, params, &window) @@ -764,7 +770,7 @@ pub fn render_workspace_to_buffer( session: &Session, params: BufferParams, output: &Output, - handle: &WorkspaceHandle, + handle: (WorkspaceHandle, usize), ) -> Result { let mode = output .current_mode() @@ -783,7 +789,7 @@ pub fn render_workspace_to_buffer( common: &mut Common, session: &Session, output: &Output, - handle: &WorkspaceHandle, + handle: (WorkspaceHandle, usize), ) -> Result<(Option>>, RenderElementStates), DTError> where R: Renderer @@ -814,6 +820,7 @@ pub fn render_workspace_to_buffer( age, common, &output, + None, handle, cursor_mode, None, @@ -837,6 +844,7 @@ pub fn render_workspace_to_buffer( age, common, &output, + None, handle, cursor_mode, None, @@ -1304,7 +1312,7 @@ pub fn schedule_offscreen_workspace_session( &session, params.clone(), &output, - &handle, + (handle, 0), /* TODO: Hack, we should know the idx */ ) { Ok(false) => { // rendering yielded no new damage, buffer still pending