PipeWire capture: hide cursor when it goes off screen or is not visible

Set cursor position to (-1,-1) to indicate it's not valid when it goes
off the screen or it gets hidden by the compositor. Compositors indicate
invalid or hidden cursor by unsetting the cursor id in cursor metadata
and using spa_meta_cursor_is_valid() will tell us the needed information
for this.

Bug: chromium:346608851
Change-Id: I71b3222ca161b7fd8e964f4f4e12b9983179beba
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/355080
Reviewed-by: Alexander Cooper <alcooper@chromium.org>
Commit-Queue: Jan Grulich <grulja@gmail.com>
Cr-Commit-Position: refs/heads/main@{#42548}
diff --git a/modules/desktop_capture/linux/wayland/mouse_cursor_monitor_pipewire.cc b/modules/desktop_capture/linux/wayland/mouse_cursor_monitor_pipewire.cc
index 3d33b0f..00b07f3 100644
--- a/modules/desktop_capture/linux/wayland/mouse_cursor_monitor_pipewire.cc
+++ b/modules/desktop_capture/linux/wayland/mouse_cursor_monitor_pipewire.cc
@@ -40,6 +40,14 @@
   RTC_DCHECK_RUN_ON(&sequence_checker_);
   RTC_DCHECK(callback_);
 
+  absl::optional<DesktopVector> mouse_cursor_position =
+      options_.screencast_stream()->CaptureCursorPosition();
+  // Invalid cursor or position
+  if (!mouse_cursor_position) {
+    callback_->OnMouseCursor(nullptr);
+    return;
+  }
+
   std::unique_ptr<MouseCursor> mouse_cursor =
       options_.screencast_stream()->CaptureCursor();
 
@@ -48,11 +56,7 @@
   }
 
   if (mode_ == SHAPE_AND_POSITION) {
-    absl::optional<DesktopVector> mouse_cursor_position =
-        options_.screencast_stream()->CaptureCursorPosition();
-    if (mouse_cursor_position) {
-      callback_->OnMouseCursorPosition(mouse_cursor_position.value());
-    }
+    callback_->OnMouseCursorPosition(mouse_cursor_position.value());
   }
 }
 
diff --git a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc
index 90273ab..047ad5a 100644
--- a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc
+++ b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc
@@ -680,32 +680,38 @@
     const struct spa_meta_cursor* cursor =
         static_cast<struct spa_meta_cursor*>(spa_buffer_find_meta_data(
             spa_buffer, SPA_META_Cursor, sizeof(*cursor)));
-    if (cursor && spa_meta_cursor_is_valid(cursor)) {
-      struct spa_meta_bitmap* bitmap = nullptr;
 
-      if (cursor->bitmap_offset)
-        bitmap =
-            SPA_MEMBER(cursor, cursor->bitmap_offset, struct spa_meta_bitmap);
+    if (cursor) {
+      if (spa_meta_cursor_is_valid(cursor)) {
+        struct spa_meta_bitmap* bitmap = nullptr;
 
-      if (bitmap && bitmap->size.width > 0 && bitmap->size.height > 0) {
-        const uint8_t* bitmap_data =
-            SPA_MEMBER(bitmap, bitmap->offset, uint8_t);
-        BasicDesktopFrame* mouse_frame = new BasicDesktopFrame(
-            DesktopSize(bitmap->size.width, bitmap->size.height));
-        mouse_frame->CopyPixelsFrom(
-            bitmap_data, bitmap->stride,
-            DesktopRect::MakeWH(bitmap->size.width, bitmap->size.height));
-        mouse_cursor_ = std::make_unique<MouseCursor>(
-            mouse_frame, DesktopVector(cursor->hotspot.x, cursor->hotspot.y));
+        if (cursor->bitmap_offset)
+          bitmap =
+              SPA_MEMBER(cursor, cursor->bitmap_offset, struct spa_meta_bitmap);
+
+        if (bitmap && bitmap->size.width > 0 && bitmap->size.height > 0) {
+          const uint8_t* bitmap_data =
+              SPA_MEMBER(bitmap, bitmap->offset, uint8_t);
+          BasicDesktopFrame* mouse_frame = new BasicDesktopFrame(
+              DesktopSize(bitmap->size.width, bitmap->size.height));
+          mouse_frame->CopyPixelsFrom(
+              bitmap_data, bitmap->stride,
+              DesktopRect::MakeWH(bitmap->size.width, bitmap->size.height));
+          mouse_cursor_ = std::make_unique<MouseCursor>(
+              mouse_frame, DesktopVector(cursor->hotspot.x, cursor->hotspot.y));
+
+          if (observer_) {
+            observer_->OnCursorShapeChanged();
+          }
+        }
+        mouse_cursor_position_.set(cursor->position.x, cursor->position.y);
 
         if (observer_) {
-          observer_->OnCursorShapeChanged();
+          observer_->OnCursorPositionChanged();
         }
-      }
-      mouse_cursor_position_.set(cursor->position.x, cursor->position.y);
-
-      if (observer_) {
-        observer_->OnCursorPositionChanged();
+      } else {
+        // Indicate an invalid cursor
+        mouse_cursor_position_.set(-1, -1);
       }
     }
   }