Skip to content

feat(capture/linux): add KWin direct screencast capture method#5009

Open
Kishi85 wants to merge 16 commits intoLizardByte:masterfrom
Kishi85:kwin-direct-screencast
Open

feat(capture/linux): add KWin direct screencast capture method#5009
Kishi85 wants to merge 16 commits intoLizardByte:masterfrom
Kishi85:kwin-direct-screencast

Conversation

@Kishi85
Copy link
Copy Markdown
Contributor

@Kishi85 Kishi85 commented Apr 16, 2026

Description

This adapts the changes from #4724 to the changes from #5008. See the linked PR for details on the feature.

ToDo-List:

Screenshot

Issues Fixed or Closed

Roadmap Issues

Type of Change

  • feat: New feature (non-breaking change which adds functionality)
  • fix: Bug fix (non-breaking change which fixes an issue)
  • docs: Documentation only changes
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semicolons, etc.)
  • refactor: Code change that neither fixes a bug nor adds a feature
  • perf: Code change that improves performance
  • test: Adding missing tests or correcting existing tests
  • build: Changes that affect the build system or external dependencies
  • ci: Changes to CI configuration files and scripts
  • chore: Other changes that don't modify src or test files
  • revert: Reverts a previous commit
  • BREAKING CHANGE: Introduces a breaking change (can be combined with any type above)

Checklist

  • Code follows the style guidelines of this project
  • Code has been self-reviewed
  • Code has been commented, particularly in hard-to-understand areas
  • Code docstring/documentation-blocks for new or existing methods/components have been added or updated
  • Unit tests have been added or updated for any new or modified functionality

AI Usage

  • None: No AI tools were used in creating this PR
  • Light: AI provided minor assistance (formatting, simple suggestions)
  • Moderate: AI helped with code generation or debugging specific parts
  • Heavy: AI generated most or all of the code changes

@Kishi85 Kishi85 force-pushed the kwin-direct-screencast branch 9 times, most recently from 2ce02db to b1dbab7 Compare April 17, 2026 12:08
@neatnoise
Copy link
Copy Markdown
Contributor

Tested on KDE Plasma 6.6.4, RX 9070 XT, Mesa 26.2 dev, CachyOS with Vulkan CBR encoding. Works great once you get past the setup — I had to set KWIN_WAYLAND_NO_PERMISSION_CHECKS=1 for KWin (via
~/.config/environment.d/kwin.conf) and restart the session, otherwise the protocol doesn't show up in the registry even though the screencast plugin is loaded.

Once running, streaming is smooth. At one point Moonlight picked the external IP instead of the local one (sometimes It does), so the stream was going out through the internet and back without me even noticing — only realized when I turned on the debug overlay and saw higher the Internet network latency.

@Kishi85 Kishi85 changed the title feat(capture/linux): add KWin direct screencast capture method feat(capture/linux): add KWin direct screencast capture method - v2 Apr 17, 2026
@ReenigneArcher ReenigneArcher changed the title feat(capture/linux): add KWin direct screencast capture method - v2 feat(capture/linux): add KWin direct screencast capture method Apr 17, 2026
@Kishi85 Kishi85 changed the title feat(capture/linux): add KWin direct screencast capture method feat(capture/linux): add KWin direct screencast capture method (v2) Apr 17, 2026
@Kishi85 Kishi85 changed the title feat(capture/linux): add KWin direct screencast capture method (v2) feat(capture/linux): add KWin direct screencast capture method Apr 17, 2026
@Kishi85
Copy link
Copy Markdown
Contributor Author

Kishi85 commented Apr 17, 2026

void-linux/void-packages#31274 (comment)

Has had the permission issue before on xdg-portal-kde and fixed it by adding X-KDE-Wayland-Interfaces=zkde_screencast_unstable_v1 to the associated desktop file. So maybe we could do something similar here and have a clean way to run this without any hacks or environment variables necessary.

@Kishi85
Copy link
Copy Markdown
Contributor Author

Kishi85 commented Apr 17, 2026

Adding a dummy desktop file like this as ~/.local/share/applications/app-dev.lizardbyte.app.Sunshine-kwin-screencast-helper.desktop or /usr/share/applications/app-dev.lizardbyte.app.Sunshine-kwin-screencast-helper.desktop fixes the permission issue but needs the absolute path to the real binary in it for kwin to be able to properly assign the permission:

[Desktop Entry]
Comment=Sunshine kwin screencast permission helper
Name=app-dev.lizardbyte.app.Sunshine-kwin-screencast-helper
NoDisplay=true
Type=Application
X-KDE-Wayland-Interfaces=zkde_screencast_unstable_v1
Exec=/home/user/git/sunshine/cmake-build-debug/sunshine-0.0.0-b1dbab76

I'll have to test if we have to package and properly distribute the .desktop file or if it is sufficient to create it on-the-fly upon kwingrab init (in ~/.local/share/applications/app-dev.lizardbyte.app.Sunshine-kwin-screencast-helper.desktop before accessing zkde_screencast_unstable_v1). The latter would be preferable, we could also just remove the desktop file upon destruction to have a clean state.

@Kishi85 Kishi85 force-pushed the kwin-direct-screencast branch 13 times, most recently from 980f115 to 2e361c6 Compare April 18, 2026 19:14
@Kishi85
Copy link
Copy Markdown
Contributor Author

Kishi85 commented Apr 18, 2026

Running this with CAP_SYS_ADMIN breaks KWin's permission check (because it's not allowed to resolve the executable path for the PID with the capability). I'll have to check if the same workaround we do for portalgrab works here.

@Kishi85 Kishi85 marked this pull request as ready for review April 21, 2026 17:27
@Kishi85 Kishi85 force-pushed the kwin-direct-screencast branch from 6453fa9 to 03163b3 Compare April 22, 2026 08:23
@Kishi85
Copy link
Copy Markdown
Contributor Author

Kishi85 commented Apr 22, 2026

Added necessary adaptions for #5041 (also temporarily added the commit from #5041 to the list so this can be tested properly).

Please do not merge before #5041 is merged.

@moi952

This comment was marked as off-topic.

@Kishi85

This comment was marked as off-topic.

Kishi85 and others added 15 commits April 23, 2026 07:06
This commit is taken from LizardByte#4724
with all pipewire duplication removed and changed to pipewire.cpp

Co-authored-by: Ramalama2 <6314556+Ramalama2@users.noreply.github.com>
…wayland output index

This is just a first shot at working multi-monitor support for basic
testing.
Utilitzies kde_output_order_v1 wayland protocol
…s permission check

KWin's Wayland permission check requires the wayland client processs
pid's executable to be readable by KWin. While running with
CAP_SYS_ADMIN this is not possible so KWin will fail the check.
This is necessary for running with CAP_SYS_ADMIN as the normal check for
display_names being empty will not work as that will always return a
dummy value to not drop capabilities early (before encoder probing).
…ermission

Also extend the permission helper to check if system file exists
Added right after ENABLE_PORTAL (as it's very similar).
FreeBSD and Flatpak should be tested more before enabling.
@Kishi85
Copy link
Copy Markdown
Contributor Author

Kishi85 commented Apr 23, 2026

@ReenigneArcher Do you think this should be enabled for FreeBSD and Flatpak as well (to be on-par with portalgrab)? Nothing should break, the worst case would be that kwingrab does not work (most likely due to missing permissions).

Unfortunately I can't test those 2 options by myself atm, hence I've left them out in eba45e6.

@psyke83
Copy link
Copy Markdown
Contributor

psyke83 commented Apr 23, 2026

My thoughts:

XDG Desktop Portal is always guaranteed to work for a Flatpak since the XDG standard is mandated by the package format, and the Desktop Portal is specifically targeted for sandboxed apps. KDE also (uniquely) has a secondary permission system - plumbed through flatpak - that allows bypassing of manual portal setup. For that reason, kwingrab is technically not necessary unless there is a measurable performance difference in the screencast flow through pipewire between the methods. But on the other hand, kwingrab has the same security requirements as portal, and can work without issue as long as your .desktop file is installed, correct? I don't see the harm in enabling it, as long as we can verify it works as expected. Having it enabled for all possible Linux packaging formats would simplify documentation.

FreeBSD doesn't support Flatpak, and while I think they do support the XDG standard, Desktop Portal is not guaranteed to be present, and if it is, it's unclear how to leverage the permission bypass without a working flatpak command, so it seems that kwingrab makes sense for this environment.

@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
18 New issues
18 New Code Smells (required ≤ 0)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@Kishi85
Copy link
Copy Markdown
Contributor Author

Kishi85 commented Apr 23, 2026

My thoughts:

XDG Desktop Portal is always guaranteed to work for a Flatpak since the XDG standard is mandated by the package format, and the Desktop Portal is specifically targeted for sandboxed apps. KDE also (uniquely) has a secondary permission system - plumbed through flatpak - that allows bypassing of manual portal setup. For that reason, kwingrab is technically not necessary unless there is a measurable performance difference in the screencast flow through pipewire between the methods. But on the other hand, kwingrab has the same security requirements as portal, and can work without issue as long as your .desktop file is installed, correct? I don't see the harm in enabling it, as long as we can verify it works as expected. Having it enabled for all possible Linux packaging formats would simplify documentation.

FreeBSD doesn't support Flatpak, and while I think they do support the XDG standard, Desktop Portal is not guaranteed to be present, and if it is, it's unclear how to leverage the permission bypass without a working flatpak command, so it seems that kwingrab makes sense for this environment.

  • From my personal testing (over local ethernet) kwingrab feels subjectively snappier than portalgrab and objectively (from moonlight streaming stats) host processing latency is lower for kwingrab vs. portalgrab on mostly idle desktop. At least in my case min values go down to 1.5ms with kwingrab vs. >=2ms with portalgrab, with averages following by around the same amount of difference.
  • Since we're forced to use KDE-specific Wayland protocols for kwingrab via zkde_screencast_unstable_v1 already it's also using kde_output_order_v1 so kwingrab is able to follow Screen priorities set in Display Settings. Making the primary screen the one that the sunshine stream is started on and keyboard shortcut order by the same logic.
  • The secondary permission system for portalgrab via flatpak seems to be irrelevant for kwingrab as it's only checking the wayland interface permission via executable matching desktop file. AppImages work via the temporary permission helper but I'm unsure if the same is true for Flatpak (as that might not yield the correct desktop file for permission or need the security context implementation instead).
  • As for FreeBSD that's the interesting one. KWin screencasting does not require Desktop Portal only Pipewire so in theory it should just work with kwin_wayland on FreeBSD. I've no way to test this atm and I'm not sure the permission setup will work correctly for that case.

@Kishi85
Copy link
Copy Markdown
Contributor Author

Kishi85 commented Apr 23, 2026

Technical sidenote: Looking at /usr/share/applications/org.freedesktop.impl.portal.desktop.kde.desktop one can see that xdg-desktop-portal-kde is also using zkde_screencast_unstable_v1 (among a few other interfaces) to provide the XDG portal implementation for KDE:

[Desktop Entry]
Exec=/usr/lib/xdg-desktop-portal-kde
X-KDE-Wayland-Interfaces=org_kde_kwin_fake_input,org_kde_plasma_window_management,zkde_screencast_unstable_v1
X-KDE-DBUS-Restricted-Interfaces=org.kde.KWin.ScreenShot2
NoDisplay=true
Icon=kde

So we can assume that all pipewire stream features for portalgrab via xdg-desktop-portal-kde should also be directly available for kwingrab.

@psyke83
Copy link
Copy Markdown
Contributor

psyke83 commented Apr 23, 2026

That's the issue with kwingrab; there's extra maintenance burden in directly utilizing the (unstable) Wayland extension that would be transparently handled by XDG Portal via the KDE helper.

Relevant PR that may impact us in future, if the "v1" protocol is obsoleted: https://invent.kde.org/plasma/kwin/-/merge_requests/9048
Edit: matching PR on Portal side: https://invent.kde.org/plasma/xdg-desktop-portal-kde/-/merge_requests/544

@Kishi85
Copy link
Copy Markdown
Contributor Author

Kishi85 commented Apr 23, 2026

That's the issue with kwingrab; there's extra maintenance burden in directly utilizing the (unstable) Wayland extension that would be transparently handled by XDG Portal via the KDE helper.

Relevant PR that may impact us in future, if the "v1" protocol is obsoleted: https://invent.kde.org/plasma/kwin/-/merge_requests/9048 Edit: matching PR on Portal side: https://invent.kde.org/plasma/xdg-desktop-portal-kde/-/merge_requests/544

We're not the only ones in that boat then (OBS for example also utilizes it) and if it breaks we still have a working fallback with portalgrab (which Sunshine will always need for anything non-KWin). Also we have enough time to prepare so thanks for mentioning the drafts early.

kwingrab is just a way to get a more direct stream for KWin-based systems with a few bonuses (like working screen priorities). The main streaming logic is already shared with portalgrab by utilizing pipewire_display_t so it's just the negotiation that might break until fixed (although I'm not seeing a huge difference for output streaming between v1 and v2 as it is right now. We should even be able to implement a fallback from v2 to v1 once the necessary definitions are in plasma-wayland-protocols).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants