diff --git a/ui/platform/linux/ui_utility_linux.cpp b/ui/platform/linux/ui_utility_linux.cpp index 2479325..76bb270 100644 --- a/ui/platform/linux/ui_utility_linux.cpp +++ b/ui/platform/linux/ui_utility_linux.cpp @@ -9,8 +9,9 @@ #include "base/platform/base_platform_info.h" #include "base/platform/linux/base_linux_glibmm_helper.h" #include "base/platform/linux/base_linux_xdp_utilities.h" -#include "ui/platform/linux/ui_linux_wayland_integration.h" +#include "base/call_delayed.h" #include "base/const_string.h" +#include "ui/platform/linux/ui_linux_wayland_integration.h" #ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION #include "base/platform/linux/base_linux_xcb_utilities.h" @@ -26,6 +27,10 @@ namespace Platform { namespace { constexpr auto kXCBFrameExtentsAtomName = "_GTK_FRAME_EXTENTS"_cs; +constexpr auto kDelayDeactivateEventTimeout = crl::time(400); + +bool PendingDeactivateEvent/* = false*/; +int ChildPopupsHiddenOnWayland/* = 0*/; #ifndef DESKTOP_APP_DISABLE_X11_INTEGRATION std::optional XCBWindowMapped(xcb_window_t window) { @@ -548,6 +553,34 @@ void ShowWindowMenu(not_null widget, const QPoint &point) { } } +void RegisterChildPopupHiding() { + if (!::Platform::IsWayland()) { + return; + } + ++ChildPopupsHiddenOnWayland; + base::call_delayed(kDelayDeactivateEventTimeout, [] { + if (!--ChildPopupsHiddenOnWayland) { + if (base::take(PendingDeactivateEvent)) { + // We didn't receive ApplicationActivate event in time. + QEvent appDeactivate(QEvent::ApplicationDeactivate); + QCoreApplication::sendEvent(qApp, &appDeactivate); + } + } + }); +} + +bool SkipApplicationDeactivateEvent() { + if (!ChildPopupsHiddenOnWayland) { + return false; + } + PendingDeactivateEvent = true; + return true; +} + +void GotApplicationActivateEvent() { + PendingDeactivateEvent = false; +} + namespace internal { TitleControls::Layout TitleControlsLayout() { diff --git a/ui/platform/mac/ui_utility_mac.mm b/ui/platform/mac/ui_utility_mac.mm index 857db1e..3c59a5f 100644 --- a/ui/platform/mac/ui_utility_mac.mm +++ b/ui/platform/mac/ui_utility_mac.mm @@ -147,6 +147,16 @@ std::optional IsOverlapped( return false; } +void RegisterChildPopupHiding() { +} + +bool SkipApplicationDeactivateEvent() { + return false; +} + +void GotApplicationActivateEvent() { +} + namespace internal { TitleControls::Layout TitleControlsLayout() { diff --git a/ui/platform/ui_platform_utility.h b/ui/platform/ui_platform_utility.h index 3def532..e7343cc 100644 --- a/ui/platform/ui_platform_utility.h +++ b/ui/platform/ui_platform_utility.h @@ -58,6 +58,12 @@ void ShowWindowMenu(not_null widget, const QPoint &point); void FixPopupMenuNativeEmojiPopup(not_null menu); +// Workaround for a Qt/Wayland bug that hides the parent popup when +// the child popup gets hidden, by sending Deactivate / Activate events. +void RegisterChildPopupHiding(); +[[nodiscard]] bool SkipApplicationDeactivateEvent(); +void GotApplicationActivateEvent(); + } // namespace Ui::Platform // Platform dependent implementations. diff --git a/ui/platform/win/ui_utility_win.cpp b/ui/platform/win/ui_utility_win.cpp index bb1cc32..e81b150 100644 --- a/ui/platform/win/ui_utility_win.cpp +++ b/ui/platform/win/ui_utility_win.cpp @@ -203,4 +203,14 @@ void FixPopupMenuNativeEmojiPopup(not_null menu) { menu->lifetime().make_state(menu)); } +void RegisterChildPopupHiding() { +} + +bool SkipApplicationDeactivateEvent() { + return false; +} + +void GotApplicationActivateEvent() { +} + } // namespace Ui::Platform diff --git a/ui/widgets/popup_menu.cpp b/ui/widgets/popup_menu.cpp index 305bc0f..049455d 100644 --- a/ui/widgets/popup_menu.cpp +++ b/ui/widgets/popup_menu.cpp @@ -673,6 +673,9 @@ bool PopupMenu::eventFilter(QObject *o, QEvent *e) { } void PopupMenu::hideMenu(bool fast) { + if (fast && _parent) { + Platform::RegisterChildPopupHiding(); + } if (isHidden() || (_hiding && !fast)) { return; }