Repository: electron/electron
Pull request: fix: check screen capture permissions in `desktopCapturer`

#### Description of Change

Closes https://github.com/electron/electron/issues/42143.

Resolves an issue following https://github.com/electron/electron/pull/41403 where `desktopCapturer.getSources` never resolves unless the user grants permissions on macOS.

This handles the issue by pre-emptively checking whether the user has granted permissions and rejects the promise if no permissions have been granted. `TryPromptUserForScreenCapture` plumbs down to `CGRequestScreenCaptureAccess()`, which is a (poorly documented) function that prompts for access if the user has not yet been prompted and returns false immediately. It then will return true or false without prompting if the user has either granted access or been previously prompted and chosen not to grant access.

#### Checklist
<!-- Remove items that do not apply. For completed items, change [ ] to [x]. -->

- [x] PR description included and stakeholders cc'd
- [x] `npm test` passes
- [x] [PR release notes](https://github.com/electron/clerk/blob/main/README.md) describe the change in a way relevant to app developers, and are [capitalized, punctuated, and past tense](https://github.com/electron/clerk/blob/main/README.md#examples).

#### Release Notes

Notes: Resolved an issue where `desktopCapturer.getSources` never fulfilled its promise in some cases.

Changed files:
filename: shell/browser/api/electron_api_desktop_capturer.cc
patch: @@ -42,6 +42,10 @@
 #include "ui/gfx/x/randr.h"
 #endif
 
+#if BUILDFLAG(IS_MAC)
+#include "ui/base/cocoa/permissions_utils.h"
+#endif
+
 #if BUILDFLAG(IS_LINUX)
 // Private function in ui/base/x/x11_display_util.cc
 base::flat_map<x11::RandR::Output, int> GetMonitors(
@@ -305,6 +309,13 @@ void DesktopCapturer::StartHandling(bool capture_window,
   capture_window_ = capture_window;
   capture_screen_ = capture_screen;
 
+#if BUILDFLAG(IS_MAC)
+  if (!ui::TryPromptUserForScreenCapture()) {
+    HandleFailure();
+    return;
+  }
+#endif
+
   {
     // Initialize the source list.
     // Apply the new thumbnail size and restart capture.
@@ -456,21 +467,25 @@ void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) {
               std::back_inserter(captured_sources_));
   }
 
-  if (!capture_window_ && !capture_screen_) {
-    v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
-    v8::HandleScope scope(isolate);
-    gin_helper::CallMethod(this, "_onfinished", captured_sources_);
+  if (!capture_window_ && !capture_screen_)
+    HandleSuccess();
+}
+
+void DesktopCapturer::HandleSuccess() {
+  v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
+  v8::HandleScope scope(isolate);
+  gin_helper::CallMethod(this, "_onfinished", captured_sources_);
 
-    screen_capturer_.reset();
-    window_capturer_.reset();
+  screen_capturer_.reset();
+  window_capturer_.reset();
 
-    Unpin();
-  }
+  Unpin();
 }
 
 void DesktopCapturer::HandleFailure() {
   v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
   v8::HandleScope scope(isolate);
+
   gin_helper::CallMethod(this, "_onerror", "Failed to get sources.");
 
   screen_capturer_.reset();

filename: shell/browser/api/electron_api_desktop_capturer.h
patch: @@ -94,6 +94,7 @@ class DesktopCapturer : public gin::Wrappable<DesktopCapturer>,
 
   void UpdateSourcesList(DesktopMediaList* list);
   void HandleFailure();
+  void HandleSuccess();
 
   std::unique_ptr<DesktopListListener> window_listener_;
   std::unique_ptr<DesktopListListener> screen_listener_;