Skip to content

Commit 5aec74c

Browse files
committed
refactor(linux/xdgportal): Unify display_name generation/matching in pipewire_streaminfo_t
Reduce complexity in other code parts and have the display_name generation/matching done next to each other for better maintainability.
1 parent 9d5a610 commit 5aec74c

1 file changed

Lines changed: 58 additions & 63 deletions

File tree

src/platform/linux/portalgrab.cpp

Lines changed: 58 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,45 @@ namespace portal {
180180
int pos_x;
181181
int pos_y;
182182
std::string monitor_name;
183+
184+
std::string to_display_name() {
185+
if (monitor_name.length() > 0) {
186+
return std::format("n{}", monitor_name);
187+
}
188+
return std::format("p{},{},{},{}", pos_x, pos_y, width, height);
189+
}
190+
bool match_display_name(const std::string &display_name) const{
191+
// Empty display_name never matches
192+
if (display_name.empty()) {
193+
return false;
194+
}
195+
// Method 1: Display_name starts with 'n' match by monitor_name starting from pos 1
196+
if (display_name[0] == 'n') {
197+
return display_name.substr(1) == monitor_name;
198+
}
199+
// Method 2: Display_name starts with 'p' match by position+resolution starting from pos 1
200+
if (display_name[0] == 'p') {
201+
auto stringstream = std::stringstream(display_name.substr(1));
202+
std::string stringvalue;
203+
std::vector<int> values;
204+
constexpr char display_name_delimiter = ',';
205+
while (std::getline(stringstream, stringvalue, display_name_delimiter)) {
206+
if (std::ranges::all_of(stringvalue, ::isdigit)) {
207+
values.emplace_back(std::stoi(stringvalue));
208+
} else {
209+
BOOST_LOG(debug) << "[portalgrab] Failed to parse int value: '"sv << stringvalue << "'";
210+
}
211+
}
212+
// Check if the vector has 4 values (pos_x, pos_y, width, height) from display_names formatting
213+
if (values.size() != 4) {
214+
BOOST_LOG(debug) << "[portalgrab] Display name does not match expected format 'x,y,w,h': '"sv << display_name << "'";
215+
return false;
216+
}
217+
return pos_x == values[0] && pos_y == values[1] && width == values[2] && height == values[3];
218+
}
219+
// All matching methods have failed. No match!
220+
return false;
221+
}
183222
};
184223

185224
class dbus_t {
@@ -1316,9 +1355,17 @@ namespace portal {
13161355
return -1;
13171356
}
13181357
// Match display_name to a stream from the pipewire_streams vector
1319-
pipewire_streaminfo_t stream = match_display_name_to_stream(pipewire_streams, display_name);
1358+
bool use_fallback = true;
1359+
pipewire_streaminfo_t stream;
1360+
for (const auto &stream_ : pipewire_streams) {
1361+
if (stream_.match_display_name(display_name)) {
1362+
stream = stream_;
1363+
use_fallback = false;
1364+
break;
1365+
}
1366+
}
13201367
// Fall back to first stream if we cannot match the given display_name to a stream in currently available streams.
1321-
if (stream.width < 0 || stream.height < 0) {
1368+
if (use_fallback) {
13221369
BOOST_LOG(info) << "[portalgrab] Using first available stream as no matching stream was found for: '"sv << display_name << "'";
13231370
stream = pipewire_streams[0];
13241371
}
@@ -1681,50 +1728,6 @@ namespace portal {
16811728
return 0;
16821729
}
16831730

1684-
static pipewire_streaminfo_t match_display_name_to_stream(const std::vector<pipewire_streaminfo_t> &pipewire_streams, const std::string &display_name) {
1685-
const auto invalid_stream = pipewire_streaminfo_t {-1, -1, -1, -1, -1};
1686-
// Empty display_names cannot be mapped to a valid stream
1687-
if (display_name.empty()) {
1688-
return invalid_stream;
1689-
}
1690-
// Display_name starts with 'n' match by monitor_name starting from pos 1
1691-
if (!display_name.empty() && display_name[0] == 'n') {
1692-
auto monitor_name = display_name.substr(1);
1693-
for (const auto &stream : pipewire_streams) {
1694-
if (stream.monitor_name == monitor_name) {
1695-
return stream;
1696-
}
1697-
}
1698-
}
1699-
// Display_name starts with 'p' match by position+resolution starting from pos 1
1700-
if (!display_name.empty() && display_name[0] == 'p') {
1701-
auto stringstream = std::stringstream(display_name.substr(1));
1702-
std::string stringvalue;
1703-
std::vector<int> values;
1704-
constexpr char display_name_delimiter = ',';
1705-
while (std::getline(stringstream, stringvalue, display_name_delimiter)) {
1706-
if (std::ranges::all_of(stringvalue, ::isdigit)) {
1707-
values.emplace_back(std::stoi(stringvalue));
1708-
} else {
1709-
BOOST_LOG(warning) << "[portalgrab] Failed to parse int value: '"sv << stringvalue << "'";
1710-
}
1711-
}
1712-
// Check if the vector has 4 values (pos_x, pos_y, width, height) from display_names formatting
1713-
if (values.size() != 4) {
1714-
BOOST_LOG(warning) << "[portalgrab] Display name does not match expected format 'x,y,w,h': '"sv << display_name << "'";
1715-
return invalid_stream;
1716-
}
1717-
// Determine correct pipewire_node by iterating pipewire_streams and matching position and resolution
1718-
for (const auto &stream : pipewire_streams) {
1719-
if (stream.pos_x == values[0] && stream.pos_y == values[1] && stream.width == values[2] && stream.height == values[3]) {
1720-
return stream;
1721-
}
1722-
}
1723-
}
1724-
// If we reach this point, no matching stream was found.
1725-
return invalid_stream;
1726-
}
1727-
17281731
platf::mem_type_e mem_type;
17291732
wl::display_t wl_display;
17301733
pipewire_t pipewire;
@@ -1758,21 +1761,6 @@ namespace platf {
17581761
return portal;
17591762
}
17601763

1761-
std::vector<std::string> portal_streams_to_display_names(const std::vector<portal::pipewire_streaminfo_t> &pipewire_streams, const bool log) {
1762-
std::vector<std::string> display_names;
1763-
for (auto stream : pipewire_streams) {
1764-
if (log) {
1765-
BOOST_LOG(info) << "[portalgrab] Found stream for display: '"sv << stream.monitor_name << "' position: "sv << stream.pos_x << "x"sv << stream.pos_y << " resolution: "sv << stream.width << "x"sv << stream.height;
1766-
}
1767-
if (stream.monitor_name.length() > 0) {
1768-
display_names.emplace_back(std::format("n{}", stream.monitor_name));
1769-
} else {
1770-
display_names.emplace_back(std::format("p{},{},{},{}", stream.pos_x, stream.pos_y, stream.width, stream.height));
1771-
}
1772-
}
1773-
return display_names;
1774-
}
1775-
17761764
std::vector<std::string> portal_display_names() {
17771765
auto dbus = std::make_shared<portal::dbus_t>();
17781766

@@ -1787,14 +1775,21 @@ namespace platf {
17871775
BOOST_LOG(warning) << "[portalgrab] Failed to connect to portal. Cannot enumerate displays, returning empty list.";
17881776
return {};
17891777
}
1790-
std::vector<std::string> dbus_display_names = portal_streams_to_display_names(dbus->pipewire_streams, true);
1778+
std::vector<std::string> dbus_display_names;
1779+
for (auto stream_ : dbus->pipewire_streams) {
1780+
BOOST_LOG(info) << "[portalgrab] Found stream for display: '"sv << stream_.monitor_name << "' position: "sv << stream_.pos_x << "x"sv << stream_.pos_y << " resolution: "sv << stream_.width << "x"sv << stream_.height;
1781+
dbus_display_names.emplace_back(stream_.to_display_name());
1782+
}
17911783
// Release the new portal as soon as possible to properly release related resources early.
17921784
dbus.reset();
17931785
// Get all display_names from cache
17941786
int cache_pipewire_fd;
17951787
std::vector<portal::pipewire_streaminfo_t> cache_pipewire_streams;
17961788
portal::session_cache_t::instance().get_or_create_session(cache_pipewire_fd, cache_pipewire_streams);
1797-
std::vector<std::string> cache_display_names = portal_streams_to_display_names(cache_pipewire_streams, false);
1789+
std::vector<std::string> cache_display_names;
1790+
for (auto stream_ : cache_pipewire_streams) {
1791+
cache_display_names.emplace_back(stream_.to_display_name());
1792+
}
17981793
// Close the unused duplicated pipewire_fd from get_or_create_session
17991794
close(cache_pipewire_fd);
18001795
// Compare dbus with cache display names and invalidate the cache if things differ

0 commit comments

Comments
 (0)