fixed ubuntu (Wayland) recording workflow
This commit is contained in:
+26
-2
@@ -107,6 +107,15 @@ function hasBinary(name) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// On Wayland, xinput only sees XWayland (X11-bridge) events — native Wayland
|
||||||
|
// app clicks are delivered via the Wayland protocol and never reach xinput.
|
||||||
|
// Treating it as "available" would leave the session with no click capture AND
|
||||||
|
// no interval fallback, so zero steps get captured.
|
||||||
|
function isWayland() {
|
||||||
|
return process.platform === 'linux'
|
||||||
|
&& (process.env.XDG_SESSION_TYPE === 'wayland' || Boolean(process.env.WAYLAND_DISPLAY));
|
||||||
|
}
|
||||||
|
|
||||||
class CaptureService {
|
class CaptureService {
|
||||||
constructor({
|
constructor({
|
||||||
store,
|
store,
|
||||||
@@ -184,7 +193,11 @@ class CaptureService {
|
|||||||
|
|
||||||
clickCaptureAvailable() {
|
clickCaptureAvailable() {
|
||||||
if (this._clickAvail === undefined) {
|
if (this._clickAvail === undefined) {
|
||||||
this._clickAvail = process.platform === 'win32' || (process.platform === 'linux' && hasBinary('xinput'));
|
// Wayland: xinput connects via XWayland and only sees X11-bridge clicks.
|
||||||
|
// Native Wayland app events are invisible to it, so we can't reliably
|
||||||
|
// detect clicks — disable this path and fall back to interval capture.
|
||||||
|
this._clickAvail = process.platform === 'win32'
|
||||||
|
|| (process.platform === 'linux' && !isWayland() && hasBinary('xinput'));
|
||||||
}
|
}
|
||||||
return this._clickAvail;
|
return this._clickAvail;
|
||||||
}
|
}
|
||||||
@@ -300,6 +313,7 @@ class CaptureService {
|
|||||||
showWindow() {
|
showWindow() {
|
||||||
const win = this.getWindow();
|
const win = this.getWindow();
|
||||||
if (win && !win.isDestroyed()) {
|
if (win && !win.isDestroyed()) {
|
||||||
|
if (win.isMinimized()) win.restore();
|
||||||
win.show();
|
win.show();
|
||||||
win.focus();
|
win.focus();
|
||||||
}
|
}
|
||||||
@@ -383,7 +397,16 @@ class CaptureService {
|
|||||||
if (!this.session || this.session.paused) { this.warmingUp = false; return; }
|
if (!this.session || this.session.paused) { this.warmingUp = false; return; }
|
||||||
}
|
}
|
||||||
if (wantHide && win && !win.isDestroyed() && win.isVisible()) {
|
if (wantHide && win && !win.isDestroyed() && win.isVisible()) {
|
||||||
|
// On Linux without a working system tray (common on Wayland GNOME
|
||||||
|
// without AppIndicator) the user has no way to bring back a hidden
|
||||||
|
// window mid-session. Minimize instead: the window disappears from
|
||||||
|
// screen (so it won't appear in fullscreen screenshots) but remains
|
||||||
|
// accessible via the taskbar.
|
||||||
|
if (process.platform === 'linux' && (!this.tray || this.tray.isDestroyed())) {
|
||||||
|
win.minimize();
|
||||||
|
} else {
|
||||||
win.hide();
|
win.hide();
|
||||||
|
}
|
||||||
// Let a couple of frames of the now-unobscured screen land before
|
// Let a couple of frames of the now-unobscured screen land before
|
||||||
// the user's first click, so that frame shows their work, not the
|
// the user's first click, so that frame shows their work, not the
|
||||||
// app window that was just dismissed.
|
// app window that was just dismissed.
|
||||||
@@ -775,13 +798,14 @@ class CaptureService {
|
|||||||
try {
|
try {
|
||||||
this.clickWatcherBuf = '';
|
this.clickWatcherBuf = '';
|
||||||
this.linuxEvent = null;
|
this.linuxEvent = null;
|
||||||
if (process.platform === 'linux' && hasBinary('xinput')) {
|
if (process.platform === 'linux' && !isWayland() && hasBinary('xinput')) {
|
||||||
// Stream raw button events from the X server; one capture per press.
|
// Stream raw button events from the X server; one capture per press.
|
||||||
// xinput block-buffers stdout when piped, so a press event can sit
|
// xinput block-buffers stdout when piped, so a press event can sit
|
||||||
// in its buffer until later motion events flush it — by then the
|
// in its buffer until later motion events flush it — by then the
|
||||||
// cursor read in onOsClick lands where the mouse moved *after* the
|
// cursor read in onOsClick lands where the mouse moved *after* the
|
||||||
// click. stdbuf -oL forces line-buffering so events (and the cursor
|
// click. stdbuf -oL forces line-buffering so events (and the cursor
|
||||||
// read) line up with the actual click instant.
|
// read) line up with the actual click instant.
|
||||||
|
// (Skipped on Wayland: xinput only sees XWayland events — see isWayland.)
|
||||||
const argv = hasBinary('stdbuf')
|
const argv = hasBinary('stdbuf')
|
||||||
? ['stdbuf', '-oL', 'xinput', 'test-xi2', '--root']
|
? ['stdbuf', '-oL', 'xinput', 'test-xi2', '--root']
|
||||||
: ['xinput', 'test-xi2', '--root'];
|
: ['xinput', 'test-xi2', '--root'];
|
||||||
|
|||||||
@@ -14,7 +14,13 @@ try {
|
|||||||
}
|
}
|
||||||
const env = sanitizeElectronEnv();
|
const env = sanitizeElectronEnv();
|
||||||
|
|
||||||
const child = spawn(electronPath, ['.'], {
|
// On Linux/Wayland, enable PipeWire-based screen capture so desktopCapturer
|
||||||
|
// can go through the XDG Desktop Portal when XWayland isn't the only option.
|
||||||
|
const extraArgs = process.platform === 'linux'
|
||||||
|
? ['--enable-features=WebRTCPipeWireCapturer']
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const child = spawn(electronPath, [...extraArgs, '.'], {
|
||||||
stdio: 'inherit',
|
stdio: 'inherit',
|
||||||
env,
|
env,
|
||||||
windowsHide: false,
|
windowsHide: false,
|
||||||
|
|||||||
Reference in New Issue
Block a user