WarmUpTill / SceneSwitcher

An automation tool for OBS Studio
https://obsproject.com/forum/resources/automatic-scene-switching.395/
GNU General Public License v2.0
995 stars 78 forks source link

Cursor position only updates over xwayland windows #512

Open KaelWD opened 2 years ago

KaelWD commented 2 years ago

Describe the bug Dual monitor setup with 2560x1440 and 1920x1080, using this plugin to switch between monitors based on cursor position. OBS installed from apt ppa.

To Reproduce Steps to reproduce the behavior:

  1. Open scene switcher settings with a cursor macro
  2. Move cursor over an xwayland window (eg. chrome)
  3. Move cursor over a native wayland window (eg. obs)

Expected behavior The cursor position should always update

Actual behavior The cursor position is frozen to the last value before it left the xwayland window

Logs https://gist.github.com/KaelWD/1b59698b7b7d0e3d09d1485ccced69bb

Version information

Operating System: Kubuntu 22.04 KDE Plasma Version: 5.24.6 KDE Frameworks Version: 5.95.0 Qt Version: 5.15.3 Kernel Version: 5.15.0-46-generic (64-bit) Graphics Platform: Wayland

WarmUpTill commented 2 years ago

Thank you for reporting the issue!

Unfortunately that is a known limitation of the plugin as it relies on the X window system to receive this information. https://github.com/WarmUpTill/SceneSwitcher/blob/c392004edf6055597d403e949011c954accedb86/src/linux/advanced-scene-switcher-nix.cpp#L263-L266 I haven't found a way to make this work for native Wayland applications yet. Similar issues might occur in other functionality which relies on the X* functions like getting information window states or simulating key presses.

I am not sure when I will get around to this.

MSVO commented 2 years ago

I faced the same issue with Ubuntu 22.10. Cursor position was detected in browser but not in obs window. Upon starting the screen switcher, obs crashes in few seconds. Then I saw this thread and switched to "Ubuntu Xorg" from available desktop choices in Ubuntu log-in prompt. Now it works!.

WarmUpTill commented 2 years ago

The changes in the linked PR might be able to resolve the issue, as instead of relying on the XQueryPointer() function the Qt function QCursor::pos() is used.

I would appreciate if someone facing this problem could give this build a try and report back if it made a difference: https://github.com/WarmUpTill/SceneSwitcher/actions/runs/3558051581

jvyden commented 2 years ago

I would appreciate if someone facing this problem could give this build a try and report back if it made a difference: https://github.com/WarmUpTill/SceneSwitcher/actions/runs/3558051581

I tried this build on Arch Linux, and it seems to segfault after clicking "Start" in the settings. Here's the log:

info: [adv-ss] started
X Error of failed request:  BadWindow (invalid Window parameter)
  Major opcode of failed request:  20 (X_GetProperty)
  Resource id in failed request:  0x0
  Serial number of failed request:  38
  Current serial number in output stream:  38
QObject::killTimer: Timers cannot be stopped from another thread
QObject::~QObject: Timers cannot be stopped from another thread
error: eglMakeCurrent failed
error: eglMakeCurrent failed
error: eglMakeCurrent failed
error: eglSwapInterval failed
error: eglSwapBuffers failed
QObject::killTimer: Timers cannot be stopped from another thread
QObject::~QObject: Timers cannot be stopped from another thread
Segmentation fault (core dumped)

Looks like it's still trying to use X11 in some way?

I ran the coredump through GDB and here's what it had to say, although it's probably not too helpful:

[Thread debugging using libthread_db enabled]                                                                                                                                               
Using host libthread_db library "/usr/lib/libthread_db.so.1".
--Type <RET> for more, q to quit, c to continue without paging--
Core was generated by `obs'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00007f3ee7909df8 in nullBrushInstance () at /usr/src/debug/qt6-base/qtbase-everywhere-src-6.4.1/src/gui/painting/qbrush.cpp:339
Downloading 0.07 MB source file /usr/src/debug/qt6-base/qtbase-everywhere-src-6.4.1/src/gui/painting/qbrush.cpp
339         return nullBrushInstance_holder()->brush;                                                                                                                                       
[Current thread is 1 (Thread 0x7f3ed663d600 (LWP 63898))]

Let me know if you need the coredump for further inspection (I can get around with it but I don't know how to use it that much haha) and I can e-mail it to you, or if other information is needed :p

WarmUpTill commented 2 years ago

Huh, that is strange - not sure why it would segfault in some Qt paint function. I would appreciate it if you can share the core file.

Looks like it's still trying to use X11 in some way?

The window title related stuff as well as the idle detection is still relying on X11. I assume that is where the X_GetProperty error is coming from.

Thanks for the test!

jvyden commented 2 years ago

Here you go:

core.obs.1000.29339cecb2c6447ea268952ac5f0e674.21203.1669666507000000.zip

I hope this doesnt have anything sensitive lol :sweat_smile:

jvyden commented 2 years ago

Should be noted that this is a different coredump than the one I shared the details of above, I accidentally nuked it while cleaning up my drive. Regardless, setup was the same.

WarmUpTill commented 2 years ago

Thanks for sharing the core file!

I added additional error handling for non X11 windowing systems. A build should be available here in a few minutes: https://github.com/WarmUpTill/SceneSwitcher/actions/runs/3584941397

Seems to work as expected on Ubuntu with Wayland windowing system.

Note that the same type of crash occurs with the built-in OBS scene switcher as well every time the active window is changed. I will probably submit a PR for this as well.

jvyden commented 2 years ago

Seems to be tracking the cursor for Wayland windows properly, but it still seems to be a little problematic. The position of the cursor only updates when it's over the OBS window itself.

Give the nature of this, I wonder if it's a security problem. Is Wayland not sending cursor updates on purpose?

WarmUpTill commented 2 years ago

Give the nature of this, I wonder if it's a security problem. Is Wayland not sending cursor updates on purpose?

As far as I understood X11 and Wayland are designed completely differently and Wayland simply does not provided standardized way to get the global cursor position outside the active window.

I could try to read directly from the corresponding /dev/input/eventX devices and try to figure out which one is the mouse, but that is probably not a good idea either. Usually only a limited set of users / groups can access those devices and there are probably a lot of edge cases to consider.

So unfortunately I do not really have a solution to support this functionality on Wayland the same way it is on X11.

But at least the crashes are solved for now, so I will merge the PR, but leave the issue open in case someone else has an idea how to solve this.

achow101 commented 2 months ago

While Wayland doesn't provide a way to get the global cursor position, at least some compositors do. KWin's scripting API allows fetching the cursor position, and I found kdotool which utilizes that functionality to retrieve that information (although it looks like the implementation for getting the cursor position is not really that complicated). I've written a script that adds a macro condition "KWin Cursor" that is similar to the built in cursor condition but uses kdotool to retrieve the cursor position: https://github.com/achow101/obs-avss-kwin-cursor/blob/main/kwin-cursor.py

I'd guess that the only true solution to this problem would require implementing every compositors' different way of retrieving the cursor position if they have that supported at all. But that seems extraordinarily annoying to do.