diff --git a/src/platform/linux/pipewire.cpp b/src/platform/linux/pipewire.cpp index a6a7ab6c9..3f10695ee 100644 --- a/src/platform/linux/pipewire.cpp +++ b/src/platform/linux/pipewire.cpp @@ -615,7 +615,46 @@ namespace pipewire { } } - virtual int configure_stream(const std::string &display_name, int &out_pipewire_fd, int &out_pipewire_node, int &out_pos_x, int &out_pos_y, int &out_width, int &out_height) = 0; + /** + * @brief Configure the pipewire stream + * @param display_name provide a stream for this display_name + * @param out_pipewire_fd set to the pipewire fd for the stream in during function call (or -1 for using the local context) + * @param out_pipewire_node set to the pipewire node of the stream in during function call + * @returns 0 if the stream successfully configured + */ + virtual int configure_stream(const std::string &display_name, int &out_pipewire_fd, int &out_pipewire_node) = 0; + + /** + * @brief Verify and update display parameters for logical dimensions, desktop dimensions and logical desktop dimensions (default is adapted from wlgrab) + */ + virtual void verify_and_update_display_parameters() { + // Set environment dimensions to stream dimensions (unless we find something better to report here) + if (env_height <= 0 || env_width <= 0) { + this->env_width = width; + this->env_height = height; + BOOST_LOG(debug) << "[pipewire] Desktop Resolution: "sv << env_width << 'x' << env_height; + } + // Query logical sizes directly using wayland wl::monitors() and match current screen based on offset/dimensions + if (logical_height <= 0 || logical_width <= 0 || env_logical_height <= 0 || env_logical_width <= 0) { + int desktop_logical_width = 0; + int desktop_logical_height = 0; + for (const auto &monitor : wl::monitors()) { + // If logical_width and logical_height are not valid try to update them to correct values by matching to monitor position/dimension or position/logical dimensions + // since we're iterating for maximum environment size anyway + if ((logical_width <= 0 || logical_height <= 0) && monitor->viewport.offset_x == offset_x && monitor->viewport.offset_y == offset_y && ((monitor->viewport.width == width && monitor->viewport.height == height) || (monitor->viewport.logical_width == width && monitor->viewport.logical_height == height))) { + this->logical_width = monitor->viewport.logical_width; + this->logical_height = monitor->viewport.logical_height; + BOOST_LOG(debug) << "[pipewire] Logical Resolution: "sv << logical_width << 'x' << logical_height; + } + // Update logical dimensions to setup maximum environment size over all screens + desktop_logical_width = std::max(desktop_logical_width, monitor->viewport.offset_x + monitor->viewport.logical_width); + desktop_logical_height = std::max(desktop_logical_height, monitor->viewport.offset_y + monitor->viewport.logical_height); + } + this->env_logical_width = std::max(env_logical_width, desktop_logical_width); + this->env_logical_height = std::max(env_logical_height, desktop_logical_height); + BOOST_LOG(debug) << "[pipewire] Logical Desktop Resolution: "sv << env_logical_width << 'x' << env_logical_height; + } + } int init(platf::mem_type_e hwdevice_type, const std::string &display_name, const ::video::config_t &config) { // calculate frame interval we should capture at @@ -638,14 +677,15 @@ namespace pipewire { int pipewire_fd = -1; int pipewire_node = -1; - int pos_x = -1; - int pos_y = -1; // Fetch stream info - if (configure_stream(display_name, pipewire_fd, pipewire_node, pos_x, pos_y, width, height) < 0) { + if (configure_stream(display_name, pipewire_fd, pipewire_node) < 0 || pipewire_node < 0) { BOOST_LOG(error) << "[pipewire] Could not find display with name: '"sv << display_name << "'"; return -1; } - BOOST_LOG(info) << "[pipewire] Streaming display '"sv << display_name << "' from position: "sv << pos_x << "x"sv << pos_y << " resolution: "sv << width << "x"sv << height; + BOOST_LOG(info) << "[pipewire] Streaming display '"sv << display_name << "' from position: "sv << offset_x << "x"sv << offset_y << " resolution: "sv << width << "x"sv << height; + + // Verify or update display parameters for streaming to ensure absolute touch inputs work as expected + verify_and_update_display_parameters(); framerate = config.framerate; @@ -668,10 +708,10 @@ namespace pipewire { return -1; } + // Wait for pipewire negotiation to finish so we have the proper negotiated dimensions int timeout_ms = 1500; int negotiated_w = 0; int negotiated_h = 0; - while (timeout_ms > 0) { negotiated_w = shared_state->negotiated_width.load(); negotiated_h = shared_state->negotiated_height.load(); @@ -681,22 +721,21 @@ namespace pipewire { std::this_thread::sleep_for(std::chrono::milliseconds(10)); timeout_ms -= 10; } - // Set width and height to the values negotiated by pipewire if (negotiated_w > 0 && negotiated_h > 0 && (negotiated_w != width || negotiated_h != height)) { - BOOST_LOG(info) << "[pipewire] Using negotiated resolution "sv - << negotiated_w << "x" << negotiated_h; - width = negotiated_w; height = negotiated_h; - } + BOOST_LOG(info) << "[pipewire] Using negotiated Resolution: "sv << width << "x" << height; - // Set env dimensions to match the captured display. - // Portal captures a single display, so the environment size equals the capture size. - // Without this, touch input is silently dropped because touch_port_t::operator bool() - // checks env_width and env_height are non-zero. - env_width = width; - env_height = height; + // Reset and update display parameters for negotiated resolution + env_width = 0; + env_height = 0; + logical_height = 0; + logical_width = 0; + env_logical_height = 0; + env_logical_width = 0; + verify_and_update_display_parameters(); + } return 0; } diff --git a/src/platform/linux/portalgrab.cpp b/src/platform/linux/portalgrab.cpp index 03f50b57c..1f845df7c 100644 --- a/src/platform/linux/portalgrab.cpp +++ b/src/platform/linux/portalgrab.cpp @@ -724,7 +724,7 @@ namespace portal { class portal_t: public pipewire::pipewire_display_t { public: - int configure_stream(const std::string &display_name, int &out_pipewire_fd, int &out_pipewire_node, int &out_pos_x, int &out_pos_y, int &out_width, int &out_height) override { + int configure_stream(const std::string &display_name, int &out_pipewire_fd, int &out_pipewire_node) override { // Connect DBus portal session if (dbus.init() < 0) { BOOST_LOG(error) << "[portalgrab] Failed to connect to dbus. portal_t setup failed."; @@ -759,13 +759,16 @@ namespace portal { // Restore global maxframerate negotiation state pipewire.set_negotiate_maxframerate(negotiate_maxframerate.load()); - // Return values + // Return values for pipewire init out_pipewire_fd = dbus.pipewire_fd; out_pipewire_node = stream.pipewire_node; - out_pos_x = stream.pos_x; - out_pos_y = stream.pos_y; - out_width = stream.width; - out_height = stream.height; + // Set/update basic stream parameters on display_t + this->offset_x = stream.pos_x; + this->offset_y = stream.pos_y; + this->width = stream.width; + this->height = stream.height; + this->logical_width = 0; // Explicitly mark for pipewire_display_t to try to figure this out. + this->logical_height = 0; // Explicitly Mark for pipewire_display_t to try to figure this out. // Flag successful setup return 0; }