mirror of
https://github.com/wayvr-org/wayvr.git
synced 2026-10-28 16:02:47 +01:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85aa0fb1bc | ||
|
|
7f72abc62a | ||
|
|
83ae798215 | ||
|
|
bdbdbea20b | ||
|
|
a077f2dda4 | ||
|
|
8d35b45c2b | ||
|
|
6af5623fa7 | ||
|
|
62ef7a1210 |
No files matched your search
Generated
+23
-20
@@ -225,11 +225,11 @@ checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b"
|
||||
|
||||
[[package]]
|
||||
name = "ash"
|
||||
version = "0.38.0+1.3.281"
|
||||
version = "0.37.3+1.3.251"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f"
|
||||
checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a"
|
||||
dependencies = [
|
||||
"libloading",
|
||||
"libloading 0.7.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -789,7 +789,7 @@ checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
"libloading 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1264,7 +1264,7 @@ version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
|
||||
dependencies = [
|
||||
"libloading",
|
||||
"libloading 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2031,6 +2031,16 @@ dependencies = [
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.5"
|
||||
@@ -2671,7 +2681,7 @@ version = "0.18.0"
|
||||
source = "git+https://github.com/galister/openxrs?rev=af4a55d#af4a55df60125491c80c61464c824219c6019b76"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"libloading",
|
||||
"libloading 0.8.5",
|
||||
"ndk-context",
|
||||
"openxr-sys",
|
||||
]
|
||||
@@ -3472,12 +3482,6 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slabbin"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8305086044614627ed85432d27b87cf9fc047204eaa036a11de6cf0120f273"
|
||||
|
||||
[[package]]
|
||||
name = "slice-of-array"
|
||||
version = "0.3.2"
|
||||
@@ -3908,7 +3912,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vulkano"
|
||||
version = "0.34.0"
|
||||
source = "git+https://github.com/vulkano-rs/vulkano?rev=b9f3e89#b9f3e893005078b5680cd1672037465a2b5f3133"
|
||||
source = "git+https://github.com/vulkano-rs/vulkano?rev=94f50f1#94f50f18bd25971ea123adb8b5782ad65a8f085c"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"ash",
|
||||
@@ -3918,17 +3922,16 @@ dependencies = [
|
||||
"half",
|
||||
"heck 0.4.1",
|
||||
"indexmap 2.3.0",
|
||||
"libloading",
|
||||
"nom",
|
||||
"libloading 0.8.5",
|
||||
"objc",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"raw-window-handle",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"slabbin",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"vk-parse",
|
||||
@@ -3938,7 +3941,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vulkano-macros"
|
||||
version = "0.34.0"
|
||||
source = "git+https://github.com/vulkano-rs/vulkano?rev=b9f3e89#b9f3e893005078b5680cd1672037465a2b5f3133"
|
||||
source = "git+https://github.com/vulkano-rs/vulkano?rev=94f50f1#94f50f18bd25971ea123adb8b5782ad65a8f085c"
|
||||
dependencies = [
|
||||
"proc-macro-crate 2.0.2",
|
||||
"proc-macro2",
|
||||
@@ -3949,7 +3952,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vulkano-shaders"
|
||||
version = "0.34.0"
|
||||
source = "git+https://github.com/vulkano-rs/vulkano?rev=b9f3e89#b9f3e893005078b5680cd1672037465a2b5f3133"
|
||||
source = "git+https://github.com/vulkano-rs/vulkano?rev=94f50f1#94f50f18bd25971ea123adb8b5782ad65a8f085c"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"heck 0.4.1",
|
||||
@@ -4574,7 +4577,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wlx-overlay-s"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ash",
|
||||
@@ -4644,7 +4647,7 @@ dependencies = [
|
||||
"as-raw-xcb-connection",
|
||||
"gethostname",
|
||||
"libc",
|
||||
"libloading",
|
||||
"libloading 0.8.5",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"x11rb-protocol",
|
||||
|
||||
+4
-4
@@ -4,14 +4,14 @@ debug = true
|
||||
|
||||
[package]
|
||||
name = "wlx-overlay-s"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.86"
|
||||
ash = "^0.38.0"
|
||||
ash = "^0.37.2"
|
||||
chrono = "0.4.38"
|
||||
chrono-tz = "0.9.0"
|
||||
clap = { version = "4.5.6", features = ["derive"] }
|
||||
@@ -53,8 +53,8 @@ smallvec = "1.13.2"
|
||||
strum = { version = "0.26.2", features = ["derive"] }
|
||||
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" }
|
||||
vulkano = { git = "https://github.com/vulkano-rs/vulkano", rev = "94f50f1" }
|
||||
vulkano-shaders = { git = "https://github.com/vulkano-rs/vulkano", rev = "94f50f1" }
|
||||
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 }
|
||||
|
||||
@@ -6,21 +6,18 @@ WlxOverlay-S allows you to access your desktop screens while in VR.
|
||||
|
||||
In comparison to similar overlays, WlxOverlay-S aims to run alongside VR games and experiences while having as little performance impact as possible. The UI appearance and rendering techniques are kept as simple and efficient as possible, while still allowing a high degree of customizability.
|
||||
|
||||
This is the coming-together of two of my previous projects:
|
||||
- [WlxOverlay](https://github.com/galister/WlxOverlay) (SteamVR overlay written in C#)
|
||||
- [WlxOverlay-X](https://github.com/galister/wlx-overlay-x) (OpenXR overlay using StereoKit, written in Rust)
|
||||

|
||||
|
||||

|
||||
|
||||
# Join the Linux VR Community
|
||||
## Join the Linux VR Community
|
||||
|
||||
We are available on either:
|
||||
- Discord: https://discord.gg/gHwJ2vwSWV
|
||||
|
||||
- Discord: <https://discord.gg/gHwJ2vwSWV>
|
||||
- Matrix Space: `#linux-vr-adventures:matrix.org`
|
||||
|
||||
Questions/issues specific to WlxOverlay-S will be handled in the `wlxoverlay` chat room.
|
||||
|
||||
# Setup
|
||||
## Setup
|
||||
|
||||
1. Grab the latest AppImage from [Releases](https://github.com/galister/wlx-overlay-s/releases).
|
||||
1. `chmod +x WlxOverlay-S-*.AppImage`
|
||||
@@ -31,18 +28,21 @@ AUR package is [wlx-overlay-s-git](https://aur.archlinux.org/packages/wlx-overla
|
||||
|
||||
You may also want to [build from source](https://github.com/galister/wlx-overlay-s/wiki/Building-from-Source).
|
||||
|
||||
# First Start
|
||||
## First Start
|
||||
|
||||
**If you get a screen share pop-up, check the terminal and select the screens in the order it tells you to.**
|
||||
**When the screen share pop-up appears, check the terminal and select the screens in the order it requests.**
|
||||
|
||||
If you selected the screens in the wrong order:
|
||||
- `rm ~/.config/wlxoverlay/conf.d/pw_tokens.yaml` then restart
|
||||
|
||||
SteamVR users: WlxOverlay-S will register itself for auto-start, so you will not need to start it every time.
|
||||
- `rm ~/.config/wlxoverlay/conf.d/pw_tokens.yaml` then restart
|
||||
|
||||
**SteamVR users**: WlxOverlay-S will register itself for auto-start, so you will not need to start it every time.
|
||||
|
||||
**Envision users**: Set `wlx-overlay-s --openxr --show` as the _Autostart Command_ on your Envision profile! This will give you a home environment with a [customizable background](https://github.com/galister/wlx-overlay-s/wiki/OpenXR-Skybox)!
|
||||
|
||||
**Please continue reading the guide below.**
|
||||
|
||||
# Getting Started
|
||||
## Getting Started
|
||||
|
||||
### Working Set
|
||||
|
||||
@@ -51,6 +51,7 @@ Your working set consists of your currently selected overlays; screens, mirrors,
|
||||
The working set appears in front of you when shown, and can be re-centered by hiding and showing again.
|
||||
|
||||
Show and hide your working set using:
|
||||
|
||||
- Non-vive controller: double-tap B or Y on your left controller.
|
||||
- Vive controller: double-tap the menu button on your left controller (OpenXR, for SteamVR, you might need to bind `showhide` yourself.)
|
||||
|
||||
@@ -58,6 +59,7 @@ Show and hide your working set using:
|
||||
|
||||
Much of the functionality in WlxOverlay-S depends on what color of laser you are using to interact with a UI element. \
|
||||
Using the default settings, there are 3 modes:
|
||||
|
||||
- Regular Mode: Blue laser
|
||||
- Right-click Mode: Orange laser
|
||||
- Middle-click Mode: Purple laser
|
||||
@@ -77,6 +79,7 @@ Check your left wrist for the watch. The watch is your primary tool for controll
|
||||
Hovering a pointer over a screen will move the mouse. If there are more than one pointers hovering a screen, the pointer that was last used to click will take precedence.
|
||||
|
||||
The click depends on the laser color:
|
||||
|
||||
- Blue laser: Left click
|
||||
- Orange laser: Right click
|
||||
- Purple laser: Middle click
|
||||
@@ -92,6 +95,7 @@ The keyboard is fully customizable via the [keyboard.yaml](https://raw.githubuse
|
||||
Download it into your `~/.config/wlxoverlay/` folder and edit it to your liking.
|
||||
|
||||
Typing
|
||||
|
||||
- Use the BLUE laser when typing regularly.
|
||||
- While using ORANGE laser, all keystrokes will have SHIFT applied.
|
||||
- Purple laser has no effect as of now.
|
||||
@@ -104,31 +108,35 @@ Typing
|
||||
|
||||

|
||||
|
||||
To customize bindings on OpenXR, refer to the [OpenXR Bindings wiki page](https://github.com/galister/wlx-overlay-s/wiki/OpenXR-Bindings).
|
||||
|
||||
If your bindings are not supported, please reach out. \
|
||||
We would like to work with you and include additional bindings.
|
||||
|
||||
# Troubleshooting
|
||||
## Troubleshooting
|
||||
|
||||
Check [here](https://github.com/galister/wlx-overlay-s/wiki/Troubleshooting) for tips.
|
||||
|
||||
# Known Issues
|
||||
## Known Issues
|
||||
|
||||
### Mouse is not where it should be
|
||||
|
||||
## Mouse is not where it should be
|
||||
Hyprland users: Hyprland v0.41.0 changed their absolute input implementation to one that does not respect existing absolute input standards. Make your voice heard: [Hyprland#6023](https://github.com/hyprwm/Hyprland/issues/6023)・[Hyprland#6889](https://github.com/hyprwm/Hyprland/issues/6889)
|
||||
|
||||
Niri users: use on Niri 0.1.7 or later.
|
||||
|
||||
Other desktops: You may have selected the screens in the wrong order, see [First Start](#first-start).
|
||||
|
||||
## Space-drag crashes SteamVR
|
||||
### Space-drag crashes SteamVR
|
||||
|
||||
This has been idenfitied as an issue with SteamVR versions 2.5.5 and above (latest tested 2.7.2). One way to avoid the crash is by switching to the `temp-v1.27.5` branch of SteamVR (via beta selection) and selecting [Steam-Play-None](https://github.com/Scrumplex/Steam-Play-None) under the compatibility tab.
|
||||
|
||||
## Modifiers get stuck in weird ways
|
||||
### Modifiers get stuck in weird ways
|
||||
|
||||
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.
|
||||
|
||||
## X11 limitations
|
||||
### 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.
|
||||
|
||||
+11
-9
@@ -313,15 +313,17 @@ where
|
||||
pointer = &mut app.input_state.pointers[idx];
|
||||
pointer.interaction.hovered_id = None;
|
||||
}
|
||||
if let Some(clicked_id) = pointer.interaction.clicked_id.take() {
|
||||
if let Some(clicked) = overlays.mut_by_id(clicked_id) {
|
||||
let hit = PointerHit {
|
||||
pointer: pointer.idx,
|
||||
overlay: clicked_id,
|
||||
mode: pointer.interaction.mode,
|
||||
..Default::default()
|
||||
};
|
||||
clicked.backend.on_pointer(app, &hit, false);
|
||||
if !pointer.now.click && pointer.before.click {
|
||||
if let Some(clicked_id) = pointer.interaction.clicked_id.take() {
|
||||
if let Some(clicked) = overlays.mut_by_id(clicked_id) {
|
||||
let hit = PointerHit {
|
||||
pointer: pointer.idx,
|
||||
overlay: clicked_id,
|
||||
mode: pointer.interaction.mode,
|
||||
..Default::default()
|
||||
};
|
||||
clicked.backend.on_pointer(app, &hit, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0.0, None); // no hit
|
||||
|
||||
@@ -2,6 +2,9 @@ pub mod common;
|
||||
pub mod input;
|
||||
pub mod notifications;
|
||||
|
||||
#[allow(clippy::all)]
|
||||
mod notifications_dbus;
|
||||
|
||||
#[cfg(feature = "openvr")]
|
||||
pub mod openvr;
|
||||
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
use dbus::{blocking::Connection, channel::MatchingReceiver, message::MatchRule};
|
||||
use dbus::{
|
||||
arg::{PropMap, Variant},
|
||||
blocking::Connection,
|
||||
channel::MatchingReceiver,
|
||||
message::MatchRule,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use std::{
|
||||
sync::{
|
||||
@@ -9,6 +14,7 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
backend::notifications_dbus::OrgFreedesktopNotifications,
|
||||
overlays::toast::{Toast, ToastTopic},
|
||||
state::AppState,
|
||||
};
|
||||
@@ -196,6 +202,60 @@ impl Drop for NotificationManager {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DbusNotificationSender {
|
||||
connection: Connection,
|
||||
}
|
||||
|
||||
impl DbusNotificationSender {
|
||||
pub fn new() -> anyhow::Result<Self> {
|
||||
Ok(Self {
|
||||
connection: Connection::new_session()?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn notify_send(
|
||||
&self,
|
||||
summary: &str,
|
||||
body: &str,
|
||||
urgency: u8,
|
||||
timeout: i32,
|
||||
replaces_id: u32,
|
||||
transient: bool,
|
||||
) -> anyhow::Result<u32> {
|
||||
let proxy = self.connection.with_proxy(
|
||||
"org.freedesktop.Notifications",
|
||||
"/org/freedesktop/Notifications",
|
||||
Duration::from_millis(1000),
|
||||
);
|
||||
|
||||
let mut hints = PropMap::new();
|
||||
hints.insert("urgency".to_string(), Variant(Box::new(urgency)));
|
||||
hints.insert("transient".to_string(), Variant(Box::new(transient)));
|
||||
|
||||
Ok(proxy.notify(
|
||||
"WlxOverlay-S",
|
||||
replaces_id,
|
||||
"",
|
||||
summary,
|
||||
body,
|
||||
vec![],
|
||||
hints,
|
||||
timeout,
|
||||
)?)
|
||||
}
|
||||
|
||||
pub fn notify_close(&self, id: u32) -> anyhow::Result<()> {
|
||||
let proxy = self.connection.with_proxy(
|
||||
"org.freedesktop.Notifications",
|
||||
"/org/freedesktop/Notifications",
|
||||
Duration::from_millis(1000),
|
||||
);
|
||||
|
||||
proxy.close_notification(id)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_dbus(msg: &dbus::Message) -> anyhow::Result<Toast> {
|
||||
let mut args = msg.iter_init();
|
||||
let app_name: String = args.read()?;
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
// This code was autogenerated with `dbus-codegen-rust -g -m None -d org.freedesktop.Notifications -p /org/freedesktop/Notifications`, see https://github.com/diwic/dbus-rs
|
||||
use dbus as dbus;
|
||||
#[allow(unused_imports)]
|
||||
use dbus::arg;
|
||||
use dbus::blocking;
|
||||
|
||||
pub trait OrgFreedesktopDBusProperties {
|
||||
fn get<R0: for<'b> arg::Get<'b> + 'static>(&self, interface_name: &str, property_name: &str) -> Result<R0, dbus::Error>;
|
||||
fn get_all(&self, interface_name: &str) -> Result<arg::PropMap, dbus::Error>;
|
||||
fn set<I2: arg::Arg + arg::Append>(&self, interface_name: &str, property_name: &str, value: I2) -> Result<(), dbus::Error>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OrgFreedesktopDBusPropertiesPropertiesChanged {
|
||||
pub interface_name: String,
|
||||
pub changed_properties: arg::PropMap,
|
||||
pub invalidated_properties: Vec<String>,
|
||||
}
|
||||
|
||||
impl arg::AppendAll for OrgFreedesktopDBusPropertiesPropertiesChanged {
|
||||
fn append(&self, i: &mut arg::IterAppend) {
|
||||
arg::RefArg::append(&self.interface_name, i);
|
||||
arg::RefArg::append(&self.changed_properties, i);
|
||||
arg::RefArg::append(&self.invalidated_properties, i);
|
||||
}
|
||||
}
|
||||
|
||||
impl arg::ReadAll for OrgFreedesktopDBusPropertiesPropertiesChanged {
|
||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||
Ok(OrgFreedesktopDBusPropertiesPropertiesChanged {
|
||||
interface_name: i.read()?,
|
||||
changed_properties: i.read()?,
|
||||
invalidated_properties: i.read()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl dbus::message::SignalArgs for OrgFreedesktopDBusPropertiesPropertiesChanged {
|
||||
const NAME: &'static str = "PropertiesChanged";
|
||||
const INTERFACE: &'static str = "org.freedesktop.DBus.Properties";
|
||||
}
|
||||
|
||||
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgFreedesktopDBusProperties for blocking::Proxy<'a, C> {
|
||||
|
||||
fn get<R0: for<'b> arg::Get<'b> + 'static>(&self, interface_name: &str, property_name: &str) -> Result<R0, dbus::Error> {
|
||||
self.method_call("org.freedesktop.DBus.Properties", "Get", (interface_name, property_name, ))
|
||||
.and_then(|r: (arg::Variant<R0>, )| Ok((r.0).0, ))
|
||||
}
|
||||
|
||||
fn get_all(&self, interface_name: &str) -> Result<arg::PropMap, dbus::Error> {
|
||||
self.method_call("org.freedesktop.DBus.Properties", "GetAll", (interface_name, ))
|
||||
.and_then(|r: (arg::PropMap, )| Ok(r.0, ))
|
||||
}
|
||||
|
||||
fn set<I2: arg::Arg + arg::Append>(&self, interface_name: &str, property_name: &str, value: I2) -> Result<(), dbus::Error> {
|
||||
self.method_call("org.freedesktop.DBus.Properties", "Set", (interface_name, property_name, arg::Variant(value), ))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait OrgFreedesktopDBusIntrospectable {
|
||||
fn introspect(&self) -> Result<String, dbus::Error>;
|
||||
}
|
||||
|
||||
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgFreedesktopDBusIntrospectable for blocking::Proxy<'a, C> {
|
||||
|
||||
fn introspect(&self) -> Result<String, dbus::Error> {
|
||||
self.method_call("org.freedesktop.DBus.Introspectable", "Introspect", ())
|
||||
.and_then(|r: (String, )| Ok(r.0, ))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait OrgFreedesktopDBusPeer {
|
||||
fn ping(&self) -> Result<(), dbus::Error>;
|
||||
fn get_machine_id(&self) -> Result<String, dbus::Error>;
|
||||
}
|
||||
|
||||
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgFreedesktopDBusPeer for blocking::Proxy<'a, C> {
|
||||
|
||||
fn ping(&self) -> Result<(), dbus::Error> {
|
||||
self.method_call("org.freedesktop.DBus.Peer", "Ping", ())
|
||||
}
|
||||
|
||||
fn get_machine_id(&self) -> Result<String, dbus::Error> {
|
||||
self.method_call("org.freedesktop.DBus.Peer", "GetMachineId", ())
|
||||
.and_then(|r: (String, )| Ok(r.0, ))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait OrgFreedesktopNotifications {
|
||||
fn set_noti_window_visibility(&self, value: bool) -> Result<(), dbus::Error>;
|
||||
fn toggle_dnd(&self) -> Result<bool, dbus::Error>;
|
||||
fn set_dnd(&self, state: bool) -> Result<(), dbus::Error>;
|
||||
fn get_dnd(&self) -> Result<bool, dbus::Error>;
|
||||
fn manually_close_notification(&self, id: u32, timeout: bool) -> Result<(), dbus::Error>;
|
||||
fn close_all_notifications(&self) -> Result<(), dbus::Error>;
|
||||
fn hide_latest_notification(&self, close: bool) -> Result<(), dbus::Error>;
|
||||
fn get_capabilities(&self) -> Result<Vec<String>, dbus::Error>;
|
||||
fn notify(&self, app_name: &str, replaces_id: u32, app_icon: &str, summary: &str, body: &str, actions: Vec<&str>, hints: arg::PropMap, expire_timeout: i32) -> Result<u32, dbus::Error>;
|
||||
fn close_notification(&self, id: u32) -> Result<(), dbus::Error>;
|
||||
fn get_server_information(&self) -> Result<(String, String, String, String), dbus::Error>;
|
||||
fn dnd(&self) -> Result<bool, dbus::Error>;
|
||||
fn set_dnd_(&self, value: bool) -> Result<(), dbus::Error>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OrgFreedesktopNotificationsOnDndToggle {
|
||||
pub dnd: bool,
|
||||
}
|
||||
|
||||
impl arg::AppendAll for OrgFreedesktopNotificationsOnDndToggle {
|
||||
fn append(&self, i: &mut arg::IterAppend) {
|
||||
arg::RefArg::append(&self.dnd, i);
|
||||
}
|
||||
}
|
||||
|
||||
impl arg::ReadAll for OrgFreedesktopNotificationsOnDndToggle {
|
||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||
Ok(OrgFreedesktopNotificationsOnDndToggle {
|
||||
dnd: i.read()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl dbus::message::SignalArgs for OrgFreedesktopNotificationsOnDndToggle {
|
||||
const NAME: &'static str = "OnDndToggle";
|
||||
const INTERFACE: &'static str = "org.freedesktop.Notifications";
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OrgFreedesktopNotificationsNotificationClosed {
|
||||
pub id: u32,
|
||||
pub reason: u32,
|
||||
}
|
||||
|
||||
impl arg::AppendAll for OrgFreedesktopNotificationsNotificationClosed {
|
||||
fn append(&self, i: &mut arg::IterAppend) {
|
||||
arg::RefArg::append(&self.id, i);
|
||||
arg::RefArg::append(&self.reason, i);
|
||||
}
|
||||
}
|
||||
|
||||
impl arg::ReadAll for OrgFreedesktopNotificationsNotificationClosed {
|
||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||
Ok(OrgFreedesktopNotificationsNotificationClosed {
|
||||
id: i.read()?,
|
||||
reason: i.read()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl dbus::message::SignalArgs for OrgFreedesktopNotificationsNotificationClosed {
|
||||
const NAME: &'static str = "NotificationClosed";
|
||||
const INTERFACE: &'static str = "org.freedesktop.Notifications";
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OrgFreedesktopNotificationsActionInvoked {
|
||||
pub id: u32,
|
||||
pub action_key: String,
|
||||
}
|
||||
|
||||
impl arg::AppendAll for OrgFreedesktopNotificationsActionInvoked {
|
||||
fn append(&self, i: &mut arg::IterAppend) {
|
||||
arg::RefArg::append(&self.id, i);
|
||||
arg::RefArg::append(&self.action_key, i);
|
||||
}
|
||||
}
|
||||
|
||||
impl arg::ReadAll for OrgFreedesktopNotificationsActionInvoked {
|
||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||
Ok(OrgFreedesktopNotificationsActionInvoked {
|
||||
id: i.read()?,
|
||||
action_key: i.read()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl dbus::message::SignalArgs for OrgFreedesktopNotificationsActionInvoked {
|
||||
const NAME: &'static str = "ActionInvoked";
|
||||
const INTERFACE: &'static str = "org.freedesktop.Notifications";
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OrgFreedesktopNotificationsNotificationReplied {
|
||||
pub id: u32,
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
impl arg::AppendAll for OrgFreedesktopNotificationsNotificationReplied {
|
||||
fn append(&self, i: &mut arg::IterAppend) {
|
||||
arg::RefArg::append(&self.id, i);
|
||||
arg::RefArg::append(&self.text, i);
|
||||
}
|
||||
}
|
||||
|
||||
impl arg::ReadAll for OrgFreedesktopNotificationsNotificationReplied {
|
||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||
Ok(OrgFreedesktopNotificationsNotificationReplied {
|
||||
id: i.read()?,
|
||||
text: i.read()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl dbus::message::SignalArgs for OrgFreedesktopNotificationsNotificationReplied {
|
||||
const NAME: &'static str = "NotificationReplied";
|
||||
const INTERFACE: &'static str = "org.freedesktop.Notifications";
|
||||
}
|
||||
|
||||
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgFreedesktopNotifications for blocking::Proxy<'a, C> {
|
||||
|
||||
fn set_noti_window_visibility(&self, value: bool) -> Result<(), dbus::Error> {
|
||||
self.method_call("org.freedesktop.Notifications", "SetNotiWindowVisibility", (value, ))
|
||||
}
|
||||
|
||||
fn toggle_dnd(&self) -> Result<bool, dbus::Error> {
|
||||
self.method_call("org.freedesktop.Notifications", "ToggleDnd", ())
|
||||
.and_then(|r: (bool, )| Ok(r.0, ))
|
||||
}
|
||||
|
||||
fn set_dnd(&self, state: bool) -> Result<(), dbus::Error> {
|
||||
self.method_call("org.freedesktop.Notifications", "SetDnd", (state, ))
|
||||
}
|
||||
|
||||
fn get_dnd(&self) -> Result<bool, dbus::Error> {
|
||||
self.method_call("org.freedesktop.Notifications", "GetDnd", ())
|
||||
.and_then(|r: (bool, )| Ok(r.0, ))
|
||||
}
|
||||
|
||||
fn manually_close_notification(&self, id: u32, timeout: bool) -> Result<(), dbus::Error> {
|
||||
self.method_call("org.freedesktop.Notifications", "ManuallyCloseNotification", (id, timeout, ))
|
||||
}
|
||||
|
||||
fn close_all_notifications(&self) -> Result<(), dbus::Error> {
|
||||
self.method_call("org.freedesktop.Notifications", "CloseAllNotifications", ())
|
||||
}
|
||||
|
||||
fn hide_latest_notification(&self, close: bool) -> Result<(), dbus::Error> {
|
||||
self.method_call("org.freedesktop.Notifications", "HideLatestNotification", (close, ))
|
||||
}
|
||||
|
||||
fn get_capabilities(&self) -> Result<Vec<String>, dbus::Error> {
|
||||
self.method_call("org.freedesktop.Notifications", "GetCapabilities", ())
|
||||
.and_then(|r: (Vec<String>, )| Ok(r.0, ))
|
||||
}
|
||||
|
||||
fn notify(&self, app_name: &str, replaces_id: u32, app_icon: &str, summary: &str, body: &str, actions: Vec<&str>, hints: arg::PropMap, expire_timeout: i32) -> Result<u32, dbus::Error> {
|
||||
self.method_call("org.freedesktop.Notifications", "Notify", (app_name, replaces_id, app_icon, summary, body, actions, hints, expire_timeout, ))
|
||||
.and_then(|r: (u32, )| Ok(r.0, ))
|
||||
}
|
||||
|
||||
fn close_notification(&self, id: u32) -> Result<(), dbus::Error> {
|
||||
self.method_call("org.freedesktop.Notifications", "CloseNotification", (id, ))
|
||||
}
|
||||
|
||||
fn get_server_information(&self) -> Result<(String, String, String, String), dbus::Error> {
|
||||
self.method_call("org.freedesktop.Notifications", "GetServerInformation", ())
|
||||
}
|
||||
|
||||
fn dnd(&self) -> Result<bool, dbus::Error> {
|
||||
<Self as blocking::stdintf::org_freedesktop_dbus::Properties>::get(self, "org.freedesktop.Notifications", "Dnd")
|
||||
}
|
||||
|
||||
fn set_dnd_(&self, value: bool) -> Result<(), dbus::Error> {
|
||||
<Self as blocking::stdintf::org_freedesktop_dbus::Properties>::set(self, "org.freedesktop.Notifications", "Dnd", value)
|
||||
}
|
||||
}
|
||||
+22
-17
@@ -44,8 +44,8 @@ use vulkano::{
|
||||
allocator::StandardDescriptorSetAllocator, DescriptorSet, WriteDescriptorSet,
|
||||
},
|
||||
device::{
|
||||
physical::PhysicalDevice, Device, DeviceCreateInfo, DeviceExtensions, DeviceFeatures,
|
||||
Queue, QueueCreateInfo, QueueFlags,
|
||||
physical::PhysicalDevice, Device, DeviceCreateInfo, DeviceExtensions, Features, Queue,
|
||||
QueueCreateInfo, QueueFlags,
|
||||
},
|
||||
format::Format,
|
||||
image::{
|
||||
@@ -195,7 +195,7 @@ impl WlxGraphics {
|
||||
let target_version = vulkano::Version::V1_3;
|
||||
let library = get_vulkan_library();
|
||||
|
||||
let vk_app_info_raw = vk::ApplicationInfo::default()
|
||||
let vk_app_info_raw = vk::ApplicationInfo::builder()
|
||||
.application_version(0)
|
||||
.engine_version(0)
|
||||
.api_version(vk_target_version);
|
||||
@@ -205,7 +205,7 @@ impl WlxGraphics {
|
||||
.create_vulkan_instance(
|
||||
system,
|
||||
get_instance_proc_addr,
|
||||
&vk::InstanceCreateInfo::default()
|
||||
&vk::InstanceCreateInfo::builder()
|
||||
.application_info(&vk_app_info_raw)
|
||||
.enabled_extension_names(&instance_extensions_raw)
|
||||
as *const _ as *const _,
|
||||
@@ -286,23 +286,25 @@ impl WlxGraphics {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let features = DeviceFeatures {
|
||||
let features = Features {
|
||||
dynamic_rendering: true,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let queue_priorities = [1.0];
|
||||
|
||||
let queue_create_infos = [vk::DeviceQueueCreateInfo::default()
|
||||
let queue_create_infos = [vk::DeviceQueueCreateInfo::builder()
|
||||
.queue_family_index(queue_family_index)
|
||||
.queue_priorities(&queue_priorities)];
|
||||
.queue_priorities(&queue_priorities)
|
||||
.build()];
|
||||
|
||||
let mut device_create_info = vk::DeviceCreateInfo::default()
|
||||
let mut device_create_info = vk::DeviceCreateInfo::builder()
|
||||
.queue_create_infos(&queue_create_infos)
|
||||
.enabled_extension_names(&device_extensions_raw);
|
||||
.enabled_extension_names(&device_extensions_raw)
|
||||
.build();
|
||||
|
||||
let mut dynamic_rendering =
|
||||
PhysicalDeviceDynamicRenderingFeatures::default().dynamic_rendering(true);
|
||||
PhysicalDeviceDynamicRenderingFeatures::builder().dynamic_rendering(true);
|
||||
|
||||
dynamic_rendering.p_next = device_create_info.p_next as _;
|
||||
device_create_info.p_next = (&mut dynamic_rendering) as *const _ as *const c_void;
|
||||
@@ -487,9 +489,9 @@ impl WlxGraphics {
|
||||
physical_device,
|
||||
DeviceCreateInfo {
|
||||
enabled_extensions: my_extensions,
|
||||
enabled_features: DeviceFeatures {
|
||||
enabled_features: Features {
|
||||
dynamic_rendering: true,
|
||||
..DeviceFeatures::empty()
|
||||
..Features::empty()
|
||||
},
|
||||
queue_create_infos: vec![QueueCreateInfo {
|
||||
queue_family_index,
|
||||
@@ -625,9 +627,9 @@ impl WlxGraphics {
|
||||
physical_device,
|
||||
DeviceCreateInfo {
|
||||
enabled_extensions: my_extensions,
|
||||
enabled_features: DeviceFeatures {
|
||||
enabled_features: Features {
|
||||
dynamic_rendering: true,
|
||||
..DeviceFeatures::empty()
|
||||
..Features::empty()
|
||||
},
|
||||
queue_create_infos: vec![QueueCreateInfo {
|
||||
queue_family_index,
|
||||
@@ -1034,7 +1036,10 @@ impl WlxGraphics {
|
||||
(fns.v1_0.queue_submit)(
|
||||
self.queue.handle(),
|
||||
1,
|
||||
[SubmitInfo::default().command_buffers(&[command_buffer.handle()])].as_ptr(),
|
||||
[SubmitInfo::builder()
|
||||
.command_buffers(&[command_buffer.handle()])
|
||||
.build()]
|
||||
.as_ptr(),
|
||||
fence.handle(),
|
||||
)
|
||||
}
|
||||
@@ -1186,7 +1191,7 @@ impl WlxPipeline<WlxPipelineDynamic> {
|
||||
let vep = vert.entry_point("main").unwrap(); // want panic
|
||||
let fep = frag.entry_point("main").unwrap(); // want panic
|
||||
|
||||
let vertex_input_state = Vert2Uv::per_vertex().definition(&vep)?;
|
||||
let vertex_input_state = Vert2Uv::per_vertex().definition(&vep.info().input_interface)?;
|
||||
|
||||
let stages = smallvec![
|
||||
vulkano::pipeline::PipelineShaderStageCreateInfo::new(vep),
|
||||
@@ -1343,7 +1348,7 @@ impl WlxPipeline<WlxPipelineLegacy> {
|
||||
let vep = vert.entry_point("main").unwrap(); // want panic
|
||||
let fep = frag.entry_point("main").unwrap(); // want panic
|
||||
|
||||
let vertex_input_state = Vert2Uv::per_vertex().definition(&vep)?;
|
||||
let vertex_input_state = Vert2Uv::per_vertex().definition(&vep.info().input_interface)?;
|
||||
|
||||
let stages = smallvec![
|
||||
vulkano::pipeline::PipelineShaderStageCreateInfo::new(vep),
|
||||
|
||||
@@ -52,7 +52,15 @@ impl<D, S> CanvasBuilder<D, S> {
|
||||
}
|
||||
|
||||
// Creates a label with fg_color, font_size inherited from the canvas
|
||||
pub fn label(&mut self, x: f32, y: f32, w: f32, h: f32, radius: f32, text: Arc<str>) -> &mut Control<D, S> {
|
||||
pub fn label(
|
||||
&mut self,
|
||||
x: f32,
|
||||
y: f32,
|
||||
w: f32,
|
||||
h: f32,
|
||||
radius: f32,
|
||||
text: Arc<str>,
|
||||
) -> &mut Control<D, S> {
|
||||
let idx = self.canvas.controls.len();
|
||||
self.canvas.controls.push(Control {
|
||||
rect: Rect { x, y, w, h },
|
||||
@@ -116,7 +124,15 @@ impl<D, S> CanvasBuilder<D, S> {
|
||||
}
|
||||
|
||||
// Creates a button with fg_color, bg_color, font_size inherited from the canvas
|
||||
pub fn button(&mut self, x: f32, y: f32, w: f32, h: f32, radius: f32, text: Arc<str>) -> &mut Control<D, S> {
|
||||
pub fn button(
|
||||
&mut self,
|
||||
x: f32,
|
||||
y: f32,
|
||||
w: f32,
|
||||
h: f32,
|
||||
radius: f32,
|
||||
text: Arc<str>,
|
||||
) -> &mut Control<D, S> {
|
||||
let idx = self.canvas.controls.len();
|
||||
|
||||
self.canvas.interactive_set_idx(x, y, w, h, idx);
|
||||
|
||||
@@ -220,6 +220,10 @@ impl<D, S> Canvas<D, S> {
|
||||
cmd_buffer.end_render_pass()?;
|
||||
cmd_buffer.build_and_execute_now()
|
||||
}
|
||||
|
||||
pub fn data_mut(&mut self) -> &mut D {
|
||||
&mut self.canvas.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<D, S> InteractionHandler for Canvas<D, S> {
|
||||
|
||||
@@ -17,6 +17,7 @@ use crate::{
|
||||
task::{ColorChannel, SystemTask, TaskType},
|
||||
},
|
||||
config::{save_layout, save_settings, AStrSetExt},
|
||||
hid::VirtualKey,
|
||||
overlays::{
|
||||
toast::{Toast, ToastTopic},
|
||||
watch::WATCH_NAME,
|
||||
@@ -26,6 +27,12 @@ use crate::{
|
||||
|
||||
use super::{ExecArgs, ModularControl, ModularData};
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
pub enum PressRelease {
|
||||
Release,
|
||||
Press,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone, Copy)]
|
||||
pub enum ViewAngleKind {
|
||||
/// The cosine of the angle at which the watch becomes fully transparent
|
||||
@@ -116,6 +123,10 @@ pub enum ButtonAction {
|
||||
command: ExecArgs,
|
||||
toast: Option<Arc<str>>,
|
||||
},
|
||||
VirtualKey {
|
||||
keycode: VirtualKey,
|
||||
action: PressRelease,
|
||||
},
|
||||
Watch {
|
||||
action: WatchAction,
|
||||
},
|
||||
@@ -316,6 +327,9 @@ fn handle_action(action: &ButtonAction, press: &mut PressData, app: &mut AppStat
|
||||
ButtonAction::Watch { action } => run_watch(action, app),
|
||||
ButtonAction::Overlay { target, action } => run_overlay(target, action, app),
|
||||
ButtonAction::Window { target, action } => run_window(target, action, app),
|
||||
ButtonAction::VirtualKey { keycode, action } => app
|
||||
.hid_provider
|
||||
.send_key(*keycode, matches!(*action, PressRelease::Press)),
|
||||
ButtonAction::Toast {
|
||||
message,
|
||||
body,
|
||||
|
||||
+2
-1
@@ -7,6 +7,7 @@ use input_linux::{
|
||||
};
|
||||
use libc::{input_event, timeval};
|
||||
use once_cell::sync::Lazy;
|
||||
use serde::Deserialize;
|
||||
use std::mem::transmute;
|
||||
use std::{fs::File, sync::atomic::AtomicBool};
|
||||
use strum::{EnumIter, EnumString, IntoEnumIterator};
|
||||
@@ -316,7 +317,7 @@ pub const META: KeyModifier = 0x80;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(u16)]
|
||||
#[derive(Debug, PartialEq, Clone, Copy, IntegerId, EnumString, EnumIter)]
|
||||
#[derive(Debug, Deserialize, PartialEq, Clone, Copy, IntegerId, EnumString, EnumIter)]
|
||||
pub enum VirtualKey {
|
||||
Escape = 9,
|
||||
N1, // number row
|
||||
|
||||
@@ -6,12 +6,12 @@ use std::{
|
||||
|
||||
use crate::{
|
||||
backend::{
|
||||
input::PointerMode,
|
||||
overlay::{OverlayData, OverlayState},
|
||||
input::{InteractionHandler, PointerMode},
|
||||
overlay::{OverlayBackend, OverlayData, OverlayRenderer, OverlayState},
|
||||
},
|
||||
config::{self, ConfigType},
|
||||
gui::{
|
||||
canvas::{builder::CanvasBuilder, control::Control},
|
||||
canvas::{builder::CanvasBuilder, control::Control, Canvas},
|
||||
color_parse, KeyCapType,
|
||||
},
|
||||
hid::{
|
||||
@@ -180,7 +180,7 @@ where
|
||||
interaction_transform,
|
||||
..Default::default()
|
||||
},
|
||||
backend: Box::new(canvas),
|
||||
backend: Box::new(KeyboardBackend { canvas }),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
@@ -435,3 +435,68 @@ fn key_events_for_macro(macro_verbs: &Vec<String>) -> Vec<(VirtualKey, bool)> {
|
||||
}
|
||||
key_events
|
||||
}
|
||||
|
||||
struct KeyboardBackend {
|
||||
canvas: Canvas<KeyboardData, KeyButtonData>,
|
||||
}
|
||||
|
||||
impl OverlayBackend for KeyboardBackend {
|
||||
fn set_interaction(&mut self, interaction: Box<dyn crate::backend::input::InteractionHandler>) {
|
||||
self.canvas.set_interaction(interaction)
|
||||
}
|
||||
fn set_renderer(&mut self, renderer: Box<dyn crate::backend::overlay::OverlayRenderer>) {
|
||||
self.canvas.set_renderer(renderer)
|
||||
}
|
||||
}
|
||||
|
||||
impl InteractionHandler for KeyboardBackend {
|
||||
fn on_pointer(
|
||||
&mut self,
|
||||
app: &mut AppState,
|
||||
hit: &crate::backend::input::PointerHit,
|
||||
pressed: bool,
|
||||
) {
|
||||
self.canvas.on_pointer(app, hit, pressed)
|
||||
}
|
||||
fn on_scroll(
|
||||
&mut self,
|
||||
app: &mut AppState,
|
||||
hit: &crate::backend::input::PointerHit,
|
||||
delta: f32,
|
||||
) {
|
||||
self.canvas.on_scroll(app, hit, delta)
|
||||
}
|
||||
fn on_left(&mut self, app: &mut AppState, pointer: usize) {
|
||||
self.canvas.on_left(app, pointer)
|
||||
}
|
||||
fn on_hover(
|
||||
&mut self,
|
||||
app: &mut AppState,
|
||||
hit: &crate::backend::input::PointerHit,
|
||||
) -> Option<crate::backend::input::Haptics> {
|
||||
self.canvas.on_hover(app, hit)
|
||||
}
|
||||
}
|
||||
|
||||
impl OverlayRenderer for KeyboardBackend {
|
||||
fn init(&mut self, app: &mut AppState) -> anyhow::Result<()> {
|
||||
self.canvas.init(app)
|
||||
}
|
||||
fn render(&mut self, app: &mut AppState) -> anyhow::Result<()> {
|
||||
self.canvas.render(app)
|
||||
}
|
||||
fn extent(&mut self) -> Option<[u32; 3]> {
|
||||
self.canvas.extent()
|
||||
}
|
||||
fn view(&mut self) -> Option<std::sync::Arc<vulkano::image::view::ImageView>> {
|
||||
self.canvas.view()
|
||||
}
|
||||
fn pause(&mut self, app: &mut AppState) -> anyhow::Result<()> {
|
||||
self.canvas.data_mut().modifiers = 0;
|
||||
app.hid_provider.set_modifiers(0);
|
||||
self.canvas.pause(app)
|
||||
}
|
||||
fn resume(&mut self, app: &mut AppState) -> anyhow::Result<()> {
|
||||
self.canvas.resume(app)
|
||||
}
|
||||
}
|
||||
+75
-14
@@ -18,6 +18,7 @@ use wlx_capture::{
|
||||
DrmFormat, FrameFormat, MouseMeta, WlxFrame, DRM_FORMAT_ABGR2101010, DRM_FORMAT_ABGR8888,
|
||||
DRM_FORMAT_ARGB8888, DRM_FORMAT_XBGR2101010, DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB8888,
|
||||
},
|
||||
pipewire::PipewireSelectScreenResult,
|
||||
WlxCapture,
|
||||
};
|
||||
|
||||
@@ -25,8 +26,8 @@ use wlx_capture::{
|
||||
use {
|
||||
crate::config_io,
|
||||
std::error::Error,
|
||||
std::{ops::Deref, path::PathBuf},
|
||||
wlx_capture::pipewire::{pipewire_select_screen, PipewireCapture},
|
||||
std::{ops::Deref, path::PathBuf, task},
|
||||
wlx_capture::pipewire::PipewireCapture,
|
||||
};
|
||||
|
||||
#[cfg(all(feature = "x11", feature = "pipewire"))]
|
||||
@@ -337,21 +338,22 @@ impl ScreenRenderer {
|
||||
)> {
|
||||
let name = output.name.clone();
|
||||
let embed_mouse = !session.config.double_cursor_fix;
|
||||
log::info!(
|
||||
"On screen share prompt, pick: {} {} {} (pos {}, {})",
|
||||
&output.name,
|
||||
&output.make,
|
||||
&output.model,
|
||||
&output.logical_pos.0,
|
||||
&output.logical_pos.1,
|
||||
);
|
||||
let select_screen_result = futures::executor::block_on(pipewire_select_screen(
|
||||
|
||||
let select_screen_result = select_pw_screen(
|
||||
&format!(
|
||||
"Now select: {} {} {} @ {},{}",
|
||||
&output.name,
|
||||
&output.make,
|
||||
&output.model,
|
||||
&output.logical_pos.0,
|
||||
&output.logical_pos.1
|
||||
),
|
||||
token,
|
||||
embed_mouse,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
))?;
|
||||
)?;
|
||||
|
||||
let node_id = select_screen_result.streams.first().unwrap().node_id; // streams guaranteed to have at least one element
|
||||
|
||||
@@ -866,8 +868,16 @@ pub fn create_screens_x11pw(app: &mut AppState) -> anyhow::Result<ScreenCreateDa
|
||||
let pw_tokens_copy = pw_tokens.clone();
|
||||
let token = pw_tokens.arc_get("x11").map(|s| s.as_str());
|
||||
let embed_mouse = !app.session.config.double_cursor_fix;
|
||||
let select_screen_result =
|
||||
futures::executor::block_on(pipewire_select_screen(token, embed_mouse, true, true, true))?;
|
||||
|
||||
let select_screen_result = select_pw_screen(
|
||||
"Select ALL screens on the screencast pop-up!",
|
||||
token,
|
||||
embed_mouse,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
)?;
|
||||
|
||||
if let Some(restore_token) = select_screen_result.restore_token {
|
||||
if pw_tokens.arc_set("x11".into(), restore_token.clone()) {
|
||||
log::info!("Adding Pipewire token {}", restore_token);
|
||||
@@ -1066,3 +1076,54 @@ fn best_match<'a>(
|
||||
log::debug!("best: {:?}", best.map(|b| &b.monitor));
|
||||
best
|
||||
}
|
||||
|
||||
#[cfg(feature = "pipewire")]
|
||||
fn select_pw_screen(
|
||||
instructions: &str,
|
||||
token: Option<&str>,
|
||||
embed_mouse: bool,
|
||||
screens_only: bool,
|
||||
persist: bool,
|
||||
multiple: bool,
|
||||
) -> Result<PipewireSelectScreenResult, wlx_capture::pipewire::AshpdError> {
|
||||
use crate::backend::notifications::DbusNotificationSender;
|
||||
use wlx_capture::pipewire::pipewire_select_screen;
|
||||
|
||||
let future = async move {
|
||||
let print_at = Instant::now() + Duration::from_millis(250);
|
||||
let mut notify = None;
|
||||
|
||||
let f = pipewire_select_screen(token, embed_mouse, screens_only, persist, multiple);
|
||||
futures::pin_mut!(f);
|
||||
|
||||
loop {
|
||||
match futures::poll!(&mut f) {
|
||||
task::Poll::Ready(result) => return result,
|
||||
task::Poll::Pending => {
|
||||
if Instant::now() >= print_at {
|
||||
log::info!("{}", instructions);
|
||||
if let Ok(sender) = DbusNotificationSender::new() {
|
||||
if let Ok(id) = sender.notify_send(instructions, "", 2, 0, 0, true) {
|
||||
notify = Some((sender, id));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
futures::future::lazy(|_| {
|
||||
std::thread::sleep(Duration::from_millis(10));
|
||||
})
|
||||
.await;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let result = f.await;
|
||||
if let Some((sender, id)) = notify {
|
||||
let _ = sender.notify_close(id);
|
||||
}
|
||||
result
|
||||
};
|
||||
|
||||
futures::executor::block_on(future)
|
||||
}
|
||||
Reference in new issue
Block a user