mirror of
https://github.com/wayvr-org/wayvr.git
synced 2026-10-28 20:03:14 +01:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f425820d7 | ||
|
|
6a2d8b9f90 | ||
|
|
583a5f7fe0 | ||
|
|
03f2eaf97f | ||
|
|
21331b5c42 | ||
|
|
72a82530ae | ||
|
|
13d9284bb8 | ||
|
|
b0a33a1181 | ||
|
|
4f38d1ad44 | ||
|
|
c6bc880bc3 | ||
|
|
0a2be76150 | ||
|
|
1a87823847 | ||
|
|
e763e15bdc | ||
|
|
6a3b60f298 | ||
|
|
397b3eedd1 | ||
|
|
9d18628354 | ||
|
|
dc985f6da6 | ||
|
|
850601b3b9 | ||
|
|
8a4c7a400f | ||
|
|
d9287f3250 | ||
|
|
378ea120c8 | ||
|
|
f4cc49ca69 | ||
|
|
57ff3aa1dd | ||
|
|
0808383e70 | ||
|
|
c71911998e | ||
|
|
50c3f49989 | ||
|
|
b6a07c43a5 |
No files matched your search
@@ -0,0 +1,51 @@
|
||||
name: Build AppImage
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
|
||||
env:
|
||||
APPDIR: WlxOverlay-S.AppDir
|
||||
CARGO_TERM_COLOR: always
|
||||
SCCACHE_GHA_ENABLED: "true"
|
||||
RUSTC_WRAPPER: "sccache"
|
||||
|
||||
jobs:
|
||||
build_appimage:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup sccache
|
||||
uses: mozilla-actions/sccache-action@v0.0.3
|
||||
- name: Prepare Environment
|
||||
run: |
|
||||
sudo add-apt-repository -syn universe
|
||||
sudo add-apt-repository -syn ppa:pipewire-debian/pipewire-upstream || sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 25088A0359807596
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y fuse cmake pkg-config fontconfig libasound2-dev libxkbcommon-dev libxkbcommon-x11-0 libxkbcommon-x11-dev libopenxr-dev libfontconfig-dev libdbus-1-dev libpipewire-0.3-0 libpipewire-0.3-dev libspa-0.2-dev libx11-6 libxext6 libxrandr2 libx11-dev libxext-dev libxrandr-dev libopenvr-dev libopenvr-api1
|
||||
rustup update
|
||||
|
||||
test -f linuxdeploy-x86_64.AppImage || wget -q "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage"
|
||||
chmod +x linuxdeploy-x86_64.AppImage
|
||||
|
||||
test -d ${APPDIR} && rm -rf ${APPDIR}
|
||||
mkdir -p ${APPDIR}/usr/bin
|
||||
|
||||
- name: Cargo Build
|
||||
run: |
|
||||
cargo build --release
|
||||
mv target/release/wlx-overlay-s ${APPDIR}/usr/bin
|
||||
chmod +x ${APPDIR}/usr/bin/wlx-overlay-s
|
||||
|
||||
- name: Package AppImage
|
||||
run: |
|
||||
export VERSION=$GITHUB_REF_NAME
|
||||
./linuxdeploy-x86_64.AppImage -dwlx-overlay-s.desktop -iwlx-overlay-s.png --appdir=${APPDIR} --output appimage --exclude-library '*libpipewire*'
|
||||
mv WlxOverlay-S-$VERSION-x86_64.AppImage WlxOverlay-S-x86_64.AppImage
|
||||
|
||||
- name: Upload AppImage
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: WlxOverlay-S-${{ github.ref_name }}-x86_64.AppImage
|
||||
path: ./WlxOverlay-S-x86_64.AppImage
|
||||
@@ -2,7 +2,7 @@ name: Check Full
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
#branches: [ "main" ]
|
||||
branches: [ "!main" ]
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
Generated
+4
-2
@@ -2682,6 +2682,7 @@ version = "0.10.0"
|
||||
source = "git+https://github.com/galister/openxrs?rev=af4a55d#af4a55df60125491c80c61464c824219c6019b76"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mint",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4555,7 +4556,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "wlx-capture"
|
||||
version = "0.3.12"
|
||||
source = "git+https://github.com/galister/wlx-capture?tag=v0.3.12#14d2b8a13dad62849973fe90bed7be262aa07143"
|
||||
source = "git+https://github.com/galister/wlx-capture?tag=v0.3.13#c375a7c1d4b57741655a052ebe8af9fb4774f92d"
|
||||
dependencies = [
|
||||
"ashpd",
|
||||
"drm-fourcc",
|
||||
@@ -4573,7 +4574,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wlx-overlay-s"
|
||||
version = "0.4.3"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ash",
|
||||
@@ -4599,6 +4600,7 @@ dependencies = [
|
||||
"libmonado-rs",
|
||||
"log",
|
||||
"log-panics",
|
||||
"mint",
|
||||
"once_cell",
|
||||
"openxr",
|
||||
"ovr_overlay",
|
||||
|
||||
+7
-2
@@ -4,7 +4,7 @@ debug = true
|
||||
|
||||
[package]
|
||||
name = "wlx-overlay-s"
|
||||
version = "0.4.3"
|
||||
version = "0.5.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
@@ -34,6 +34,7 @@ log = "0.4.21"
|
||||
once_cell = "1.19.0"
|
||||
openxr = { git = "https://github.com/galister/openxrs", rev = "af4a55d", features = [
|
||||
"linked",
|
||||
"mint",
|
||||
], optional = true }
|
||||
ovr_overlay = { features = [
|
||||
"ovr_input",
|
||||
@@ -54,7 +55,7 @@ sysinfo = { version = "0.31.2" }
|
||||
thiserror = "1.0.61"
|
||||
vulkano = { git = "https://github.com/vulkano-rs/vulkano", rev = "b9f3e89" }
|
||||
vulkano-shaders = { git = "https://github.com/vulkano-rs/vulkano", rev = "b9f3e89" }
|
||||
wlx-capture = { git = "https://github.com/galister/wlx-capture", tag = "v0.3.12", default-features = false }
|
||||
wlx-capture = { git = "https://github.com/galister/wlx-capture", tag = "v0.3.13", default-features = false }
|
||||
libmonado-rs = { git = "https://github.com/technobaboo/libmonado-rs", rev = "a495f6d", optional = true }
|
||||
winit = { version = "0.30.0", optional = true }
|
||||
xdg = "2.5.2"
|
||||
@@ -67,6 +68,10 @@ xcb = { version = "1.4.0", optional = true, features = [
|
||||
image_dds = { version = "0.6.0", default-features = false, features = [
|
||||
"ddsfile",
|
||||
] }
|
||||
mint = "0.5.9"
|
||||
|
||||
[build-dependencies]
|
||||
regex = { version = "*" }
|
||||
|
||||
[features]
|
||||
default = ["openvr", "openxr", "osc", "x11", "wayland"]
|
||||
|
||||
@@ -128,12 +128,8 @@ This has been idenfitied as an issue with SteamVR versions 2.5.5 and above (late
|
||||
|
||||
This is a rare issue that can make your desktop not react to click or keys due to a modifier being stuck somewhere. Restarting the overlay fixes this.
|
||||
|
||||
## Scroll wheel doesn't work
|
||||
|
||||
This seems to be an issue specific to Electron apps (Discord, Element, Slack, Spotify) on Wayland. Scrolling will work when using these in your web browser.
|
||||
|
||||
## X11 limitations
|
||||
|
||||
- X11 capture can generally seem slow. This is because zero-copy GPU capture is not supported on the general X11 desktop. Consider trying Wayland or Picom.
|
||||
- DPI scaling is not supported and may cause the mouse to not follow the laser properly.
|
||||
- Upright screens are not supported and can cause the mouse to act weirdly.
|
||||
- Screen changes (connecting / disconnecting a display, resolution changes, etc) are not handled at runtime. Restart the overlay for these to take effect.
|
||||
@@ -0,0 +1,40 @@
|
||||
use regex::Regex;
|
||||
use std::process::Command;
|
||||
|
||||
fn main() {
|
||||
let mut wlx_build = get_version().unwrap_or(format!("{}-unknown", env!("CARGO_PKG_VERSION")));
|
||||
|
||||
match std::env::var("GITHUB_JOB").as_deref() {
|
||||
Ok("make_release") => {
|
||||
wlx_build = format!("{} (Release)", &wlx_build);
|
||||
}
|
||||
Ok("build_appimage") => {
|
||||
wlx_build = format!("{} (AppImage)", &wlx_build);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
println!("cargo:rustc-env=WLX_BUILD={}", &wlx_build);
|
||||
}
|
||||
|
||||
fn get_version() -> Result<String, Box<dyn std::error::Error>> {
|
||||
let re = Regex::new(r"v([0-9.]+)-([0-9]+)-g([a-f0-9]+)").unwrap(); // safe
|
||||
let output = Command::new("git")
|
||||
.args(["describe", "--tags", "--abbrev=7", "--dirty"])
|
||||
.output()?;
|
||||
|
||||
let mut output_str = String::from_utf8(output.stdout)?;
|
||||
|
||||
if output_str.is_empty() {
|
||||
let output = Command::new("git")
|
||||
.args(["describe", "--tags", "--abbrev=7", "--dirty", "--always"])
|
||||
.output()?;
|
||||
|
||||
output_str = format!(
|
||||
"{}-{}",
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
String::from_utf8(output.stdout)?
|
||||
);
|
||||
}
|
||||
|
||||
Ok(re.replace_all(&output_str, "${1}.r${2}.${3}").into_owned())
|
||||
}
|
||||
+11
-5
@@ -73,6 +73,9 @@ impl InputState {
|
||||
if hand.now.space_rotate != hand.before.space_rotate {
|
||||
log::debug!("Hand {}: space_rotate {}", hand.idx, hand.now.space_rotate);
|
||||
}
|
||||
if hand.now.space_reset != hand.before.space_reset {
|
||||
log::debug!("Hand {}: space_reset {}", hand.idx, hand.now.space_reset);
|
||||
}
|
||||
if hand.now.click_modifier_right != hand.before.click_modifier_right {
|
||||
log::debug!(
|
||||
"Hand {}: click_modifier_right {}",
|
||||
@@ -192,6 +195,7 @@ pub struct PointerState {
|
||||
pub show_hide: bool,
|
||||
pub space_drag: bool,
|
||||
pub space_rotate: bool,
|
||||
pub space_reset: bool,
|
||||
pub click_modifier_right: bool,
|
||||
pub click_modifier_middle: bool,
|
||||
pub move_mouse: bool,
|
||||
@@ -366,7 +370,10 @@ where
|
||||
);
|
||||
}
|
||||
|
||||
// Pass mouse motion events only if not scrolling
|
||||
// (allows scrolling on all Chromium-based applications)
|
||||
let haptics = hovered.backend.on_hover(app, &hit);
|
||||
|
||||
pointer = &mut app.input_state.pointers[idx];
|
||||
|
||||
if pointer.now.scroll.abs() > 0.1 {
|
||||
@@ -376,12 +383,9 @@ where
|
||||
.grabbed
|
||||
.is_some_and(|x| x.grabbed_id == hit.overlay)
|
||||
{
|
||||
let is_portrait = hovered.view().is_some_and(|v| {
|
||||
let extent = v.image().extent();
|
||||
extent[0] >= extent[1]
|
||||
});
|
||||
let can_curve = hovered.extent().is_some_and(|e| e[0] >= e[1]);
|
||||
|
||||
if is_portrait {
|
||||
if can_curve {
|
||||
let cur = hovered.state.curvature.unwrap_or(0.0);
|
||||
let new = (cur - scroll * 0.01).min(0.35);
|
||||
if new <= f32::EPSILON {
|
||||
@@ -389,6 +393,8 @@ where
|
||||
} else {
|
||||
hovered.state.curvature = Some(new);
|
||||
}
|
||||
} else {
|
||||
hovered.state.curvature = None;
|
||||
}
|
||||
} else {
|
||||
hovered.backend.on_scroll(app, &hit, scroll);
|
||||
|
||||
@@ -132,21 +132,14 @@ pub(super) unsafe fn create_overlay_session(
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn hmd_pose_from_views(views: &[xr::View]) -> (Affine3A, f32) {
|
||||
let ipd;
|
||||
let pos = {
|
||||
let pos0: Vec3 = unsafe { std::mem::transmute(views[0].pose.position) };
|
||||
let pos1: Vec3 = unsafe { std::mem::transmute(views[1].pose.position) };
|
||||
ipd = (pos0.distance(pos1) * 1000.0).round() * 0.1;
|
||||
(pos0 + pos1) * 0.5
|
||||
};
|
||||
let rot = {
|
||||
let rot0: Quat = unsafe { std::mem::transmute(views[0].pose.orientation) };
|
||||
let rot1: Quat = unsafe { std::mem::transmute(views[1].pose.orientation) };
|
||||
rot0.lerp(rot1, 0.5)
|
||||
};
|
||||
type Vec3M = mint::Vector3<f32>;
|
||||
type QuatM = mint::Quaternion<f32>;
|
||||
|
||||
(Affine3A::from_rotation_translation(rot, pos), ipd)
|
||||
pub(super) fn ipd_from_views(views: &[xr::View]) -> f32 {
|
||||
let p0: Vec3 = Vec3M::from(views[0].pose.position).into();
|
||||
let p1: Vec3 = Vec3M::from(views[1].pose.position).into();
|
||||
|
||||
(p0.distance(p1) * 1000.0).round() * 0.1
|
||||
}
|
||||
|
||||
pub(super) fn transform_to_norm_quat(transform: &Affine3A) -> Quat {
|
||||
@@ -181,3 +174,9 @@ pub(super) fn transform_to_posef(transform: &Affine3A) -> xr::Posef {
|
||||
let rotation = transform_to_norm_quat(transform);
|
||||
translation_rotation_to_posef(translation, rotation)
|
||||
}
|
||||
|
||||
pub(super) fn posef_to_transform(pose: &xr::Posef) -> Affine3A {
|
||||
let rotation = QuatM::from(pose.orientation).into();
|
||||
let translation = Vec3M::from(pose.position).into();
|
||||
Affine3A::from_rotation_translation(rotation, translation)
|
||||
}
|
||||
@@ -15,7 +15,7 @@ use crate::{
|
||||
state::{AppSession, AppState},
|
||||
};
|
||||
|
||||
use super::XrState;
|
||||
use super::{helpers::posef_to_transform, XrState};
|
||||
|
||||
type XrSession = xr::Session<xr::Vulkan>;
|
||||
|
||||
@@ -156,6 +156,7 @@ pub(super) struct OpenXrHandSource {
|
||||
action_show_hide: CustomClickAction,
|
||||
action_space_drag: CustomClickAction,
|
||||
action_space_rotate: CustomClickAction,
|
||||
action_space_reset: CustomClickAction,
|
||||
action_modifier_right: CustomClickAction,
|
||||
action_modifier_middle: CustomClickAction,
|
||||
action_move_mouse: CustomClickAction,
|
||||
@@ -204,6 +205,22 @@ impl OpenXrInputSource {
|
||||
pub fn update(&mut self, xr: &XrState, state: &mut AppState) -> anyhow::Result<()> {
|
||||
xr.session.sync_actions(&[(&self.action_set).into()])?;
|
||||
|
||||
let loc = xr.view.locate(&xr.stage, xr.predicted_display_time)?;
|
||||
let hmd = posef_to_transform(&loc.pose);
|
||||
if loc
|
||||
.location_flags
|
||||
.contains(xr::SpaceLocationFlags::ORIENTATION_VALID)
|
||||
{
|
||||
state.input_state.hmd.matrix3 = hmd.matrix3;
|
||||
}
|
||||
|
||||
if loc
|
||||
.location_flags
|
||||
.contains(xr::SpaceLocationFlags::POSITION_VALID)
|
||||
{
|
||||
state.input_state.hmd.translation = hmd.translation;
|
||||
}
|
||||
|
||||
for i in 0..2 {
|
||||
self.hands[i].update(&mut state.input_state.pointers[i], xr, &state.session)?;
|
||||
}
|
||||
@@ -299,13 +316,21 @@ impl OpenXrHand {
|
||||
.location_flags
|
||||
.contains(xr::SpaceLocationFlags::ORIENTATION_VALID)
|
||||
{
|
||||
let (quat, pos) = unsafe {
|
||||
let (cur_quat, cur_pos) = (Quat::from_affine3(&pointer.pose), pointer.pose.translation);
|
||||
|
||||
let (new_quat, new_pos) = unsafe {
|
||||
(
|
||||
transmute::<Quaternionf, Quat>(location.pose.orientation),
|
||||
transmute::<Vector3f, Vec3>(location.pose.position),
|
||||
)
|
||||
};
|
||||
pointer.pose = Affine3A::from_rotation_translation(quat, pos);
|
||||
let lerp_factor =
|
||||
(1.0 / (xr.fps / 100.0) * session.config.pointer_lerp_factor).clamp(0.1, 1.0);
|
||||
pointer.raw_pose = Affine3A::from_rotation_translation(new_quat, new_pos);
|
||||
pointer.pose = Affine3A::from_rotation_translation(
|
||||
cur_quat.lerp(new_quat, lerp_factor),
|
||||
cur_pos.lerp(new_pos.into(), lerp_factor).into(),
|
||||
);
|
||||
}
|
||||
|
||||
pointer.now.click = self
|
||||
@@ -361,6 +386,11 @@ impl OpenXrHand {
|
||||
.action_space_rotate
|
||||
.state(pointer.before.space_rotate, xr, session)?;
|
||||
|
||||
pointer.now.space_reset =
|
||||
self.source
|
||||
.action_space_reset
|
||||
.state(pointer.before.space_reset, xr, session)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -394,6 +424,7 @@ impl OpenXrHandSource {
|
||||
action_show_hide: CustomClickAction::new(action_set, "show_hide", side)?,
|
||||
action_space_drag: CustomClickAction::new(action_set, "space_drag", side)?,
|
||||
action_space_rotate: CustomClickAction::new(action_set, "space_rotate", side)?,
|
||||
action_space_reset: CustomClickAction::new(action_set, "space_reset", side)?,
|
||||
action_modifier_right: CustomClickAction::new(
|
||||
action_set,
|
||||
"click_modifier_right",
|
||||
@@ -563,6 +594,14 @@ fn suggest_bindings(instance: &xr::Instance, hands: &[&OpenXrHandSource; 2]) ->
|
||||
instance
|
||||
);
|
||||
|
||||
add_custom!(
|
||||
profile.space_reset,
|
||||
&hands[0].action_space_reset,
|
||||
&hands[1].action_space_reset,
|
||||
bindings,
|
||||
instance
|
||||
);
|
||||
|
||||
add_custom!(
|
||||
profile.click_modifier_right,
|
||||
&hands[0].action_modifier_right,
|
||||
@@ -618,6 +657,7 @@ struct OpenXrActionConfProfile {
|
||||
show_hide: Option<OpenXrActionConfAction>,
|
||||
space_drag: Option<OpenXrActionConfAction>,
|
||||
space_rotate: Option<OpenXrActionConfAction>,
|
||||
space_reset: Option<OpenXrActionConfAction>,
|
||||
click_modifier_right: Option<OpenXrActionConfAction>,
|
||||
click_modifier_middle: Option<OpenXrActionConfAction>,
|
||||
move_mouse: Option<OpenXrActionConfAction>,
|
||||
|
||||
@@ -48,7 +48,9 @@ struct XrState {
|
||||
system: xr::SystemId,
|
||||
session: xr::Session<xr::Vulkan>,
|
||||
predicted_display_time: xr::Time,
|
||||
fps: f32,
|
||||
stage: Arc<xr::Space>,
|
||||
view: Arc<xr::Space>,
|
||||
stage_offset: Affine3A,
|
||||
}
|
||||
|
||||
@@ -123,12 +125,16 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
||||
let stage =
|
||||
session.create_reference_space(xr::ReferenceSpaceType::STAGE, xr::Posef::IDENTITY)?;
|
||||
|
||||
let view = session.create_reference_space(xr::ReferenceSpaceType::VIEW, xr::Posef::IDENTITY)?;
|
||||
|
||||
let mut xr_state = XrState {
|
||||
instance: xr_instance,
|
||||
system,
|
||||
session,
|
||||
predicted_display_time: xr::Time::from_nanos(0),
|
||||
fps: 30.0,
|
||||
stage: Arc::new(stage),
|
||||
view: Arc::new(view),
|
||||
stage_offset: Affine3A::IDENTITY,
|
||||
};
|
||||
|
||||
@@ -149,6 +155,8 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
||||
let mut next_device_update = Instant::now();
|
||||
let mut due_tasks = VecDeque::with_capacity(4);
|
||||
|
||||
let mut fps_counter: VecDeque<Instant> = VecDeque::new();
|
||||
|
||||
let mut main_session_visible = false;
|
||||
|
||||
'main_loop: loop {
|
||||
@@ -227,6 +235,24 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
||||
frame_stream.begin()?;
|
||||
|
||||
xr_state.predicted_display_time = xr_frame_state.predicted_display_time;
|
||||
xr_state.fps = {
|
||||
fps_counter.push_back(Instant::now());
|
||||
|
||||
while let Some(time) = fps_counter.front() {
|
||||
if time.elapsed().as_secs_f32() > 1. {
|
||||
fps_counter.pop_front();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let total_elapsed = fps_counter
|
||||
.front()
|
||||
.map(|time| time.elapsed().as_secs_f32())
|
||||
.unwrap_or(0f32);
|
||||
|
||||
fps_counter.len() as f32 / total_elapsed
|
||||
};
|
||||
|
||||
if !xr_frame_state.should_render {
|
||||
frame_stream.end(
|
||||
@@ -274,8 +300,7 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
||||
&xr_state.stage,
|
||||
)?;
|
||||
|
||||
let (hmd, ipd) = helpers::hmd_pose_from_views(&views);
|
||||
app_state.input_state.hmd = hmd;
|
||||
let ipd = helpers::ipd_from_views(&views);
|
||||
if (app_state.input_state.ipd - ipd).abs() > 0.01 {
|
||||
log::info!("IPD changed: {} -> {}", app_state.input_state.ipd, ipd);
|
||||
app_state.input_state.ipd = ipd;
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
// -- space_rotate --
|
||||
// rotate your stage (playspace rotate, WIP)
|
||||
//
|
||||
// -- space_reset --
|
||||
// reset your stage (reset the offset from playspace drag)
|
||||
//
|
||||
// -- click_modifier_right --
|
||||
// while this is held, your pointer will turn ORANGE and your mouse clicks will be RIGHT clicks
|
||||
//
|
||||
@@ -132,6 +135,10 @@
|
||||
left: "/user/hand/left/input/trackpad/force",
|
||||
// right trackpad is alt_click
|
||||
},
|
||||
space_reset: {
|
||||
double_click: true,
|
||||
left: "/user/hand/left/input/trackpad/force",
|
||||
},
|
||||
click_modifier_right: {
|
||||
left: "/user/hand/left/input/b/touch",
|
||||
right: "/user/hand/right/input/b/touch"
|
||||
|
||||
@@ -55,6 +55,16 @@ impl PlayspaceMover {
|
||||
state: &AppState,
|
||||
monado: &mut Monado,
|
||||
) {
|
||||
for pointer in state.input_state.pointers.iter() {
|
||||
if pointer.now.space_reset {
|
||||
if !pointer.before.space_reset {
|
||||
log::info!("Space reset");
|
||||
self.reset_offset(monado);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(mut data) = self.rotate.take() {
|
||||
let pointer = &state.input_state.pointers[data.hand];
|
||||
if !pointer.now.space_rotate {
|
||||
@@ -64,32 +74,25 @@ impl PlayspaceMover {
|
||||
}
|
||||
|
||||
let new_hand =
|
||||
Quat::from_affine3(&(data.pose * state.input_state.pointers[data.hand].pose));
|
||||
Quat::from_affine3(&(data.pose * state.input_state.pointers[data.hand].raw_pose));
|
||||
|
||||
let dq = new_hand * data.hand_pose.conjugate();
|
||||
let rel_y = f32::atan2(
|
||||
2.0 * (dq.y * dq.w + dq.x * dq.z),
|
||||
(2.0 * (dq.w * dq.w + dq.x * dq.x)) - 1.0,
|
||||
);
|
||||
let mut space_transform = if state.session.config.space_rotate_unlocked {
|
||||
Affine3A::from_quat(dq)
|
||||
} else {
|
||||
let rel_y = f32::atan2(
|
||||
2.0 * (dq.y * dq.w + dq.x * dq.z),
|
||||
(2.0 * (dq.w * dq.w + dq.x * dq.x)) - 1.0,
|
||||
);
|
||||
|
||||
//let mut space_transform = Affine3A::from_rotation_translation(dq, Vec3::ZERO);
|
||||
let mut space_transform = Affine3A::from_rotation_y(rel_y);
|
||||
Affine3A::from_rotation_y(rel_y)
|
||||
};
|
||||
let offset = (space_transform.transform_vector3a(state.input_state.hmd.translation)
|
||||
- state.input_state.hmd.translation)
|
||||
* -1.0;
|
||||
let mut overlay_transform = Affine3A::from_rotation_y(-rel_y);
|
||||
|
||||
overlay_transform.translation = offset;
|
||||
space_transform.translation = offset;
|
||||
|
||||
overlays.iter_mut().for_each(|overlay| {
|
||||
if overlay.state.grabbable {
|
||||
overlay.state.dirty = true;
|
||||
overlay.state.transform.translation =
|
||||
overlay_transform.transform_point3a(overlay.state.transform.translation);
|
||||
}
|
||||
});
|
||||
|
||||
data.pose *= space_transform;
|
||||
data.hand_pose = new_hand;
|
||||
|
||||
@@ -98,7 +101,7 @@ impl PlayspaceMover {
|
||||
} else {
|
||||
for (i, pointer) in state.input_state.pointers.iter().enumerate() {
|
||||
if pointer.now.space_rotate {
|
||||
let hand_pose = Quat::from_affine3(&self.last_transform);
|
||||
let hand_pose = Quat::from_affine3(&(self.last_transform * pointer.raw_pose));
|
||||
self.rotate = Some(MoverData {
|
||||
pose: self.last_transform,
|
||||
hand: i,
|
||||
@@ -121,7 +124,7 @@ impl PlayspaceMover {
|
||||
|
||||
let new_hand = data
|
||||
.pose
|
||||
.transform_point3a(state.input_state.pointers[data.hand].pose.translation);
|
||||
.transform_point3a(state.input_state.pointers[data.hand].raw_pose.translation);
|
||||
let relative_pos =
|
||||
(new_hand - data.hand_pose) * state.session.config.space_drag_multiplier;
|
||||
|
||||
@@ -149,7 +152,7 @@ impl PlayspaceMover {
|
||||
if pointer.now.space_drag {
|
||||
let hand_pos = self
|
||||
.last_transform
|
||||
.transform_point3a(pointer.pose.translation);
|
||||
.transform_point3a(pointer.raw_pose.translation);
|
||||
self.drag = Some(MoverData {
|
||||
pose: self.last_transform,
|
||||
hand: i,
|
||||
@@ -186,8 +189,8 @@ impl PlayspaceMover {
|
||||
self.rotate = None;
|
||||
}
|
||||
|
||||
let y1 = input.pointers[0].pose.translation.y;
|
||||
let y2 = input.pointers[1].pose.translation.y;
|
||||
let y1 = input.pointers[0].raw_pose.translation.y;
|
||||
let y2 = input.pointers[1].raw_pose.translation.y;
|
||||
let delta = y1.min(y2) - 0.03;
|
||||
self.last_transform.translation.y += delta;
|
||||
self.apply_offset(self.last_transform, monado);
|
||||
|
||||
@@ -121,6 +121,10 @@ pub fn def_point7() -> f32 {
|
||||
0.7
|
||||
}
|
||||
|
||||
pub fn def_point3() -> f32 {
|
||||
0.3
|
||||
}
|
||||
|
||||
fn def_osc_port() -> u16 {
|
||||
9000
|
||||
}
|
||||
@@ -260,6 +264,15 @@ pub struct GeneralConfig {
|
||||
|
||||
#[serde(default = "def_max_height")]
|
||||
pub screen_max_height: u16,
|
||||
|
||||
#[serde(default = "def_false")]
|
||||
pub screen_render_down: bool,
|
||||
|
||||
#[serde(default = "def_point3")]
|
||||
pub pointer_lerp_factor: f32,
|
||||
|
||||
#[serde(default = "def_false")]
|
||||
pub space_rotate_unlocked: bool,
|
||||
}
|
||||
|
||||
impl GeneralConfig {
|
||||
|
||||
@@ -1165,7 +1165,6 @@ pub struct WlxPipelineDynamic {}
|
||||
pub struct WlxPipelineLegacy {
|
||||
pub render_pass: Arc<RenderPass>,
|
||||
pub framebuffer: Arc<Framebuffer>,
|
||||
pub view: Arc<ImageView>,
|
||||
}
|
||||
|
||||
pub struct WlxPipeline<D> {
|
||||
@@ -1399,7 +1398,6 @@ impl WlxPipeline<WlxPipelineLegacy> {
|
||||
data: WlxPipelineLegacy {
|
||||
render_pass,
|
||||
framebuffer,
|
||||
view: render_target,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
+22
-16
@@ -120,21 +120,24 @@ impl<D, S> Control<D, S> {
|
||||
self.rect.h,
|
||||
)?;
|
||||
|
||||
let clamped_radius = self.corner_radius.min(self.rect.w / 2.0).min(self.rect.h / 2.0);
|
||||
let clamped_radius = self
|
||||
.corner_radius
|
||||
.min(self.rect.w / 2.0)
|
||||
.min(self.rect.h / 2.0);
|
||||
|
||||
let skew_radius = vec![
|
||||
clamped_radius / self.rect.w,
|
||||
clamped_radius / self.rect.h];
|
||||
let skew_radius = [clamped_radius / self.rect.w, clamped_radius / self.rect.h];
|
||||
|
||||
let set0 = canvas
|
||||
.pipeline_bg_color
|
||||
.uniform_buffer(0, vec![
|
||||
let set0 = canvas.pipeline_bg_color.uniform_buffer(
|
||||
0,
|
||||
vec![
|
||||
self.bg_color.x,
|
||||
self.bg_color.y,
|
||||
self.bg_color.z,
|
||||
self.bg_color.w,
|
||||
skew_radius[0],
|
||||
skew_radius[1]])?;
|
||||
skew_radius[1],
|
||||
],
|
||||
)?;
|
||||
|
||||
canvas.pipeline_bg_color.create_pass(
|
||||
[canvas.width as _, canvas.height as _],
|
||||
@@ -163,21 +166,24 @@ impl<D, S> Control<D, S> {
|
||||
self.rect.h,
|
||||
)?;
|
||||
|
||||
let clamped_radius = self.corner_radius.min(self.rect.w / 2.0).min(self.rect.h / 2.0);
|
||||
let clamped_radius = self
|
||||
.corner_radius
|
||||
.min(self.rect.w / 2.0)
|
||||
.min(self.rect.h / 2.0);
|
||||
|
||||
let skew_radius = vec![
|
||||
clamped_radius / self.rect.w,
|
||||
clamped_radius / self.rect.h];
|
||||
let skew_radius = [clamped_radius / self.rect.w, clamped_radius / self.rect.h];
|
||||
|
||||
let set0 = canvas
|
||||
.pipeline_bg_color
|
||||
.uniform_buffer(0, vec![
|
||||
let set0 = canvas.pipeline_bg_color.uniform_buffer(
|
||||
0,
|
||||
vec![
|
||||
color.x,
|
||||
color.y,
|
||||
color.z,
|
||||
color.w,
|
||||
skew_radius[0],
|
||||
skew_radius[1]])?;
|
||||
skew_radius[1],
|
||||
],
|
||||
)?;
|
||||
|
||||
let pass = canvas.pipeline_bg_color.create_pass(
|
||||
[canvas.width as _, canvas.height as _],
|
||||
|
||||
@@ -47,6 +47,7 @@ pub enum HighlightTest {
|
||||
AutoRealign,
|
||||
NotificationSounds,
|
||||
Notifications,
|
||||
RorateLock,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
@@ -55,6 +56,7 @@ pub enum SystemAction {
|
||||
ToggleAutoRealign,
|
||||
ToggleNotificationSounds,
|
||||
ToggleNotifications,
|
||||
ToggleRotateLock,
|
||||
PlayspaceResetOffset,
|
||||
PlayspaceFixFloor,
|
||||
RecalculateExtent,
|
||||
@@ -298,6 +300,7 @@ fn modular_button_highlight(
|
||||
HighlightTest::AutoRealign => app.session.config.realign_on_showhide,
|
||||
HighlightTest::NotificationSounds => app.session.config.notifications_sound_enabled,
|
||||
HighlightTest::Notifications => app.session.config.notifications_enabled,
|
||||
HighlightTest::RorateLock => !app.session.config.space_rotate_unlocked,
|
||||
};
|
||||
|
||||
if lit {
|
||||
@@ -369,6 +372,19 @@ fn run_system(action: &SystemAction, app: &mut AppState) {
|
||||
)
|
||||
.submit(app);
|
||||
}
|
||||
SystemAction::ToggleRotateLock => {
|
||||
app.session.config.space_rotate_unlocked = !app.session.config.space_rotate_unlocked;
|
||||
Toast::new(
|
||||
ToastTopic::System,
|
||||
format!(
|
||||
"Space rotate axis lock now {}.",
|
||||
ENABLED_DISABLED[!app.session.config.space_rotate_unlocked as usize]
|
||||
)
|
||||
.into(),
|
||||
"".into(),
|
||||
)
|
||||
.submit(app);
|
||||
}
|
||||
SystemAction::PlayspaceResetOffset => {
|
||||
app.tasks
|
||||
.enqueue(TaskType::System(SystemTask::ResetPlayspace));
|
||||
|
||||
+33
-12
@@ -54,12 +54,12 @@ pub struct OverlayListTemplate {
|
||||
pub enum ModularElement {
|
||||
Panel {
|
||||
rect: [f32; 4],
|
||||
corner_radius: f32,
|
||||
corner_radius: Option<f32>,
|
||||
bg_color: Arc<str>,
|
||||
},
|
||||
Label {
|
||||
rect: [f32; 4],
|
||||
corner_radius: f32,
|
||||
corner_radius: Option<f32>,
|
||||
font_size: isize,
|
||||
fg_color: Arc<str>,
|
||||
#[serde(flatten)]
|
||||
@@ -67,7 +67,7 @@ pub enum ModularElement {
|
||||
},
|
||||
CenteredLabel {
|
||||
rect: [f32; 4],
|
||||
corner_radius: f32,
|
||||
corner_radius: Option<f32>,
|
||||
font_size: isize,
|
||||
fg_color: Arc<str>,
|
||||
#[serde(flatten)]
|
||||
@@ -80,7 +80,7 @@ pub enum ModularElement {
|
||||
},
|
||||
Button {
|
||||
rect: [f32; 4],
|
||||
corner_radius: f32,
|
||||
corner_radius: Option<f32>,
|
||||
font_size: isize,
|
||||
fg_color: Arc<str>,
|
||||
bg_color: Arc<str>,
|
||||
@@ -91,7 +91,7 @@ pub enum ModularElement {
|
||||
/// Convenience type to save you from having to create a bunch of labels
|
||||
BatteryList {
|
||||
rect: [f32; 4],
|
||||
corner_radius: f32,
|
||||
corner_radius: Option<f32>,
|
||||
font_size: isize,
|
||||
fg_color: Arc<str>,
|
||||
fg_color_low: Arc<str>,
|
||||
@@ -102,7 +102,7 @@ pub enum ModularElement {
|
||||
},
|
||||
OverlayList {
|
||||
rect: [f32; 4],
|
||||
corner_radius: f32,
|
||||
corner_radius: Option<f32>,
|
||||
font_size: isize,
|
||||
fg_color: Arc<str>,
|
||||
bg_color: Arc<str>,
|
||||
@@ -150,7 +150,7 @@ pub fn modular_canvas(
|
||||
bg_color,
|
||||
} => {
|
||||
canvas.bg_color = color_parse(bg_color).unwrap_or(*FALLBACK_COLOR);
|
||||
canvas.panel(*x, *y, *w, *h, *corner_radius);
|
||||
canvas.panel(*x, *y, *w, *h, corner_radius.unwrap_or_default());
|
||||
}
|
||||
ModularElement::Label {
|
||||
rect: [x, y, w, h],
|
||||
@@ -161,7 +161,14 @@ pub fn modular_canvas(
|
||||
} => {
|
||||
canvas.font_size = *font_size;
|
||||
canvas.fg_color = color_parse(fg_color).unwrap_or(*FALLBACK_COLOR);
|
||||
let label = canvas.label(*x, *y, *w, *h, *corner_radius, empty_str.clone());
|
||||
let label = canvas.label(
|
||||
*x,
|
||||
*y,
|
||||
*w,
|
||||
*h,
|
||||
corner_radius.unwrap_or_default(),
|
||||
empty_str.clone(),
|
||||
);
|
||||
modular_label_init(label, data);
|
||||
}
|
||||
ModularElement::CenteredLabel {
|
||||
@@ -173,7 +180,14 @@ pub fn modular_canvas(
|
||||
} => {
|
||||
canvas.font_size = *font_size;
|
||||
canvas.fg_color = color_parse(fg_color).unwrap_or(*FALLBACK_COLOR);
|
||||
let label = canvas.label_centered(*x, *y, *w, *h, *corner_radius, empty_str.clone());
|
||||
let label = canvas.label_centered(
|
||||
*x,
|
||||
*y,
|
||||
*w,
|
||||
*h,
|
||||
corner_radius.unwrap_or_default(),
|
||||
empty_str.clone(),
|
||||
);
|
||||
modular_label_init(label, data);
|
||||
}
|
||||
ModularElement::Sprite {
|
||||
@@ -207,7 +221,14 @@ pub fn modular_canvas(
|
||||
canvas.bg_color = color_parse(bg_color).unwrap_or(*FALLBACK_COLOR);
|
||||
canvas.fg_color = color_parse(fg_color).unwrap_or(*FALLBACK_COLOR);
|
||||
canvas.font_size = *font_size;
|
||||
let button = canvas.button(*x, *y, *w, *h, *corner_radius, text.clone());
|
||||
let button = canvas.button(
|
||||
*x,
|
||||
*y,
|
||||
*w,
|
||||
*h,
|
||||
corner_radius.unwrap_or_default(),
|
||||
text.clone(),
|
||||
);
|
||||
modular_button_init(button, data);
|
||||
}
|
||||
ModularElement::BatteryList {
|
||||
@@ -240,7 +261,7 @@ pub fn modular_canvas(
|
||||
button_y + 2.,
|
||||
button_w - 4.,
|
||||
button_h - 4.,
|
||||
*corner_radius,
|
||||
corner_radius.unwrap_or_default(),
|
||||
empty_str.clone(),
|
||||
);
|
||||
modular_label_init(
|
||||
@@ -290,7 +311,7 @@ pub fn modular_canvas(
|
||||
button_y + 2.,
|
||||
button_w - 4.,
|
||||
button_h - 4.,
|
||||
*corner_radius,
|
||||
corner_radius.unwrap_or_default(),
|
||||
screen.name.clone(),
|
||||
);
|
||||
|
||||
|
||||
+4
-2
@@ -242,7 +242,7 @@ impl HidProvider for UInputProvider {
|
||||
self.desktop_origin = origin;
|
||||
}
|
||||
fn mouse_move(&mut self, pos: Vec2) {
|
||||
if self.current_action.pos.is_none() {
|
||||
if self.current_action.pos.is_none() && self.current_action.scroll.is_none() {
|
||||
self.current_action.pos = Some(pos);
|
||||
}
|
||||
self.current_action.last_requested_pos = Some(pos);
|
||||
@@ -256,6 +256,9 @@ impl HidProvider for UInputProvider {
|
||||
fn wheel(&mut self, delta: i32) {
|
||||
if self.current_action.scroll.is_none() {
|
||||
self.current_action.scroll = Some(delta);
|
||||
// Pass mouse motion events only if not scrolling
|
||||
// (allows scrolling on all Chromium-based applications)
|
||||
self.current_action.pos = None;
|
||||
}
|
||||
}
|
||||
fn commit(&mut self) {
|
||||
@@ -533,7 +536,6 @@ pub fn get_key_type(key: VirtualKey) -> KeyType {
|
||||
}
|
||||
|
||||
pub struct XkbKeymap {
|
||||
pub context: xkb::Context,
|
||||
pub keymap: xkb::Keymap,
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -120,7 +120,7 @@ impl Dispatch<WlKeyboard, ()> for WlKeymapHandler {
|
||||
|
||||
match maybe_keymap {
|
||||
Ok(Some(keymap)) => {
|
||||
state.keymap = Some(XkbKeymap { context, keymap });
|
||||
state.keymap = Some(XkbKeymap { keymap });
|
||||
}
|
||||
Ok(None) => {
|
||||
log::error!("Could not load keymap: no keymap");
|
||||
|
||||
+1
-1
@@ -31,5 +31,5 @@ pub fn get_keymap_x11() -> anyhow::Result<XkbKeymap> {
|
||||
}
|
||||
let keymap = keymap_new_from_device(&context, &conn, device_id, xkb::KEYMAP_COMPILE_NO_FLAGS);
|
||||
|
||||
Ok(XkbKeymap { context, keymap })
|
||||
Ok(XkbKeymap { keymap })
|
||||
}
|
||||
+1
-1
@@ -79,7 +79,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
log::info!(
|
||||
"Welcome to {} version {}!",
|
||||
env!("CARGO_PKG_NAME"),
|
||||
env!("CARGO_PKG_VERSION")
|
||||
env!("WLX_BUILD"),
|
||||
);
|
||||
log::info!("It is {}.", chrono::Local::now().format("%c"));
|
||||
|
||||
|
||||
@@ -329,7 +329,7 @@ enum KeyButtonData {
|
||||
static LAYOUT: Lazy<Layout> = Lazy::new(Layout::load_from_disk);
|
||||
|
||||
static MACRO_REGEX: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r"^([A-Za-z0-1_-]+)(?: +(UP|DOWN))?$").unwrap()); // want panic
|
||||
Lazy::new(|| Regex::new(r"^([A-Za-z0-9_-]+)(?: +(UP|DOWN))?$").unwrap()); // want panic
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct Layout {
|
||||
|
||||
@@ -4,7 +4,6 @@ use std::{
|
||||
};
|
||||
|
||||
use futures::{Future, FutureExt};
|
||||
use glam::vec3a;
|
||||
use wlx_capture::pipewire::{pipewire_select_screen, PipewireCapture, PipewireSelectScreenResult};
|
||||
|
||||
use crate::{
|
||||
@@ -137,7 +136,6 @@ pub fn new_mirror(
|
||||
show_hide,
|
||||
want_visible: true,
|
||||
spawn_scale: 0.5 * session.config.desktop_view_scale,
|
||||
spawn_point: vec3a(0., 0.5, 0.5),
|
||||
..Default::default()
|
||||
};
|
||||
let backend = Box::new(SplitOverlayBackend {
|
||||
|
||||
+58
-30
@@ -15,7 +15,7 @@ use vulkano::{
|
||||
};
|
||||
use wlx_capture::{
|
||||
frame::{
|
||||
DrmFormat, MouseMeta, WlxFrame, DRM_FORMAT_ABGR2101010, DRM_FORMAT_ABGR8888,
|
||||
DrmFormat, FrameFormat, MouseMeta, WlxFrame, DRM_FORMAT_ABGR2101010, DRM_FORMAT_ABGR8888,
|
||||
DRM_FORMAT_ARGB8888, DRM_FORMAT_XBGR2101010, DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB8888,
|
||||
},
|
||||
WlxCapture,
|
||||
@@ -26,9 +26,12 @@ use {
|
||||
crate::config_io,
|
||||
std::error::Error,
|
||||
std::{ops::Deref, path::PathBuf},
|
||||
wlx_capture::pipewire::{pipewire_select_screen, PipewireCapture, PipewireStream},
|
||||
wlx_capture::pipewire::{pipewire_select_screen, PipewireCapture},
|
||||
};
|
||||
|
||||
#[cfg(all(feature = "x11", feature = "pipewire"))]
|
||||
use wlx_capture::pipewire::PipewireStream;
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
use {
|
||||
crate::config::AStrMapExt,
|
||||
@@ -280,7 +283,7 @@ pub struct ScreenRenderer {
|
||||
capture: Box<dyn WlxCapture>,
|
||||
pipeline: Option<ScreenPipeline>,
|
||||
last_view: Option<Arc<ImageView>>,
|
||||
extent: [u32; 3],
|
||||
extent: Option<[u32; 3]>,
|
||||
}
|
||||
|
||||
impl ScreenRenderer {
|
||||
@@ -291,12 +294,12 @@ impl ScreenRenderer {
|
||||
capture,
|
||||
pipeline: None,
|
||||
last_view: None,
|
||||
extent: [0; 3],
|
||||
extent: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
pub fn new_wlr_dmabuf(output: &WlxOutput, config: &GeneralConfig) -> Option<ScreenRenderer> {
|
||||
pub fn new_wlr_dmabuf(output: &WlxOutput) -> Option<ScreenRenderer> {
|
||||
let client = WlxClient::new()?;
|
||||
let capture = WlrDmabufCapture::new(client, output.id);
|
||||
|
||||
@@ -305,15 +308,12 @@ impl ScreenRenderer {
|
||||
capture: Box::new(capture),
|
||||
pipeline: None,
|
||||
last_view: None,
|
||||
extent: extent_from_res(output.size, config),
|
||||
extent: None,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
pub fn new_wlr_screencopy(
|
||||
output: &WlxOutput,
|
||||
config: &GeneralConfig,
|
||||
) -> Option<ScreenRenderer> {
|
||||
pub fn new_wlr_screencopy(output: &WlxOutput) -> Option<ScreenRenderer> {
|
||||
let client = WlxClient::new()?;
|
||||
let capture = WlrScreencopyCapture::new(client, output.id);
|
||||
|
||||
@@ -322,7 +322,7 @@ impl ScreenRenderer {
|
||||
capture: Box::new(capture),
|
||||
pipeline: None,
|
||||
last_view: None,
|
||||
extent: extent_from_res(output.size, config),
|
||||
extent: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -363,14 +363,14 @@ impl ScreenRenderer {
|
||||
capture: Box::new(capture),
|
||||
pipeline: None,
|
||||
last_view: None,
|
||||
extent: extent_from_res(output.size, &session.config),
|
||||
extent: None,
|
||||
},
|
||||
select_screen_result.restore_token,
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(feature = "x11")]
|
||||
pub fn new_xshm(screen: Arc<XshmScreen>, config: &GeneralConfig) -> ScreenRenderer {
|
||||
pub fn new_xshm(screen: Arc<XshmScreen>) -> ScreenRenderer {
|
||||
let capture = XshmCapture::new(screen.clone());
|
||||
|
||||
ScreenRenderer {
|
||||
@@ -378,7 +378,7 @@ impl ScreenRenderer {
|
||||
capture: Box::new(capture),
|
||||
pipeline: None,
|
||||
last_view: None,
|
||||
extent: extent_from_res((screen.monitor.width(), screen.monitor.height()), config),
|
||||
extent: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -466,11 +466,28 @@ impl OverlayRenderer for ScreenRenderer {
|
||||
log::error!("Invalid frame");
|
||||
continue;
|
||||
}
|
||||
self.extent.get_or_insert_with(|| {
|
||||
extent_from_format(frame.format, &app.session.config)
|
||||
});
|
||||
match app.graphics.dmabuf_texture(frame) {
|
||||
Ok(new) => {
|
||||
let view = ImageView::new_default(new.clone())?;
|
||||
|
||||
self.last_view = Some(view);
|
||||
let pipeline = match self.pipeline {
|
||||
Some(ref mut p) => Some(p),
|
||||
None if app.session.config.screen_render_down => {
|
||||
log::info!("{}: Using render-down pass.", self.name);
|
||||
let pipeline = ScreenPipeline::new(&self.extent.unwrap(), app)?; // safe
|
||||
self.last_view = Some(pipeline.view.clone());
|
||||
self.pipeline = Some(pipeline);
|
||||
self.pipeline.as_mut()
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
if let Some(pipeline) = pipeline {
|
||||
pipeline.render(new.clone(), None, app)?;
|
||||
} else {
|
||||
let view = ImageView::new_default(new.clone())?;
|
||||
self.last_view = Some(view);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!(
|
||||
@@ -491,6 +508,9 @@ impl OverlayRenderer for ScreenRenderer {
|
||||
log::error!("No fd");
|
||||
continue;
|
||||
};
|
||||
self.extent.get_or_insert_with(|| {
|
||||
extent_from_format(frame.format, &app.session.config)
|
||||
});
|
||||
log::debug!("{}: New MemFd frame", self.name);
|
||||
let format = fourcc_to_vk(frame.format.fourcc)?;
|
||||
|
||||
@@ -543,10 +563,13 @@ impl OverlayRenderer for ScreenRenderer {
|
||||
let pipeline = Some(match self.pipeline {
|
||||
Some(ref mut p) => p,
|
||||
_ => {
|
||||
let mut pipeline = ScreenPipeline::new(&self.extent, app)?;
|
||||
log::info!("{}: Using render-down pass.", self.name);
|
||||
let extent = extent_from_format(frame.format, &app.session.config);
|
||||
let mut pipeline = ScreenPipeline::new(&extent, app)?;
|
||||
self.last_view = Some(pipeline.view.clone());
|
||||
pipeline.ensure_mouse_initialized(&mut upload)?;
|
||||
self.pipeline = Some(pipeline);
|
||||
self.extent = Some(extent);
|
||||
self.pipeline.as_mut().unwrap() // safe
|
||||
}
|
||||
});
|
||||
@@ -577,7 +600,7 @@ impl OverlayRenderer for ScreenRenderer {
|
||||
self.last_view.clone()
|
||||
}
|
||||
fn extent(&mut self) -> Option<[u32; 3]> {
|
||||
Some(self.extent)
|
||||
self.extent
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,16 +613,14 @@ pub fn create_screen_renderer_wl(
|
||||
session: &AppSession,
|
||||
) -> Option<ScreenRenderer> {
|
||||
let mut capture: Option<ScreenRenderer> = None;
|
||||
if (&*session.config.capture_method == "auto" || &*session.config.capture_method == "dmabuf")
|
||||
&& has_wlr_dmabuf
|
||||
{
|
||||
if (&*session.config.capture_method == "wlr-dmabuf") && has_wlr_dmabuf {
|
||||
log::info!("{}: Using Wlr DMA-Buf", &output.name);
|
||||
capture = ScreenRenderer::new_wlr_dmabuf(output, &session.config);
|
||||
capture = ScreenRenderer::new_wlr_dmabuf(output);
|
||||
}
|
||||
|
||||
if &*session.config.capture_method == "screencopy" && has_wlr_screencopy {
|
||||
log::info!("{}: Using Wlr Screencopy Wl-SHM", &output.name);
|
||||
capture = ScreenRenderer::new_wlr_screencopy(output, &session.config);
|
||||
capture = ScreenRenderer::new_wlr_screencopy(output);
|
||||
}
|
||||
|
||||
if capture.is_none() {
|
||||
@@ -899,7 +920,11 @@ pub fn create_screens_x11pw(app: &mut AppState) -> anyhow::Result<ScreenCreateDa
|
||||
capture: Box::new(PipewireCapture::new(m.name.clone(), s.node_id)),
|
||||
pipeline: None,
|
||||
last_view: None,
|
||||
extent: extent_from_res(size, &app.session.config),
|
||||
extent: Some(extent_from_res(
|
||||
size.0 as _,
|
||||
size.1 as _,
|
||||
&app.session.config,
|
||||
)),
|
||||
};
|
||||
|
||||
let backend = Box::new(SplitOverlayBackend {
|
||||
@@ -937,7 +962,7 @@ pub fn create_screens_xshm(app: &mut AppState) -> anyhow::Result<ScreenCreateDat
|
||||
|
||||
let size = (s.monitor.width(), s.monitor.height());
|
||||
let pos = (s.monitor.x(), s.monitor.y());
|
||||
let renderer = ScreenRenderer::new_xshm(s.clone(), &app.session.config);
|
||||
let renderer = ScreenRenderer::new_xshm(s.clone());
|
||||
|
||||
log::info!(
|
||||
"{}: Init X11 screen of res {:?} at {:?}",
|
||||
@@ -1003,11 +1028,14 @@ impl From<wl_output::Transform> for Transform {
|
||||
}
|
||||
}
|
||||
|
||||
fn extent_from_res(res: (i32, i32), config: &GeneralConfig) -> [u32; 3] {
|
||||
// screens above a certain resolution will have severe aliasing
|
||||
fn extent_from_format(fmt: FrameFormat, config: &GeneralConfig) -> [u32; 3] {
|
||||
extent_from_res(fmt.width, fmt.height, config)
|
||||
}
|
||||
|
||||
let h = res.1.min(config.screen_max_height as i32) as u32;
|
||||
let w = (res.0 as f32 / res.1 as f32 * h as f32) as u32;
|
||||
fn extent_from_res(width: u32, height: u32, config: &GeneralConfig) -> [u32; 3] {
|
||||
// screens above a certain resolution will have severe aliasing
|
||||
let h = height.min(config.screen_max_height as u32);
|
||||
let w = (width as f32 / height as f32 * h as f32) as u32;
|
||||
[w, h, 1]
|
||||
}
|
||||
|
||||
|
||||
+9
-9
@@ -9,14 +9,14 @@ size: [400, 200]
|
||||
elements:
|
||||
# background panel
|
||||
- type: Panel
|
||||
rect: [0, 0, 400, 200]
|
||||
corner_radius: 4
|
||||
rect: [0, 30, 400, 130]
|
||||
corner_radius: 20
|
||||
bg_color: "#24273a"
|
||||
|
||||
- type: Button
|
||||
rect: [2, 162, 26, 36]
|
||||
corner_radius: 4
|
||||
font_size: 14
|
||||
font_size: 15
|
||||
bg_color: "#c6a0f6"
|
||||
fg_color: "#24273a"
|
||||
text: "C"
|
||||
@@ -32,7 +32,7 @@ elements:
|
||||
- type: Button
|
||||
rect: [32, 162, 60, 36]
|
||||
corner_radius: 4
|
||||
font_size: 14
|
||||
font_size: 15
|
||||
fg_color: "#24273a"
|
||||
bg_color: "#a6da95"
|
||||
text: Kbd
|
||||
@@ -67,7 +67,7 @@ elements:
|
||||
- type: OverlayList
|
||||
rect: [94, 160, 306, 40]
|
||||
corner_radius: 4
|
||||
font_size: 14
|
||||
font_size: 15
|
||||
fg_color: "#cad3f5"
|
||||
bg_color: "#1e2030"
|
||||
layout: Horizontal
|
||||
@@ -147,9 +147,9 @@ elements:
|
||||
|
||||
# batteries
|
||||
- type: BatteryList
|
||||
rect: [0, 0, 400, 30]
|
||||
rect: [0, 5, 400, 30]
|
||||
corner_radius: 4
|
||||
font_size: 14
|
||||
font_size: 16
|
||||
fg_color: "#8bd5ca"
|
||||
fg_color_low: "#B06060"
|
||||
fg_color_charging: "#6080A0"
|
||||
@@ -161,7 +161,7 @@ elements:
|
||||
- type: Button
|
||||
rect: [315, 52, 70, 32]
|
||||
corner_radius: 4
|
||||
font_size: 14
|
||||
font_size: 13
|
||||
fg_color: "#cad3f5"
|
||||
bg_color: "#5b6078"
|
||||
text: "Vol +"
|
||||
@@ -171,7 +171,7 @@ elements:
|
||||
- type: Button
|
||||
rect: [315, 116, 70, 32]
|
||||
corner_radius: 4
|
||||
font_size: 14
|
||||
font_size: 13
|
||||
fg_color: "#cad3f5"
|
||||
bg_color: "#5b6078"
|
||||
text: "Vol -"
|
||||
|
||||
+2
-29
@@ -1,7 +1,7 @@
|
||||
use std::{io::Cursor, path::PathBuf, sync::Arc};
|
||||
use std::{io::Cursor, sync::Arc};
|
||||
|
||||
use anyhow::bail;
|
||||
use glam::{Affine3A, Vec3};
|
||||
use glam::Affine3A;
|
||||
use idmap::IdMap;
|
||||
use rodio::{Decoder, OutputStream, OutputStreamHandle, Source};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -89,15 +89,9 @@ impl AppState {
|
||||
}
|
||||
|
||||
pub struct AppSession {
|
||||
pub config_root_path: PathBuf,
|
||||
pub config: GeneralConfig,
|
||||
|
||||
pub toast_topics: IdMap<ToastTopic, DisplayMethod>,
|
||||
|
||||
pub color_norm: Vec3,
|
||||
pub color_shift: Vec3,
|
||||
pub color_alt: Vec3,
|
||||
pub color_grab: Vec3,
|
||||
}
|
||||
|
||||
impl AppSession {
|
||||
@@ -116,29 +110,8 @@ impl AppSession {
|
||||
});
|
||||
|
||||
AppSession {
|
||||
config_root_path,
|
||||
config,
|
||||
toast_topics,
|
||||
color_norm: Vec3 {
|
||||
x: 0.,
|
||||
y: 1.,
|
||||
z: 1.,
|
||||
},
|
||||
color_shift: Vec3 {
|
||||
x: 1.,
|
||||
y: 1.,
|
||||
z: 0.,
|
||||
},
|
||||
color_alt: Vec3 {
|
||||
x: 1.,
|
||||
y: 0.,
|
||||
z: 1.,
|
||||
},
|
||||
color_grab: Vec3 {
|
||||
x: 1.,
|
||||
y: 0.,
|
||||
z: 0.,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user