Make '[un]registerLeaveSubscription' work in all windows.

This commit is contained in:
John Preston 2021-05-27 09:34:33 +04:00
parent deecf80f20
commit 3709714339
5 changed files with 60 additions and 26 deletions

View file

@ -1948,11 +1948,26 @@ void Panel::setupControlsBackgroundWide() {
template <typename WidgetPointer> template <typename WidgetPointer>
void Panel::trackControl(WidgetPointer &widget, rpl::lifetime &lifetime) { void Panel::trackControl(WidgetPointer &widget, rpl::lifetime &lifetime) {
if (widget) { if (widget) {
widget->events( const auto raw = &*widget;
raw->events(
) | rpl::start_with_next([=](not_null<QEvent*> e) { ) | rpl::start_with_next([=](not_null<QEvent*> e) {
using Type = std::remove_cvref_t<decltype(*raw)>;
constexpr auto mute = std::is_same_v<Type, Ui::CallMuteButton>;
if (e->type() == QEvent::Enter) { if (e->type() == QEvent::Enter) {
auto &integration = Ui::Integration::Instance();
if constexpr (mute) {
integration.registerLeaveSubscription(raw->outer());
} else {
integration.registerLeaveSubscription(raw);
}
toggleWideControls(true); toggleWideControls(true);
} else if (e->type() == QEvent::Leave) { } else if (e->type() == QEvent::Leave) {
auto &integration = Ui::Integration::Instance();
if constexpr (mute) {
integration.unregisterLeaveSubscription(raw->outer());
} else {
integration.unregisterLeaveSubscription(raw);
}
toggleWideControls(false); toggleWideControls(false);
} }
}, lifetime); }, lifetime);

View file

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "base/timer.h" #include "base/timer.h"
#include "base/event_filter.h"
#include "base/concurrent_timer.h" #include "base/concurrent_timer.h"
#include "base/qt_signal_producer.h" #include "base/qt_signal_producer.h"
#include "base/unixtime.h" #include "base/unixtime.h"
@ -997,30 +998,49 @@ QPoint Application::getPointForCallPanelCenter() const {
// macOS Qt bug workaround, sometimes no leaveEvent() gets to the nested widgets. // macOS Qt bug workaround, sometimes no leaveEvent() gets to the nested widgets.
void Application::registerLeaveSubscription(not_null<QWidget*> widget) { void Application::registerLeaveSubscription(not_null<QWidget*> widget) {
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
if (const auto topLevel = widget->window()) { if (const auto window = widget->window()) {
if (topLevel == _window->widget()) { auto i = _leaveFilters.find(window);
auto weak = Ui::MakeWeak(widget); if (i == end(_leaveFilters)) {
auto subscription = _window->widget()->leaveEvents( const auto check = [=](not_null<QEvent*> e) {
) | rpl::start_with_next([weak] { if (e->type() == QEvent::Leave) {
if (const auto window = weak.data()) { if (const auto taken = _leaveFilters.take(window)) {
QEvent ev(QEvent::Leave); for (const auto weak : taken->registered) {
QGuiApplication::sendEvent(window, &ev); if (const auto widget = weak.data()) {
QEvent ev(QEvent::Leave);
QCoreApplication::sendEvent(widget, &ev);
}
}
delete taken->filter.data();
}
} }
return base::EventFilterResult::Continue;
};
const auto filter = base::install_event_filter(window, check);
QObject::connect(filter, &QObject::destroyed, [=] {
_leaveFilters.remove(window);
}); });
_leaveSubscriptions.emplace_back(weak, std::move(subscription)); i = _leaveFilters.emplace(
window,
LeaveFilter{ .filter = filter.get() }).first;
} }
i->second.registered.push_back(widget.get());
} }
#endif // Q_OS_MAC #endif // Q_OS_MAC
} }
void Application::unregisterLeaveSubscription(not_null<QWidget*> widget) { void Application::unregisterLeaveSubscription(not_null<QWidget*> widget) {
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
_leaveSubscriptions = std::move( if (const auto topLevel = widget->window()) {
_leaveSubscriptions const auto i = _leaveFilters.find(topLevel);
) | ranges::actions::remove_if([&](const LeaveSubscription &subscription) { if (i != end(_leaveFilters)) {
auto pointer = subscription.pointer.data(); i->second.registered = std::move(
return !pointer || (pointer == widget); i->second.registered
}); ) | ranges::actions::remove_if([&](QPointer<QWidget> widget) {
const auto pointer = widget.data();
return !pointer || (pointer == widget);
});
}
}
#endif // Q_OS_MAC #endif // Q_OS_MAC
} }

View file

@ -369,17 +369,11 @@ private:
std::optional<base::Timer> _saveSettingsTimer; std::optional<base::Timer> _saveSettingsTimer;
struct LeaveSubscription { struct LeaveFilter {
LeaveSubscription( std::vector<QPointer<QWidget>> registered;
QPointer<QWidget> pointer, QPointer<QObject> filter;
rpl::lifetime &&subscription)
: pointer(pointer), subscription(std::move(subscription)) {
}
QPointer<QWidget> pointer;
rpl::lifetime subscription;
}; };
std::vector<LeaveSubscription> _leaveSubscriptions; base::flat_map<not_null<QWidget*>, LeaveFilter> _leaveFilters;
rpl::lifetime _lifetime; rpl::lifetime _lifetime;

View file

@ -1140,6 +1140,10 @@ rpl::producer<CallButtonColors> CallMuteButton::colorOverrides() const {
return _colorOverrides.events(); return _colorOverrides.events();
} }
not_null<QWidget*> CallMuteButton::outer() const {
return _content.get();
}
rpl::lifetime &CallMuteButton::lifetime() { rpl::lifetime &CallMuteButton::lifetime() {
return _blobs->lifetime(); return _blobs->lifetime();
} }

View file

@ -81,6 +81,7 @@ public:
void raise(); void raise();
void lower(); void lower();
[[nodiscard]] not_null<QWidget*> outer() const;
[[nodiscard]] rpl::producer<CallButtonColors> colorOverrides() const; [[nodiscard]] rpl::producer<CallButtonColors> colorOverrides() const;
[[nodiscard]] rpl::lifetime &lifetime(); [[nodiscard]] rpl::lifetime &lifetime();