Compare commits

..

8 Commits

Author SHA1 Message Date
Aleksander 618bc8281c wayvr: space gravity: hide in openvr 2026-06-03 09:36:28 +02:00
Aleksander e1c7e5744f space gravity: floor level 2026-06-03 09:36:28 +02:00
Aleksander 592a6354db Space gravity UI improvements 2026-06-03 09:36:27 +02:00
Aleksander 6a867b4157 space reset & gravity conflict bugfix, add ground friction slider 2026-06-03 09:35:12 +02:00
Aleksander 6b423a7494 dash-frontend: dedicated "Space drag" settings tab, deduplicate overlay shift code in xr&vr, account for gravity shift for static overlays 2026-06-03 09:35:12 +02:00
Aleksander 103442e2be wayvr: Space gravity (wip) 2026-06-03 09:35:12 +02:00
art0007i 9806027e19
add watch toggle setting (#526)
* add watch toggle setting

* previous commit broke monado workaround, this fixes it

* use active_state to toggle watch

* use the other monado workaround

* fix whitespace

* cargo fmt
2026-06-03 16:22:09 +09:00
Hiina 066f033a91
fix: preserve screencopy transforms for rotated outputs (#530) 2026-06-03 15:55:50 +09:00
15 changed files with 102 additions and 46 deletions

View File

@ -102,6 +102,7 @@
"SCREEN_RENDER_DOWN_HELP": "Helps with aliasing on high-res screens", "SCREEN_RENDER_DOWN_HELP": "Helps with aliasing on high-res screens",
"SCROLL_SPEED": "Scroll speed", "SCROLL_SPEED": "Scroll speed",
"SELECT_VARIANT": "Select variant", "SELECT_VARIANT": "Select variant",
"ENABLE_WATCH": "Enable watch",
"SETS_ON_WATCH": "Sets on watch", "SETS_ON_WATCH": "Sets on watch",
"SKYBOX": "Skybox", "SKYBOX": "Skybox",
"SKYMAP_ALREADY_DOWNLOADED": "This skymap is already downloaded. Select desired action.", "SKYMAP_ALREADY_DOWNLOADED": "This skymap is already downloaded. Select desired action.",

View File

@ -44,6 +44,7 @@
"USE_SKYBOX_HELP": "Wyświetlaj niebo, jeśli nie ma aplikacji sceny lub passthrough", "USE_SKYBOX_HELP": "Wyświetlaj niebo, jeśli nie ma aplikacji sceny lub passthrough",
"USE_PASSTHROUGH_HELP": "Pozwól na passthrough, jeśli runtime XR to obsługuje", "USE_PASSTHROUGH_HELP": "Pozwól na passthrough, jeśli runtime XR to obsługuje",
"SCREEN_RENDER_DOWN_HELP": "Pomaga redukować aliasing na ekranach o wysokiej rozdzielczości", "SCREEN_RENDER_DOWN_HELP": "Pomaga redukować aliasing na ekranach o wysokiej rozdzielczości",
"ENABLE_WATCH": "Włącz zegarek",
"SETS_ON_WATCH": "Lista zestawów na zegarku", "SETS_ON_WATCH": "Lista zestawów na zegarku",
"TROUBLESHOOTING": "Rozwiązywanie problemów", "TROUBLESHOOTING": "Rozwiązywanie problemów",
"CLEAR_SAVED_STATE": "Wyczyść zapisany stan", "CLEAR_SAVED_STATE": "Wyczyść zapisany stan",

View File

@ -297,6 +297,7 @@ enum SettingType {
PointerLerpFactor, PointerLerpFactor,
ScreenRenderDown, ScreenRenderDown,
ScrollSpeed, ScrollSpeed,
EnableWatch,
SetsOnWatch, SetsOnWatch,
SpaceDragMultiplier, SpaceDragMultiplier,
SpaceDragUnlocked, SpaceDragUnlocked,
@ -336,6 +337,7 @@ impl SettingType {
Self::BlockPosesOnKbdInteraction => &mut config.block_poses_on_kbd_interaction, Self::BlockPosesOnKbdInteraction => &mut config.block_poses_on_kbd_interaction,
Self::Clock12h => &mut config.clock_12h, Self::Clock12h => &mut config.clock_12h,
Self::DoubleCursorFix => &mut config.double_cursor_fix, Self::DoubleCursorFix => &mut config.double_cursor_fix,
Self::EnableWatch => &mut config.enable_watch,
Self::FocusFollowsMouseMode => &mut config.focus_follows_mouse_mode, Self::FocusFollowsMouseMode => &mut config.focus_follows_mouse_mode,
Self::HideGrabHelp => &mut config.hide_grab_help, Self::HideGrabHelp => &mut config.hide_grab_help,
Self::HideUsername => &mut config.hide_username, Self::HideUsername => &mut config.hide_username,
@ -469,6 +471,7 @@ impl SettingType {
Self::PointerLerpFactor => Ok("APP_SETTINGS.POINTER_LERP_FACTOR"), Self::PointerLerpFactor => Ok("APP_SETTINGS.POINTER_LERP_FACTOR"),
Self::ScreenRenderDown => Ok("APP_SETTINGS.SCREEN_RENDER_DOWN"), Self::ScreenRenderDown => Ok("APP_SETTINGS.SCREEN_RENDER_DOWN"),
Self::ScrollSpeed => Ok("APP_SETTINGS.SCROLL_SPEED"), Self::ScrollSpeed => Ok("APP_SETTINGS.SCROLL_SPEED"),
Self::EnableWatch => Ok("APP_SETTINGS.ENABLE_WATCH"),
Self::SetsOnWatch => Ok("APP_SETTINGS.SETS_ON_WATCH"), Self::SetsOnWatch => Ok("APP_SETTINGS.SETS_ON_WATCH"),
Self::SpaceDragMultiplier => Ok("APP_SETTINGS.SPACE_DRAG_MULTIPLIER"), Self::SpaceDragMultiplier => Ok("APP_SETTINGS.SPACE_DRAG_MULTIPLIER"),
Self::SpaceDragUnlocked => Ok("APP_SETTINGS.SPACE_DRAG_UNLOCKED"), Self::SpaceDragUnlocked => Ok("APP_SETTINGS.SPACE_DRAG_UNLOCKED"),

View File

@ -22,6 +22,7 @@ impl State {
options_slider_f32(par.mp, c, SettingType::UiAnimationSpeed, 0.5, 5.0, 0.1)?; // min, max, step options_slider_f32(par.mp, c, SettingType::UiAnimationSpeed, 0.5, 5.0, 0.1)?; // min, max, step
options_slider_f32(par.mp, c, SettingType::UiGradientIntensity, 0.0, 1.0, 0.05)?; // min, max, step options_slider_f32(par.mp, c, SettingType::UiGradientIntensity, 0.0, 1.0, 0.05)?; // min, max, step
options_slider_f32(par.mp, c, SettingType::UiRoundMultiplier, 0.1, 5.0, 0.1)?; options_slider_f32(par.mp, c, SettingType::UiRoundMultiplier, 0.1, 5.0, 0.1)?;
options_checkbox(par.mp, c, SettingType::EnableWatch)?;
options_checkbox(par.mp, c, SettingType::SetsOnWatch)?; options_checkbox(par.mp, c, SettingType::SetsOnWatch)?;
options_checkbox(par.mp, c, SettingType::Clock12h)?; options_checkbox(par.mp, c, SettingType::Clock12h)?;
Ok(State {}) Ok(State {})

View File

@ -350,9 +350,12 @@ pub fn openxr_run(
app.hid_provider.inner.commit(); app.hid_provider.inner.commit();
let watch = overlays.mut_by_id(watch_id).unwrap(); // want panic let watch = overlays.mut_by_id(watch_id).unwrap(); // want panic
if watch.config.active_state.is_none() {
watch.config.activate(&mut app);
}
let watch_state = watch.config.active_state.as_mut().unwrap(); let watch_state = watch.config.active_state.as_mut().unwrap();
let watch_transform = watch_state.transform; let watch_transform = watch_state.transform;
if watch_state.alpha < 0.05 { if watch_state.alpha < 0.05 || !app.session.config.enable_watch {
//FIXME: Temporary workaround for Monado bug //FIXME: Temporary workaround for Monado bug
watch_state.transform = Affine3A::from_scale(Vec3 { watch_state.transform = Affine3A::from_scale(Vec3 {
x: 0.001, x: 0.001,
@ -514,7 +517,13 @@ pub fn openxr_run(
//FIXME: Temporary workaround for Monado bug //FIXME: Temporary workaround for Monado bug
let watch = overlays.mut_by_id(watch_id).unwrap(); // want panic let watch = overlays.mut_by_id(watch_id).unwrap(); // want panic
watch.config.active_state.as_mut().unwrap().transform = watch_transform;
if let Some(state) = watch.config.active_state.as_mut() {
state.transform = watch_transform
}
if !app.session.config.enable_watch {
watch.config.deactivate();
}
} // main_loop } // main_loop
if let (Some(blocker), Some(monado)) = (blocker, app.monado_state.as_mut()) { if let (Some(blocker), Some(monado)) = (blocker, app.monado_state.as_mut()) {

View File

@ -145,6 +145,7 @@ pub struct AutoSettings {
pub keyboard_sound_enabled: bool, pub keyboard_sound_enabled: bool,
pub upright_screen_fix: bool, pub upright_screen_fix: bool,
pub double_cursor_fix: bool, pub double_cursor_fix: bool,
pub enable_watch: bool,
pub sets_on_watch: bool, pub sets_on_watch: bool,
pub hide_grab_help: bool, pub hide_grab_help: bool,
pub xr_click_sensitivity: f32, pub xr_click_sensitivity: f32,
@ -206,6 +207,7 @@ pub fn save_settings(config: &GeneralConfig) -> anyhow::Result<()> {
keyboard_sound_enabled: config.keyboard_sound_enabled, keyboard_sound_enabled: config.keyboard_sound_enabled,
upright_screen_fix: config.upright_screen_fix, upright_screen_fix: config.upright_screen_fix,
double_cursor_fix: config.double_cursor_fix, double_cursor_fix: config.double_cursor_fix,
enable_watch: config.enable_watch,
sets_on_watch: config.sets_on_watch, sets_on_watch: config.sets_on_watch,
hide_grab_help: config.hide_grab_help, hide_grab_help: config.hide_grab_help,
xr_click_sensitivity: config.xr_click_sensitivity, xr_click_sensitivity: config.xr_click_sensitivity,

View File

@ -238,16 +238,20 @@ impl OverlayBackend for ScreenBackend {
} }
if let Some(pipeline) = self.pipeline.as_mut() { if let Some(pipeline) = self.pipeline.as_mut() {
if self.meta.is_some_and(|old| old.extent != meta.extent) { if self.meta.is_some_and(|old| old.extent != meta.extent)
pipeline.set_extent( || frame.format.transform != pipeline.transform()
{
pipeline.set_layout(
app, app,
[meta.extent[0] as _, meta.extent[1] as _], [meta.extent[0] as _, meta.extent[1] as _],
[0., 0.], [0., 0.],
frame.format.transform,
)?; )?;
self.interaction_transform = Some(ui_transform(meta.extent)); self.interaction_transform = Some(ui_transform(meta.extent));
} }
} else { } else {
let pipeline = ScreenPipeline::new(&meta, app, stereo, [0., 0.])?; let pipeline =
ScreenPipeline::new(&meta, app, stereo, [0., 0.], frame.format.transform)?;
self.pipeline = Some(pipeline); self.pipeline = Some(pipeline);
self.interaction_transform = Some(ui_transform(meta.extent)); self.interaction_transform = Some(ui_transform(meta.extent));
} }

View File

@ -1,10 +1,9 @@
use std::{ use std::{
f32::consts::PI,
os::fd::AsRawFd, os::fd::AsRawFd,
sync::{Arc, OnceLock}, sync::{Arc, OnceLock},
}; };
use glam::{Affine3A, Vec3}; use glam::Affine3A;
use smallvec::{SmallVec, smallvec}; use smallvec::{SmallVec, smallvec};
use vulkano::{ use vulkano::{
buffer::{BufferUsage, Subbuffer}, buffer::{BufferUsage, Subbuffer},
@ -55,6 +54,7 @@ pub struct ScreenPipeline {
pipeline: Arc<WGfxPipeline<Vert2Uv>>, pipeline: Arc<WGfxPipeline<Vert2Uv>>,
extentf: [f32; 2], extentf: [f32; 2],
offsetf: [f32; 2], offsetf: [f32; 2],
transform: wlx_frame::Transform,
stereo: StereoMode, stereo: StereoMode,
} }
@ -64,6 +64,7 @@ impl ScreenPipeline {
app: &mut AppState, app: &mut AppState,
stereo: StereoMode, stereo: StereoMode,
offsetf: [f32; 2], offsetf: [f32; 2],
transform: wlx_frame::Transform,
) -> anyhow::Result<Self> { ) -> anyhow::Result<Self> {
let extentf = [meta.extent[0] as f32, meta.extent[1] as f32]; let extentf = [meta.extent[0] as f32, meta.extent[1] as f32];
@ -81,6 +82,7 @@ impl ScreenPipeline {
pipeline, pipeline,
extentf, extentf,
offsetf, offsetf,
transform,
stereo, stereo,
}; };
me.ensure_stereo(stereo); me.ensure_stereo(stereo);
@ -96,6 +98,10 @@ impl ScreenPipeline {
self.pass.clear(); // ensure_depth will repopulate self.pass.clear(); // ensure_depth will repopulate
} }
pub const fn transform(&self) -> wlx_frame::Transform {
self.transform
}
fn ensure_depth(&mut self, app: &mut AppState, depth: usize) -> anyhow::Result<()> { fn ensure_depth(&mut self, app: &mut AppState, depth: usize) -> anyhow::Result<()> {
while self.pass.len() < depth { while self.pass.len() < depth {
self.pass.push(Self::create_pass( self.pass.push(Self::create_pass(
@ -111,20 +117,22 @@ impl ScreenPipeline {
} }
for (eye, current) in self.pass.iter_mut().enumerate() { for (eye, current) in self.pass.iter_mut().enumerate() {
let verts = stereo_mode_to_verts(self.stereo, eye); let verts = stereo_mode_to_verts(self.stereo, eye, self.transform);
current.buf_vert.write()?.copy_from_slice(&verts); current.buf_vert.write()?.copy_from_slice(&verts);
} }
Ok(()) Ok(())
} }
pub fn set_extent( pub fn set_layout(
&mut self, &mut self,
app: &mut AppState, app: &mut AppState,
extentf: [f32; 2], extentf: [f32; 2],
offsetf: [f32; 2], offsetf: [f32; 2],
transform: wlx_frame::Transform,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
self.extentf = extentf; self.extentf = extentf;
self.offsetf = offsetf; self.offsetf = offsetf;
self.transform = transform;
self.pass.clear(); self.pass.clear();
self.mouse = Self::create_mouse_pass(app, self.pipeline.clone(), extentf, offsetf)?; self.mouse = Self::create_mouse_pass(app, self.pipeline.clone(), extentf, offsetf)?;
@ -241,13 +249,31 @@ impl ScreenPipeline {
} }
} }
fn stereo_mode_to_verts(stereo: StereoMode, array_index: usize) -> [Vert2Uv; 4] { fn transform_uv(uv: [f32; 2], transform: wlx_frame::Transform) -> [f32; 2] {
let [u, v] = uv;
match transform {
wlx_frame::Transform::Normal | wlx_frame::Transform::Undefined => [u, v],
wlx_frame::Transform::Rotated90 => [v, 1.0 - u],
wlx_frame::Transform::Rotated180 => [1.0 - u, 1.0 - v],
wlx_frame::Transform::Rotated270 => [1.0 - v, u],
wlx_frame::Transform::Flipped => [1.0 - u, v],
wlx_frame::Transform::Flipped90 => [v, u],
wlx_frame::Transform::Flipped180 => [u, 1.0 - v],
wlx_frame::Transform::Flipped270 => [1.0 - v, 1.0 - u],
}
}
fn stereo_mode_to_verts(
stereo: StereoMode,
array_index: usize,
transform: wlx_frame::Transform,
) -> [Vert2Uv; 4] {
let eye = match stereo { let eye = match stereo {
StereoMode::RightLeft | StereoMode::BottomTop => (1 - array_index) as f32, StereoMode::RightLeft | StereoMode::BottomTop => (1 - array_index) as f32,
_ => array_index as f32, _ => array_index as f32,
}; };
match stereo { let mut verts = match stereo {
StereoMode::None => [ StereoMode::None => [
Vert2Uv { Vert2Uv {
in_pos: [0., 0.], in_pos: [0., 0.],
@ -302,7 +328,13 @@ fn stereo_mode_to_verts(stereo: StereoMode, array_index: usize) -> [Vert2Uv; 4]
in_uv: [1., 0.5 + eye * 0.5], in_uv: [1., 0.5 + eye * 0.5],
}, },
], ],
};
for vert in &mut verts {
vert.in_uv = transform_uv(vert.in_uv, transform);
} }
verts
} }
static DMA_ALLOCATOR: OnceLock<Arc<dyn MemoryAllocator>> = OnceLock::new(); static DMA_ALLOCATOR: OnceLock<Arc<dyn MemoryAllocator>> = OnceLock::new();
@ -460,7 +492,7 @@ impl WlxCaptureOut {
FrameMeta { FrameMeta {
clear: WGfxClearMode::DontCare, clear: WGfxClearMode::DontCare,
extent: extent_from_format(self.format, config), extent: extent_from_format(self.format, config),
transform: affine_from_format(&self.format), transform: Affine3A::IDENTITY,
format: self.image.format(), format: self.image.format(),
stereo, stereo,
} }
@ -585,13 +617,14 @@ pub(super) fn receive_callback(me: &WlxCaptureIn, frame: WlxFrame) -> Option<Wlx
mouse: frame.mouse, mouse: frame.mouse,
}) })
} }
WlxFrame::Implicit => { WlxFrame::Implicit(transform) => {
log::trace!("{}: New Implicit frame", me.name); log::trace!("{}: New Implicit frame", me.name);
let Some((image, format)) = me.dma_exporter.as_ref().unwrap().get_current() else { let Some((image, mut format)) = me.dma_exporter.as_ref().unwrap().get_current() else {
log::error!("{}: Implicit frame is missing!", me.name); log::error!("{}: Implicit frame is missing!", me.name);
return None; return None;
}; };
format.transform = transform;
Some(WlxCaptureOut { Some(WlxCaptureOut {
image, image,
@ -676,6 +709,14 @@ const fn receive_callback_dummy(_: &DummyDrmExporter, frame: WlxFrame) -> Option
} }
fn extent_from_format(fmt: FrameFormat, config: &GeneralConfig) -> [u32; 2] { fn extent_from_format(fmt: FrameFormat, config: &GeneralConfig) -> [u32; 2] {
let (width, height) = match fmt.transform {
wlx_frame::Transform::Rotated90
| wlx_frame::Transform::Rotated270
| wlx_frame::Transform::Flipped90
| wlx_frame::Transform::Flipped270 => (fmt.height, fmt.width),
_ => (fmt.width, fmt.height),
};
// screens above a certain resolution will have severe aliasing // screens above a certain resolution will have severe aliasing
let height_limit = if config.screen_render_down { let height_limit = if config.screen_render_down {
u32::from(config.screen_max_height.min(2560)) u32::from(config.screen_max_height.min(2560))
@ -683,36 +724,11 @@ fn extent_from_format(fmt: FrameFormat, config: &GeneralConfig) -> [u32; 2] {
2560 2560
}; };
let h = fmt.height.min(height_limit); let h = height.min(height_limit);
let w = (fmt.width as f32 / fmt.height as f32 * h as f32) as u32; let w = (width as f32 / height as f32 * h as f32) as u32;
[w, h] [w, h]
} }
fn affine_from_format(format: &FrameFormat) -> Affine3A {
const FLIP_X: Vec3 = Vec3 {
x: -1.0,
y: 1.0,
z: 1.0,
};
match format.transform {
wlx_frame::Transform::Rotated90 => Affine3A::from_rotation_z(-PI / 2.0),
wlx_frame::Transform::Rotated180 => Affine3A::from_rotation_z(PI),
wlx_frame::Transform::Rotated270 => Affine3A::from_rotation_z(PI / 2.0),
wlx_frame::Transform::Flipped => Affine3A::from_scale(FLIP_X),
wlx_frame::Transform::Flipped90 => {
Affine3A::from_scale(FLIP_X) * Affine3A::from_rotation_z(-PI / 2.0)
}
wlx_frame::Transform::Flipped180 => {
Affine3A::from_scale(FLIP_X) * Affine3A::from_rotation_z(PI)
}
wlx_frame::Transform::Flipped270 => {
Affine3A::from_scale(FLIP_X) * Affine3A::from_rotation_z(PI / 2.0)
}
_ => Affine3A::IDENTITY,
}
}
macro_rules! new_wlx_capture { macro_rules! new_wlx_capture {
($capture_queue:expr, $capture:expr) => { ($capture_queue:expr, $capture:expr) => {
if $capture_queue.is_none() { if $capture_queue.is_none() {

View File

@ -154,7 +154,7 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
angle_fade: true, angle_fade: true,
..OverlayWindowState::default() ..OverlayWindowState::default()
}, },
show_on_spawn: true, show_on_spawn: app.session.config.enable_watch,
global: true, global: true,
..OverlayWindowConfig::from_backend(Box::new(panel)) ..OverlayWindowConfig::from_backend(Box::new(panel))
}) })

View File

@ -19,7 +19,7 @@ use wgui::{
parser::Fetchable, parser::Fetchable,
widget::{EventResult, label::WidgetLabel}, widget::{EventResult, label::WidgetLabel},
}; };
use wlx_capture::frame::MouseMeta; use wlx_capture::frame::{MouseMeta, Transform};
use wlx_common::{ use wlx_common::{
overlays::{BackendAttrib, BackendAttribValue, StereoMode}, overlays::{BackendAttrib, BackendAttribValue, StereoMode},
windowing::{OverlayWindowState, Positioning}, windowing::{OverlayWindowState, Positioning},
@ -348,10 +348,11 @@ impl OverlayBackend for WvrWindowBackend {
if let Some(pipeline) = self.pipeline.as_mut() { if let Some(pipeline) = self.pipeline.as_mut() {
if self.inner_extent != inner_extent { if self.inner_extent != inner_extent {
pipeline.set_extent( pipeline.set_layout(
app, app,
[inner_extent[0] as _, inner_extent[1] as _], [inner_extent[0] as _, inner_extent[1] as _],
[BORDER_SIZE as _, (BAR_SIZE + BORDER_SIZE) as _], [BORDER_SIZE as _, (BAR_SIZE + BORDER_SIZE) as _],
Transform::Normal,
)?; )?;
self.apply_extent(app, &meta)?; self.apply_extent(app, &meta)?;
self.inner_extent = inner_extent; self.inner_extent = inner_extent;
@ -362,6 +363,7 @@ impl OverlayBackend for WvrWindowBackend {
app, app,
self.stereo.unwrap_or(StereoMode::None), self.stereo.unwrap_or(StereoMode::None),
[BORDER_SIZE as _, (BAR_SIZE + BORDER_SIZE) as _], [BORDER_SIZE as _, (BAR_SIZE + BORDER_SIZE) as _],
Transform::Normal,
)?; )?;
self.apply_extent(app, &meta)?; self.apply_extent(app, &meta)?;
self.pipeline = Some(pipeline); self.pipeline = Some(pipeline);

View File

@ -85,6 +85,9 @@
# The settings are here for reference only. # The settings are here for reference only.
# Probably don't include them in your config file. # Probably don't include them in your config file.
## The watch will be enabled
#enable_watch: true
## The bottom of the watch will list sets instead of overlays. ## The bottom of the watch will list sets instead of overlays.
#sets_on_watch: false #sets_on_watch: false

View File

@ -288,6 +288,16 @@ where
self.sets_changed(app); self.sets_changed(app);
} }
OverlayTask::SettingsChanged => { OverlayTask::SettingsChanged => {
if let Some(watch) = self.mut_by_id(self.watch_id) {
if app.session.config.enable_watch != watch.config.active_state.is_some() {
if watch.config.active_state.is_some() {
watch.config.deactivate();
} else {
watch.config.activate(app);
}
}
}
for o in self.overlays.values_mut() { for o in self.overlays.values_mut() {
let _ = o let _ = o
.config .config

View File

@ -16,7 +16,7 @@ pub enum WlxFrame {
Dmabuf(DmabufFrame), Dmabuf(DmabufFrame),
MemFd(MemFdFrame), MemFd(MemFdFrame),
MemPtr(MemPtrFrame), MemPtr(MemPtrFrame),
Implicit, Implicit(Transform),
} }
#[derive(Debug, Clone, Copy, Default, PartialEq)] #[derive(Debug, Clone, Copy, Default, PartialEq)]

View File

@ -267,7 +267,8 @@ where
// copy_with_damage seems to not work here // copy_with_damage seems to not work here
proxy.copy(&wl_buffer); proxy.copy(&wl_buffer);
frame_buffer = Some((WlxFrame::Implicit, BufData::Dma { wl_buffer })); frame_buffer =
Some((WlxFrame::Implicit(transform), BufData::Dma { wl_buffer }));
} else if let Some(ScreenCopyEvent::Buffer { } else if let Some(ScreenCopyEvent::Buffer {
shm_format, shm_format,
width, width,

View File

@ -277,6 +277,9 @@ pub struct GeneralConfig {
#[serde(default = "def_false")] #[serde(default = "def_false")]
pub double_cursor_fix: bool, pub double_cursor_fix: bool,
#[serde(default = "def_true")]
pub enable_watch: bool,
#[serde(default = "def_false")] #[serde(default = "def_false")]
pub sets_on_watch: bool, pub sets_on_watch: bool,