fd15a75
diff -up thunderbird-102.6.0/widget/gtk/WidgetUtilsGtk.cpp.D165150 thunderbird-102.6.0/widget/gtk/WidgetUtilsGtk.cpp
fd15a75
--- thunderbird-102.6.0/widget/gtk/WidgetUtilsGtk.cpp.D165150	2022-12-12 22:37:39.000000000 +0100
fd15a75
+++ thunderbird-102.6.0/widget/gtk/WidgetUtilsGtk.cpp	2022-12-20 14:43:29.742482848 +0100
fd15a75
@@ -9,11 +9,20 @@
fd15a75
 #include "mozilla/UniquePtr.h"
fd15a75
 #include "nsReadableUtils.h"
fd15a75
 #include "nsWindow.h"
fd15a75
+#include "nsGtkKeyUtils.h"
fd15a75
 
fd15a75
 #include <gtk/gtk.h>
fd15a75
 #include <dlfcn.h>
fd15a75
 #include <glib.h>
fd15a75
 
fd15a75
+#ifdef MOZ_LOGGING
fd15a75
+#  include "mozilla/Logging.h"
fd15a75
+extern mozilla::LazyLogModule gWidgetLog;
fd15a75
+#  define LOGW(...) MOZ_LOG(gWidgetLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
fd15a75
+#else
fd15a75
+#  define LOGW(...)
fd15a75
+#endif /* MOZ_LOGGING */
fd15a75
+
fd15a75
 namespace mozilla::widget {
fd15a75
 
fd15a75
 int32_t WidgetUtilsGTK::IsTouchDeviceSupportPresent() {
fd15a75
@@ -165,4 +174,108 @@ nsTArray<nsCString> ParseTextURIList(con
fd15a75
   return result;
fd15a75
 }
fd15a75
 
fd15a75
+#ifdef MOZ_WAYLAND
fd15a75
+static gboolean token_failed(gpointer aData);
fd15a75
+
fd15a75
+class XDGTokenRequest {
fd15a75
+ public:
fd15a75
+  void SetTokenID(const char* aTokenID) {
fd15a75
+    mTransferPromise->Resolve(aTokenID, __func__);
fd15a75
+  }
fd15a75
+  void Cancel() {
fd15a75
+    mTransferPromise->Reject(false, __func__);
fd15a75
+    mActivationTimeoutID = 0;
fd15a75
+  }
fd15a75
+
fd15a75
+  XDGTokenRequest(xdg_activation_token_v1* aXdgToken,
fd15a75
+                  RefPtr<FocusRequestPromise::Private> aTransferPromise)
fd15a75
+      : mXdgToken(aXdgToken), mTransferPromise(aTransferPromise) {
fd15a75
+    mActivationTimeoutID =
fd15a75
+        g_timeout_add(sActivationTimeout, token_failed, this);
fd15a75
+  }
fd15a75
+  ~XDGTokenRequest() {
fd15a75
+    if (mXdgToken) {
fd15a75
+       xdg_activation_token_v1_destroy(mXdgToken);
fd15a75
+     }
fd15a75
+    if (mActivationTimeoutID) {
fd15a75
+      g_source_remove(mActivationTimeoutID);
fd15a75
+    }
fd15a75
+  }
fd15a75
+
fd15a75
+ private:
fd15a75
+  xdg_activation_token_v1* mXdgToken;
fd15a75
+  RefPtr<FocusRequestPromise::Private> mTransferPromise;
fd15a75
+  guint mActivationTimeoutID;
fd15a75
+  // Reject FocusRequestPromise if we don't get XDG token in 0.5 sec.
fd15a75
+  const int sActivationTimeout = 500;
fd15a75
+};
fd15a75
+
fd15a75
+// Failed to get token in time
fd15a75
+static gboolean token_failed(gpointer data) {
fd15a75
+  UniquePtr<XDGTokenRequest> request(static_cast<XDGTokenRequest*>(data));
fd15a75
+  request->Cancel();
fd15a75
+  return false;
fd15a75
+}
fd15a75
+
fd15a75
+// We've got activation token from Wayland compositor so it's time to use it.
fd15a75
+static void token_done(gpointer data, struct xdg_activation_token_v1* provider,
fd15a75
+                       const char* tokenID) {
fd15a75
+  UniquePtr<XDGTokenRequest> request(static_cast<XDGTokenRequest*>(data));
fd15a75
+  request->SetTokenID(tokenID);
fd15a75
+}
fd15a75
+
fd15a75
+static const struct xdg_activation_token_v1_listener token_listener = {
fd15a75
+    token_done,
fd15a75
+};
fd15a75
+
fd15a75
+RefPtr<FocusRequestPromise> RequestWaylandFocus() {
fd15a75
+  RefPtr<nsWindow> sourceWindow = nsWindow::GetFocusedWindow();
fd15a75
+  if (!sourceWindow) {
fd15a75
+    return nullptr;
fd15a75
+  }
fd15a75
+
fd15a75
+  RefPtr<nsWaylandDisplay> display = WaylandDisplayGet();
fd15a75
+  xdg_activation_v1* xdg_activation = display->GetXdgActivation();
fd15a75
+  if (!xdg_activation) {
fd15a75
+    return nullptr;
fd15a75
+  }
fd15a75
+
fd15a75
+  wl_surface* focusSurface;
fd15a75
+  uint32_t focusSerial;
fd15a75
+  KeymapWrapper::GetFocusInfo(&focusSurface, &focusSerial);
fd15a75
+  if (!focusSurface) {
fd15a75
+    return nullptr;
fd15a75
+  }
fd15a75
+
fd15a75
+  GdkWindow* gdkWindow = gtk_widget_get_window(sourceWindow->GetGtkWidget());
fd15a75
+  if (!gdkWindow) {
fd15a75
+    return nullptr;
fd15a75
+  }
fd15a75
+  wl_surface* surface = gdk_wayland_window_get_wl_surface(gdkWindow);
fd15a75
+  if (focusSurface != surface) {
fd15a75
+    return nullptr;
fd15a75
+  }
fd15a75
+
fd15a75
+  RefPtr<FocusRequestPromise::Private> transferPromise =
fd15a75
+      new FocusRequestPromise::Private(__func__);
fd15a75
+
fd15a75
+  xdg_activation_token_v1* aXdgToken =
fd15a75
+      xdg_activation_v1_get_activation_token(xdg_activation);
fd15a75
+  xdg_activation_token_v1_add_listener(
fd15a75
+      aXdgToken, &token_listener,
fd15a75
+      new XDGTokenRequest(aXdgToken, transferPromise));
fd15a75
+  xdg_activation_token_v1_set_serial(aXdgToken, focusSerial,
fd15a75
+                                     KeymapWrapper::GetSeat());
fd15a75
+  xdg_activation_token_v1_set_surface(aXdgToken, focusSurface);
fd15a75
+  xdg_activation_token_v1_commit(aXdgToken);
fd15a75
+
fd15a75
+  return transferPromise.forget();
fd15a75
+}
fd15a75
+
fd15a75
+bool CanTransferWaylandFocus() {
fd15a75
+  return GdkIsWaylandDisplay() && nsWindow::GetFocusedWindow() &&
fd15a75
+         !nsWindow::GetFocusedWindow()->IsDestroyed();
fd15a75
+}
fd15a75
+#endif
fd15a75
+
fd15a75
 }  // namespace mozilla::widget
fd15a75
diff -up thunderbird-102.6.0/widget/gtk/WidgetUtilsGtk.h.D165150 thunderbird-102.6.0/widget/gtk/WidgetUtilsGtk.h
fd15a75
--- thunderbird-102.6.0/widget/gtk/WidgetUtilsGtk.h.D165150	2022-12-12 22:37:41.000000000 +0100
fd15a75
+++ thunderbird-102.6.0/widget/gtk/WidgetUtilsGtk.h	2022-12-20 13:44:15.343638003 +0100
fd15a75
@@ -8,11 +8,13 @@
fd15a75
 
fd15a75
 #include "nsString.h"
fd15a75
 #include "nsTArray.h"
fd15a75
+#include "mozilla/MozPromise.h"
fd15a75
 
fd15a75
 #include <stdint.h>
fd15a75
 
fd15a75
 typedef struct _GdkDisplay GdkDisplay;
fd15a75
 typedef struct _GdkDevice GdkDevice;
fd15a75
+class nsWindow;
fd15a75
 
fd15a75
 namespace mozilla::widget {
fd15a75
 
fd15a75
@@ -51,6 +53,12 @@ bool ShouldUsePortal(PortalKind);
fd15a75
 // Parse text/uri-list
fd15a75
 nsTArray<nsCString> ParseTextURIList(const nsACString& data);
fd15a75
 
fd15a75
+#ifdef MOZ_WAYLAND
fd15a75
+using FocusRequestPromise = mozilla::MozPromise<nsCString, bool, false>;
fd15a75
+bool CanTransferWaylandFocus();
fd15a75
+RefPtr<FocusRequestPromise> RequestWaylandFocus();
fd15a75
+#endif
fd15a75
+
fd15a75
 }  // namespace mozilla::widget
fd15a75
 
fd15a75
 #endif  // WidgetUtilsGtk_h__