Repository: electron/electron
Pull request: fix: Launch apps with XDG_ACTIVATION_TOKEN in ozone/wayland

Ensure apps are launched with the activation token received from xdg_activation_v1 protocol.

#### Description of Change

Retrieve the activation token from xdg_activation_v1 protocol when running with ozone/wayland
backend and pass it to the launched app via `XDG_ACTIVATION_TOKEN` environment variable.

For reference, see:
- https://wayland.app/protocols/xdg-activation-v1
- https://issues.chromium.org/issues/40747285
- https://chromium-review.googlesource.com/c/chromium/src/+/5331811

Fixes an issue that still remains for https://github.com/electron/electron/issues/30912.

<!--
Thank you for your Pull Request. Please provide a description above and review
the requirements below.

Contributors guide: https://github.com/electron/electron/blob/main/CONTRIBUTING.md
-->

#### 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
- [ ] tests are [changed or added](https://github.com/electron/electron/blob/main/docs/development/testing.md)
- [ ] relevant documentation, tutorials, templates and examples are changed or added
- [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: Fixed other apps not being focused when launched from electron ozone/wayland


Changed files:
filename: shell/common/platform_util_linux.cc
patch: @@ -23,6 +23,7 @@
 #include "base/posix/eintr_wrapper.h"
 #include "base/process/kill.h"
 #include "base/process/launch.h"
+#include "base/run_loop.h"
 #include "base/strings/escape.h"
 #include "base/strings/string_util.h"
 #include "base/threading/thread_restrictions.h"
@@ -270,8 +271,21 @@ std::string GetErrorDescription(int error_code) {
 bool XDGUtil(const std::vector<std::string>& argv,
              const base::FilePath& working_directory,
              const bool wait_for_exit,
+             const bool focus_launched_process,
              platform_util::OpenCallback callback) {
   base::LaunchOptions options;
+  if (focus_launched_process) {
+    base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+    base::RepeatingClosure quit_loop = run_loop.QuitClosure();
+    base::nix::CreateLaunchOptionsWithXdgActivation(base::BindOnce(
+        [](base::RepeatingClosure quit_loop, base::LaunchOptions* options_out,
+           base::LaunchOptions options) {
+          *options_out = std::move(options);
+          std::move(quit_loop).Run();
+        },
+        std::move(quit_loop), &options));
+    run_loop.Run();
+  }
   options.current_directory = working_directory;
   options.allow_new_privs = true;
   // xdg-open can fall back on mailcap which eventually might plumb through
@@ -303,11 +317,12 @@ bool XDGOpen(const base::FilePath& working_directory,
              const bool wait_for_exit,
              platform_util::OpenCallback callback) {
   return XDGUtil({"xdg-open", path}, working_directory, wait_for_exit,
-                 std::move(callback));
+                 /*focus_launched_process=*/true, std::move(callback));
 }
 
 bool XDGEmail(const std::string& email, const bool wait_for_exit) {
   return XDGUtil({"xdg-email", email}, base::FilePath(), wait_for_exit,
+                 /*focus_launched_process=*/true,
                  platform_util::OpenCallback());
 }
 
@@ -376,7 +391,8 @@ bool MoveItemToTrash(const base::FilePath& full_path, bool delete_on_fail) {
     argv = {"gio", "trash", filename};
   }
 
-  return XDGUtil(argv, base::FilePath(), true, platform_util::OpenCallback());
+  return XDGUtil(argv, base::FilePath(), true, /*focus_launched_process=*/false,
+                 platform_util::OpenCallback());
 }
 
 namespace internal {