Repository: electron/electron
Pull request: fix: Use XDG_ACTIVATION_TOKEN in wayland when launched by other app

When an electron app is launched by another app ensure that the XDG_ACTIVATION_TOKEN env var is read and used for activation using xdg_activation_v1 protocol.

#### Description of Change

Set the activation token received from XDG_ACTIVATION_TOKEN env var so that it is used to activate the window both for the first instance of an electron app as well a subsequent instance that uses [app.requestSingleInstanceLock()](https://www.electronjs.org/docs/latest/api/app#apprequestsingleinstancelockadditionaldata) to pass the control to an existing instance.

For reference, see:
- https://wayland.app/protocols/xdg-activation-v1
- https://issues.chromium.org/issues/40747285
- https://chromium-review.googlesource.com/c/chromium/src/+/5280365

Fixes an issue that still remains for https://github.com/electron/electron/issues/30912.

#### 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 electron app in ozone/wayland not being focused when launched from another app


Changed files:
filename: shell/app/electron_main_delegate.cc
patch: @@ -406,6 +406,11 @@ std::optional<int> ElectronMainDelegate::PreBrowserMain() {
   content::InitializeMojoCore();
 #if BUILDFLAG(IS_MAC)
   RegisterAtomCrApp();
+#endif
+#if BUILDFLAG(IS_LINUX)
+  // Set the global activation token sent as an environment variable.
+  auto env = base::Environment::Create();
+  base::nix::ExtractXdgActivationTokenFromEnv(*env);
 #endif
   return std::nullopt;
 }

filename: shell/browser/api/electron_api_app.cc
patch: @@ -92,6 +92,11 @@
 #include "shell/browser/ui/cocoa/electron_bundle_mover.h"
 #endif
 
+#if BUILDFLAG(IS_LINUX)
+#include "base/nix/scoped_xdg_activation_token_injector.h"
+#include "base/nix/xdg_util.h"
+#endif
+
 using electron::Browser;
 
 namespace gin {
@@ -411,6 +416,12 @@ bool NotificationCallbackWrapper(
     base::CommandLine cmd,
     const base::FilePath& cwd,
     const std::vector<uint8_t> additional_data) {
+#if BUILDFLAG(IS_LINUX)
+  // Set the global activation token sent as a command line switch by another
+  // electron app instance. This also removes the switch after use to prevent
+  // any side effects of leaving it in the command line after this point.
+  base::nix::ExtractXdgActivationTokenFromCmdLine(cmd);
+#endif
   // Make sure the callback is called after app gets ready.
   if (Browser::Get()->is_ready()) {
     callback.Run(std::move(cmd), cwd, std::move(additional_data));
@@ -1022,6 +1033,15 @@ bool App::RequestSingleInstanceLock(gin::Arguments* args) {
       base::BindRepeating(NotificationCallbackWrapper, cb));
 #endif
 
+#if BUILDFLAG(IS_LINUX)
+  // Read the xdg-activation token and set it in the command line for the
+  // duration of the notification in order to ensure this is propagated to an
+  // already running electron app instance if it exists.
+  // The activation token received from the launching app is used later when
+  // activating the existing electron app instance window.
+  base::nix::ScopedXdgActivationTokenInjector activation_token_injector(
+      *base::CommandLine::ForCurrentProcess(), *base::Environment::Create());
+#endif
   switch (process_singleton_->NotifyOtherProcessOrCreate()) {
     case ProcessSingleton::NotifyResult::PROCESS_NONE:
       if (content::BrowserThread::IsThreadInitialized(