Skip to content

Conversation

@Traine9
Copy link

@Traine9 Traine9 commented Dec 15, 2025

Summary

  • Add KDE popup screen capture support with ScreenCast-only fallback
  • Add restore_token support for session persistence
  • Handle dual GPU (Intel + NVIDIA) systems: use memory buffers for CUDA when display is on Intel, enable DMA-BUF when display is on NVIDIA
  • Add "XDG Portal" option to web UI capture dropdown
  • Add build instructions for XDG Portal support in README

Test plan

  • Test on KDE Plasma 6 Wayland
  • Test on hybrid GPU system (Intel + NVIDIA)
  • Test on pure NVIDIA system
  • Verify web UI shows portal capture option

@parkerlreed
Copy link

GCC 15.2.1 has some warnings around the portal grab

[ 96%] Building CXX object CMakeFiles/sunshine.dir/src/platform/linux/input/inputtino_pen.cpp.o
[ 96%] Building CXX object CMakeFiles/sunshine.dir/src/platform/linux/input/inputtino_touch.cpp.o
[ 96%] Building CXX object CMakeFiles/sunshine.dir/src/platform/linux/publish.cpp.o
/home/parker/build/Sunshine/src/platform/linux/portalgrab.cpp:638:123: error: invalid use of incomplete type ‘class portal::session_cache_t’
  638 |     inline static const std::unique_ptr<session_cache_t> instance_ = std::unique_ptr<session_cache_t>(new session_cache_t());
      |                                                                                                                           ^
/home/parker/build/Sunshine/src/platform/linux/portalgrab.cpp:554:9: note: definition of ‘class portal::session_cache_t’ is not complete until the closing brace
  554 |   class session_cache_t {
      |         ^~~~~~~~~~~~~~~
[ 97%] Building CXX object CMakeFiles/sunshine.dir/src/platform/linux/graphics.cpp.o
In file included from /usr/include/c++/15/memory:80,
                 from /home/parker/build/Sunshine/src/platform/linux/portalgrab.cpp:9:
/usr/include/c++/15/bits/unique_ptr.h: In instantiation of ‘constexpr void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = portal::session_cache_t]’:
/usr/include/c++/15/bits/unique_ptr.h:398:17:   required from ‘constexpr std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = portal::session_cache_t; _Dp = std::default_delete<portal::session_cache_t>]’
  398 |           get_deleter()(std::move(__ptr));
      |           ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
/home/parker/build/Sunshine/src/platform/linux/portalgrab.cpp:638:58:   required from here
  638 |     inline static const std::unique_ptr<session_cache_t> instance_ = std::unique_ptr<session_cache_t>(new session_cache_t());
      |                                                          ^~~~~~~~~
/usr/include/c++/15/bits/unique_ptr.h:92:9: error: ‘portal::session_cache_t::~session_cache_t()’ is private within this context
   92 |         delete __ptr;
      |         ^~~~~~~~~~~~
/home/parker/build/Sunshine/src/platform/linux/portalgrab.cpp:628:5: note: declared private here
  628 |     ~session_cache_t() {
      |     ^
make[2]: *** [CMakeFiles/sunshine.dir/build.make:541: CMakeFiles/sunshine.dir/src/platform/linux/portalgrab.cpp.o] Error 1
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [CMakeFiles/Makefile2:2043: CMakeFiles/sunshine.dir/all] Error 2
make: *** [Makefile:156: all] Error 2

garnacho and others added 6 commits January 16, 2026 23:01
This is not present in the glad version imported in Sunshine,
plug the holes so that these functions may be used.
Add a new portal "grab" implementation that will request the necessary
permissions over XDG portals and use Pipewire for video data streaming.
This supports DMA-Buf buffer exchange for hardware accelerated encoding
(VAAPI, nvenc), software encoding will only work with memory buffers.
Require GIO and PIPEWIRE packages for portal support and use SYSTEM include directories. Also, clarify the fatal error message order for missing dependencies.
Pipewire has been added to the dependency lists for FreeBSD, Arch, Fedora, Homebrew, and Debian-based packaging and build scripts. This ensures proper support and integration for systems using Pipewire.
A value of 2 indicates "Remember this Selection".

Co-authored-by: Carson Katri <[email protected]>
@ReenigneArcher ReenigneArcher force-pushed the feat/linux/add-xdg-portal-grab branch from 70a1b64 to 9f0aefb Compare January 17, 2026 04:03
ReenigneArcher

This comment was marked as resolved.

@Traine9 Traine9 force-pushed the feat/linux/add-xdg-portal-grab branch from 374b524 to 1f566aa Compare January 19, 2026 21:05
d.bondarev and others added 13 commits January 19, 2026 23:12
- Add KDE popup screen capture support
- Add ScreenCast-only fallback when RemoteDesktop fails
- Add restore_token support for session persistence
- Handle dual GPU (Intel + NVIDIA) systems: use memory buffers for CUDA
  when display is on Intel, enable DMA-BUF when display is on NVIDIA
- Add "XDG Portal" option to web UI capture dropdown
- Add build instructions for XDG Portal support
- Add null checks in dbus_t destructor before g_object_unref calls
- Fix loop variable scope by declaring EGLint i inside for loop
- Unify create_session and create_screencast_session into create_portal_session()
- Unify start_session and start_screencast_session into start_portal_session()
- Refactor connect_to_portal() with helper functions to reduce cognitive complexity
- Fix restore_token memory management by using std::string instead of raw pointer

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Use the C++ nullptr literal instead of the C-style NULL macro
for improved type safety.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add restore token persistence to disk for auto-reconnection
- Merge nested if statements for cleaner control flow
- Make session_token parameter const where applicable
- Rename shadowed parameters (out_pipewire_node, out_width, out_height)
- Split variable declarations into separate statements
- Use member initializer list in pipewire_t constructor
- Replace strstr with std::string_view::find
- Extract helper functions to reduce nesting depth

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Encapsulate restore_token in accessor function to avoid global variable
- Make format_map static constexpr
- Replace C-style arrays with std::array
- Use std::string_view::contains instead of find

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Use inline variable for restore_token
- Convert format_map to std::array
- Use range-based for loops for format_map iteration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Replace global variable with restore_token_t class using singleton
pattern to satisfy SonarCloud's const global variable requirement.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Replace const std::string& with std::string_view in set()
- Use const unique_ptr<string> to satisfy const global requirement

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…ings

Add session_cache_t singleton that caches portal D-Bus session data.
This prevents creating multiple screen recording indicators in KDE
system tray during encoder probing, as each portal session would
otherwise show as a separate recording.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Detect hybrid GPU by checking for Intel vendor (0x8086) in DRM devices
- Use memory buffers instead of DMA-BUF for CUDA on hybrid systems
- Set row_pitch from pipewire buffer stride for correct CUDA copies
- Return timeout when no pipewire buffer available yet

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Use const unique_ptr for inline static instance (satisfies const global rule)
- Replace std::lock_guard with std::scoped_lock using CTAD

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@Traine9 Traine9 force-pushed the feat/linux/add-xdg-portal-grab branch from 1f566aa to 8abfeed Compare January 19, 2026 21:15
d.bondarev added 2 commits January 19, 2026 23:18
Use std::shared_ptr instead of std::unique_ptr for the singleton instance.
shared_ptr captures the deleter at construction time when the type is
complete, avoiding the incomplete type error with private destructor.

Fixes compilation error reported by parkerlreed.
- Revert README.md build instructions (not appropriate for README)
- Add XDG Portal option to FreeBSD capture dropdown
@Traine9
Copy link
Author

Traine9 commented Jan 19, 2026

fixed all things from @ReenigneArcher , gcc 15 warning should be gone too @parkerlreed

Always save the portal restore token when a new one is received,
not just when the token was previously empty. This fixes KDE
prompting to select a screen on every Sunshine restart.

Also improve session_cache_t singleton to use aligned storage,
avoiding destructor access issues.
@ReenigneArcher ReenigneArcher force-pushed the feat/linux/add-xdg-portal-grab branch from 9f0aefb to 5987970 Compare January 19, 2026 22:15
@Traine9 Traine9 force-pushed the feat/linux/add-xdg-portal-grab branch from 6c6d896 to 01440ac Compare January 19, 2026 22:15
@ReenigneArcher
Copy link
Member

@Traine9 appologies, but when I rebase the PR branch, it looks like it always causes conflicts in the portalgrab.cpp. Any chance you can resolve the conflicts again. I think you should just be able to ignore the differences and use the code as is in your branch for portalgrab.cpp.

@Traine9
Copy link
Author

Traine9 commented Jan 19, 2026

@ReenigneArcher merged without force push now you should able to merge it

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
4 New issues
1 Security Hotspot
4 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

@LizardByte LizardByte deleted a comment from sonarqubecloud bot Jan 20, 2026
@ReenigneArcher ReenigneArcher merged commit 7034c84 into LizardByte:feat/linux/add-xdg-portal-grab Jan 20, 2026
37 of 43 checks passed
@codecov
Copy link

codecov bot commented Jan 20, 2026

Bundle Report

Changes will increase total bundle size by 90 bytes (0.0%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
sunshine-esm 968.68kB 90 bytes (0.01%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: sunshine-esm

Assets Changed:

Asset Name Size Change Total Size Change (%)
assets/config-*.js 90 bytes 60.92kB 0.15%

Files in assets/config-*.js:

  • ./src_assets/common/assets/web/configs/tabs/Advanced.vue → Total Size: 9.24kB

@parkerlreed
Copy link

Multi touch/pen/stylus seems to be completely non functional with this enabled. Trackpad works as expected.

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.

4 participants