@@ -172,6 +172,12 @@ namespace portal {
172172 int n_modifiers;
173173 };
174174
175+ struct pipewire_screenstream_t {
176+ int pipewire_node;
177+ int width;
178+ int height;
179+ };
180+
175181 class dbus_t {
176182 public:
177183 ~dbus_t () noexcept {
@@ -281,7 +287,7 @@ namespace portal {
281287 return -1 ;
282288 }
283289
284- if (start_portal_session (loop, session_path, pipewire_node, width, height , use_screencast_only) < 0 ) {
290+ if (start_portal_session (loop, session_path, pipewire_streams , use_screencast_only) < 0 ) {
285291 return -1 ;
286292 }
287293
@@ -331,10 +337,8 @@ namespace portal {
331337 return 0 ;
332338 }
333339
340+ std::vector<pipewire_screenstream_t > pipewire_streams;
334341 int pipewire_fd;
335- int pipewire_node;
336- int width;
337- int height;
338342
339343 private:
340344 GDBusConnection *conn;
@@ -472,6 +476,7 @@ namespace portal {
472476 g_variant_builder_add (&builder, " {sv}" , " handle_token" , g_variant_new_string (request_token));
473477 g_variant_builder_add (&builder, " {sv}" , " types" , g_variant_new_uint32 (SOURCE_TYPE_MONITOR));
474478 g_variant_builder_add (&builder, " {sv}" , " cursor_mode" , g_variant_new_uint32 (CURSOR_MODE_EMBEDDED));
479+ g_variant_builder_add (&builder, " {sv}" , " multiple" , g_variant_new_boolean (TRUE ));
475480 if (persist) {
476481 g_variant_builder_add (&builder, " {sv}" , " persist_mode" , g_variant_new_uint32 (PERSIST_UNTIL_REVOKED));
477482 if (!restore_token_t::empty ()) {
@@ -510,7 +515,7 @@ namespace portal {
510515 return 0 ;
511516 }
512517
513- int start_portal_session (GMainLoop *loop, const gchar *session_path, int &out_pipewire_node, int &out_width, int &out_height , bool use_screencast) {
518+ int start_portal_session (GMainLoop *loop, const gchar *session_path, std::vector< pipewire_screenstream_t > &out_pipewire_streams , bool use_screencast) {
514519 GDBusProxy *proxy = use_screencast ? screencast_proxy : remote_desktop_proxy;
515520 const char *session_type = use_screencast ? " ScreenCast" : " RemoteDesktop" ;
516521
@@ -570,10 +575,14 @@ namespace portal {
570575 }
571576
572577 GVariantIter iter;
578+ int out_pipewire_node;
579+ int out_width;
580+ int out_height;
573581 g_autoptr (GVariant) value = nullptr ;
574582 g_variant_iter_init (&iter, streams);
575583 while (g_variant_iter_next (&iter, " (u@a{sv})" , &out_pipewire_node, &value)) {
576584 g_variant_lookup (value, " size" , " (ii)" , &out_width, &out_height, nullptr );
585+ out_pipewire_streams.emplace_back (pipewire_screenstream_t {out_pipewire_node, out_width, out_height});
577586 }
578587
579588 return 0 ;
@@ -669,15 +678,13 @@ namespace portal {
669678 *
670679 * @return 0 on success, -1 on failure
671680 */
672- int get_or_create_session (int &pipewire_fd, int &pipewire_node, int &width, int &height ) {
681+ int get_or_create_session (int &pipewire_fd, std::vector< pipewire_screenstream_t > &pipewire_streams ) {
673682 std::scoped_lock lock (mutex_);
674683
675684 if (valid_) {
676685 // Return cached session data
677686 pipewire_fd = dup (pipewire_fd_); // Duplicate FD for each caller
678- pipewire_node = pipewire_node_;
679- width = width_;
680- height = height_;
687+ pipewire_streams = pipewire_streams_;
681688 BOOST_LOG (debug) << " Reusing cached portal session" sv;
682689 return 0 ;
683690 }
@@ -694,16 +701,12 @@ namespace portal {
694701
695702 // Cache the session data
696703 pipewire_fd_ = dbus_->pipewire_fd ;
697- pipewire_node_ = dbus_->pipewire_node ;
698- width_ = dbus_->width ;
699- height_ = dbus_->height ;
704+ pipewire_streams_ = dbus_->pipewire_streams ;
700705 valid_ = true ;
701706
702707 // Return to caller (duplicate FD so each caller has their own)
703708 pipewire_fd = dup (pipewire_fd_);
704- pipewire_node = pipewire_node_;
705- width = width_;
706- height = height_;
709+ pipewire_streams = pipewire_streams_;
707710
708711 BOOST_LOG (debug) << " Created new portal session (cached)" sv;
709712 return 0 ;
@@ -759,9 +762,7 @@ namespace portal {
759762 std::mutex mutex_;
760763 std::unique_ptr<dbus_t > dbus_;
761764 int pipewire_fd_ = -1 ;
762- int pipewire_node_ = 0 ;
763- int width_ = 0 ;
764- int height_ = 0 ;
765+ std::vector<pipewire_screenstream_t > pipewire_streams_;
765766 bool valid_ = false ;
766767 bool maxframerate_failed_ = false ;
767768 };
@@ -1235,13 +1236,31 @@ namespace portal {
12351236 return -1 ;
12361237 }
12371238
1239+ // Convert display name back to int as it is an index
1240+ int display_index = -1 ;
1241+ if (!display_name.empty ()) {
1242+ display_index = std::stoi (display_name);
1243+ }
1244+
12381245 // Use cached portal session to avoid creating multiple screen recordings
12391246 int pipewire_fd = -1 ;
1240- int pipewire_node = 0 ;
1241- if (session_cache_t::instance ().get_or_create_session (pipewire_fd, pipewire_node, width, height ) < 0 ) {
1247+ std::vector< pipewire_screenstream_t > pipewire_streams ;
1248+ if (session_cache_t::instance ().get_or_create_session (pipewire_fd, pipewire_streams ) < 0 ) {
12421249 return -1 ;
12431250 }
12441251
1252+ // If stream_index is out of the currently valid range, use the first display to stream
1253+ if (display_index < 0 || display_index >= pipewire_streams.size ()) {
1254+ BOOST_LOG (warning) << " Display index out of range (using 0): " sv << display_index;
1255+ display_index = 0 ;
1256+ }
1257+
1258+ // Select correct stream for requested display
1259+ int pipewire_node = pipewire_streams[display_index].pipewire_node ;
1260+ width = pipewire_streams[display_index].width ;
1261+ height = pipewire_streams[display_index].height ;
1262+ BOOST_LOG (info) << " [portalgrab] Using display " sv << display_index << " resolution: " sv << width << " x" sv << height;
1263+
12451264 framerate = config.framerate ;
12461265
12471266 if (!shared_state) {
@@ -1641,7 +1660,18 @@ namespace platf {
16411660
16421661 pw_init (nullptr , nullptr );
16431662
1644- display_names.emplace_back (" org.freedesktop.portal.Desktop" );
1663+ // TODO: Unsure if it is better to use session cache here. Querying directly will always yield uptodate results but could fail if only one portal is allowed.
1664+ if (dbus->connect_to_portal () < 0 ) {
1665+ BOOST_LOG (warning) << " [portalgrab] Failed to connect to portal. Cannot enumerate displays, returning empty list." ;
1666+ return {};
1667+ }
1668+ for (int x = 0 ; x < dbus->pipewire_streams .size (); ++x) {
1669+ auto display = dbus->pipewire_streams [x];
1670+ BOOST_LOG (info) << " [portalgrab] Found display " sv << x << " size: " sv << display.width << " x" sv << display.height ;
1671+ // TODO: It might be better to use screen position+resolution here to detect changes in portal but it's a lot complexer to match later
1672+ display_names.emplace_back (std::to_string (x));
1673+ }
1674+ // TODO: Check if we need to close the dbus/portal connection here or not (if not using session cache)
16451675 return display_names;
16461676 }
16471677} // namespace platf
0 commit comments