# Lessons Learned from Hyperion Grabber Wayland Adaptation This document summarizes the key challenges, debugging steps, and solutions encountered during the process of adapting the Hyperion Grabber for Wayland, specifically focusing on the `wayland_poc` executable. ## 1. Initial Problem & Diagnosis * **Problem:** The user's existing `Hyperion_Grabber_X11_QT` application was not logging "picture recorded and sent" messages when run on a Wayland session, indicating a failure in screen capture and transmission. * **Initial Analysis:** The grabber is designed for X11, relying on `XDamage` and other X11-specific features. Wayland's security model prevents direct screen access, requiring applications to use `xdg-desktop-portal` and PipeWire for screen sharing with user consent. * **Conclusion:** The X11 grabber would not work natively on Wayland. A Wayland-compatible screen grabbing solution was needed. ## 2. Wayland Grabber Adaptation Strategy * **Approach:** Replace the X11 screen grabbing logic with a Wayland-compatible one, primarily using PipeWire for video streaming and `xdg-desktop-portal` for user consent. * **Proof of Concept (POC):** Developed `wayland_poc.cpp` to test the `xdg-desktop-portal` interaction and PipeWire stream connection. Also used `tutorial5.c` from PipeWire documentation to verify core PipeWire API usage. ## 3. Build Environment Challenges & Docker Adoption * **Initial Host Compilation Issues:** Attempting to compile `wayland_poc.cpp` directly on the user's Arch Linux host resulted in a persistent `fatal error: pipewire/extensions/session-manager/session-manager.h: No such file or directory`. * **Troubleshooting:** Confirmed file existence and permissions, verified `pkg-config` output, modified `CMakeLists.txt` for include paths and C++ standards, tried different compilers (GCC). None resolved the issue. * **Conclusion:** The error was highly unusual and suggested a deep, system-specific problem with how PipeWire headers were exposed or how the compiler resolved includes on the host. * **Adoption of Docker:** Decided to use Docker to create a reproducible and controlled build environment, aiming to bypass host-specific compilation issues. ## 4. Docker Build Troubleshooting (Arch Linux Base) * **Dockerfile (Arch):** Initial Dockerfile used `archlinux:latest` as base. * **Error 1: `sudo: command not found`:** Occurred because `pacman` commands were run as `builder` user without `sudo` installed or configured. * **Fix:** Moved `pacman` commands to run as `root` before switching to `builder` user. * **Error 2: `mkdir: cannot create directory ‘build’: File exists` (Permission Denied):** Occurred because `build` directory was copied from host with `root` ownership, and `builder` user lacked permissions to modify it. * **Fix:** Added `chown -R builder:builder` after `COPY` to transfer ownership to `builder` user. * **Error 3: `CMakeCache.txt` mismatch:** Occurred because `CMakeCache.txt` from host's project root was copied into container, confusing CMake. * **Fix:** Added `CMakeCache.txt` and `CMakeFiles/` to `.dockerignore` to prevent them from being copied. * **Error 4: `X11/extensions/Xdamage.h: No such file or directory` (and `scrnsaver.h`, `Xrender.h`):** Occurred because necessary X11 development headers were missing in the Docker image. * **Fix:** Added `libx11`, `libxext`, `libxdamage`, `libxss`, `libxrender` to `pacman` install list. * **Persistent `session-manager.h` error:** Despite all fixes, the `fatal error: pipewire/extensions/session-manager/session-manager.h: No such file or directory` persisted even in the Arch Docker environment. This indicated the problem was not specific to the host Arch setup, but a deeper issue with PipeWire headers or their interaction with the compiler. ## 5. Docker Build Troubleshooting (Ubuntu Base & Clang) * **Switch to Ubuntu:** Decided to switch the Docker base image to `ubuntu:latest` to rule out Arch-specific packaging issues. Also switched to `clang` as the compiler. * **Error: `fatal error: 'pipewire/extensions/session-manager/impl-session-manager.h' file not found`:** The `session-manager.h` issue persisted, even with Ubuntu and Clang. This confirmed the problem was not distribution-specific. * **Attempt to bypass umbrella header:** Modified `wayland_poc.cpp` to include individual headers (`introspect.h`, `interfaces.h`, etc.) instead of `session-manager.h`. This also failed with similar "file not found" errors for the individual headers. * **Conclusion:** The `session-manager.h` (and related `impl-session-manager.h`) compilation issue is extremely persistent and baffling, suggesting a very subtle, low-level problem that cannot be resolved by standard means or remote debugging. ## 6. Refocusing on `xdg-desktop-portal` with `QDBus` * **Realization:** The `tutorial5.c` (core PipeWire API) compiled successfully. The `session-manager.h` problem was specific to the `xdg-desktop-portal` interaction using PipeWire's session manager headers. * **New Strategy:** Isolate the `xdg-desktop-portal` interaction using Qt's `QDBus` module, completely bypassing direct PipeWire session manager header includes. * **`wayland_poc.cpp` Refactoring:** Simplified `wayland_poc.cpp` to *only* handle the `QDBus` interaction to get the `pipewire_node_id`. Removed all PipeWire stream creation/processing logic. * **QDBus API Challenges:** * **`QDBusMessage::createMethodCall` vs `createMethod`:** Discovered `createMethodCall` is the correct static method for creating method call messages in Qt 5.15. * **`QDBusMessage` constructor:** Found that the direct constructor `QDBusMessage("service", "path", "interface", "method");` is the correct way to initialize `QDBusMessage` for method calls in the specific Qt5 version in Ubuntu. * **`QDBusPendingCall` conversion:** Ensured `sessionBus.asyncCall(message)` is used, which returns `QDBusPendingCall`. * **Successful Compilation:** The simplified `wayland_poc.cpp` (QDBus-only) compiled successfully in the Ubuntu Docker container with Clang. This is a major breakthrough, confirming that the `QDBus` approach for `xdg-desktop-portal` interaction is viable. ## 7. Runtime Challenges (D-Bus Connection) * **Problem:** Running the compiled `wayland_poc` executable (from Docker) on the host failed with `Failed to connect to D-Bus session bus.` * **Reason:** Docker containers are isolated and do not have direct access to the host's D-Bus session bus by default. Environment variables (`DBUS_SESSION_BUS_ADDRESS`, `XDG_RUNTIME_DIR`, `DISPLAY`, `WAYLAND_DISPLAY`) and volume mounts (`/tmp/.X11-unix`, `$XDG_RUNTIME_DIR`) are needed. * **Further Problem:** Even with correct `docker run` parameters, the `wayland_poc` on the host failed with `D-Bus call to xdg-desktop-portal failed: "Invalid session"`. * **Diagnosis:** This error indicates `xdg-desktop-portal` is not recognizing the session context. It's often related to `XDG_SESSION_ID`, `XDG_SESSION_TYPE`, or `XDG_CURRENT_DESKTOP` not being correctly propagated or interpreted. * **Method Name Mismatch:** The `wayland_poc` was initially calling `PickSource` on `org.freedesktop.portal.ScreenCast`, but the correct method name is `SelectSources`. * **Fix:** Changed method call from `PickSource` to `SelectSources` in `wayland_poc.cpp`. * **Argument Type Mismatch:** The `SelectSources` method expects an object path (`o`) for the `parent_window` argument, but `wayland_poc` was sending an empty string (`s`). * **Fix:** Changed the first argument to `QDBusObjectPath("/")` in `wayland_poc.cpp`. * **Current Status:** The `wayland_poc` executable now compiles successfully. The D-Bus connection issue (`Failed to connect to D-Bus session bus.` or `Invalid session`) is still occurring when run on the host, indicating a persistent runtime environment issue with D-Bus access from the application. ## 8. Next Steps * **Verify `wayland_poc` execution on host:** The user needs to run the `wayland_poc` executable on their host with the provided `docker run` command (or directly if copied out) and confirm if the `xdg-desktop-portal` dialog appears and a PipeWire node ID is printed. The current D-Bus connection failure needs to be resolved. * **Integrate:** If successful, the next phase will involve integrating the `QDBus` based `xdg-desktop-portal` interaction with the core PipeWire stream capture logic (from `tutorial5.c`) into the main Hyperion grabber. * **Persistent `session-manager.h`:** The original `session-manager.h` compilation issue remains unresolved for direct PipeWire session manager API usage. The `QDBus` approach is a workaround. If direct PipeWire session manager API interaction is ever needed, this issue would need further, likely local, investigation. ## 9. Recent Debugging and Solutions * **`SelectSources` Request Denied:** * **Problem:** After initial compilation, `wayland_poc`'s `SelectSources` call was denied by `xdg-desktop-portal`. * **Diagnosis:** The D-Bus message for `SelectSources` was missing required options (e.g., `types`, `cursor_mode`, `persist_mode`, `handle_token`) that are present in successful calls (e.g., from Firefox). * **Fix:** Modified `wayland_poc.cpp` to include these missing options in the `SelectSources` D-Bus message. * **Persistent `QDateTime` Compilation Error:** * **Problem:** Encountered a persistent "incomplete type 'QDateTime'" error during compilation, even though `` was included and its position was adjusted. * **Diagnosis:** This was a highly unusual and difficult-to-diagnose error, possibly related to subtle interactions within the Qt build system or compiler. * **Workaround:** Replaced all uses of `QDateTime::currentMSecsSinceEpoch()` with `QUuid::createUuid().toString()` for generating unique tokens, and added `#include `. This successfully bypassed the compilation error. * **Docker Filesystem Isolation and `replace` Tool Misunderstanding:** * **Problem:** Changes made to `wayland_poc.cpp` using the `replace` tool were not reflected in the Docker container's build process. * **Diagnosis:** The `replace` tool modifies the host's filesystem, while the Docker container operates on its own isolated filesystem. The container was building from an outdated copy of the source file. * **Fix:** After modifying `wayland_poc.cpp` on the host, the updated file was explicitly copied into the running Docker container using `docker cp`. * **Executable Retrieval from Docker Container:** * **Problem:** Difficulty in copying the built `wayland_poc` executable from the Docker container to the host. The build container would exit immediately, and `docker cp` failed to find the file. * **Diagnosis:** The original build container was not designed to stay running. `docker cp` requires a running container or a committed image. The initial `docker commit` did not seem to capture the build artifacts correctly. * **Fix:** Committed the original build container to a new image (`hyperion-grabber-build`). Then, a new container was launched from this image with a command (`tail -f /dev/null`) to keep it running. The executable was then successfully copied from this running container using `docker cp`. * **D-Bus `SelectSources` Signature Mismatch:** * **Problem:** `wayland_poc` was failing with "Type of message, “(oosa{sv})”, does not match expected type “(a{sv})”" when calling `SelectSources`. This occurred because the `handleSelectSourcesResponse` function, designed for `SelectSources` replies, was incorrectly connected to the `CreateSession` D-Bus call's `finished` signal. The `CreateSession` reply's signature (starting with an object path) was being misinterpreted, leading to an incorrect `SelectSources` call. * **Diagnosis:** The `QObject::connect` in `main` was incorrectly routing the `CreateSession` reply to the `handleSelectSourcesResponse` function. * **Fix:** 1. Created a new handler function, `handleCreateSessionFinished`, to specifically process the `CreateSession` reply. This function extracts the session handle and then correctly initiates the `SelectSources` D-Bus call with its own `QDBusPendingCallWatcher` connected to `handleSelectSourcesResponse`. 2. Modified the `main` function to connect the `CreateSession`'s `QDBusPendingCallWatcher` to `handleCreateSessionFinished`. * **`QDBusMessage::clearArguments()` Method Not Found:** * **Problem:** Compilation failed with an error indicating `QDBusMessage` had no member named `clearArguments()`. * **Diagnosis:** The `clearArguments()` method was removed in Qt 5.15, which is the version likely used in the Docker build environment. The call was also redundant as arguments were being cleared and then immediately re-added. * **Fix:** Removed the line `message.clearArguments();` from `wayland_poc.cpp`. * **D-Bus `CreateSession` Signature Mismatch:** * **Problem:** After fixing the `SelectSources` signature, the `CreateSession` call itself started failing with "Type of message, “(oosa{sv})”, does not match expected type “(a{sv})”". This indicated that `CreateSession` also expects only a single dictionary of options (`a{sv}`). * **Diagnosis:** The `xdg-desktop-portal` API for `CreateSession` had changed, and the `handlePath`, `sessionPath`, and `applicationName` arguments were no longer expected. * **Fix:** Modified the `CreateSession` call in `wayland_poc.cpp` to only send an empty `QVariantMap` as its argument. * **D-Bus `CreateSession` "Missing token" Error:** * **Problem:** After fixing the `CreateSession` signature, the call failed with a "Missing token" error. * **Diagnosis:** The `CreateSession` method, while expecting a single dictionary of options, also requires a `handle_token` within that dictionary. * **Fix:** Added a `handle_token` to the `QVariantMap` passed to the `CreateSession` call in `wayland_poc.cpp`. * **New Runtime Error: "Remote peer disconnected"** * **Problem:** After successfully building and copying `wayland_poc` to the host, running it resulted in "D-Bus call to SelectSources failed: "Remote peer disconnected"". * **Diagnosis:** This indicates a problem with the D-Bus connection itself, rather than a rejection from the portal. Possible causes include incorrect D-Bus environment variables on the host, `xdg-desktop-portal` not running, or permission issues. * **Next Steps:** Investigate D-Bus environment variables (`DBUS_SESSION_BUS_ADDRESS`) and `xdg-desktop-portal` service status on the host.