From 44e94bfbf5549b27096ed0da2842c8b329456acb Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 21 Nov 2017 14:27:37 +0400 Subject: [PATCH] Add workaround for macOS leaveEvent() bugs. On macOS sometimes when mouse leaves the window we don't receive leaveEvent() calls in the nested widgets, like buttons, only for the window itself. --- Telegram/SourceFiles/base/flat_map.h | 2 -- .../SourceFiles/chat_helpers/tabbed_panel.cpp | 3 ++ Telegram/SourceFiles/messenger.cpp | 31 +++++++++++++++++++ Telegram/SourceFiles/messenger.h | 13 ++++++++ Telegram/SourceFiles/rpl/consumer.h | 2 +- Telegram/SourceFiles/ui/abstract_button.cpp | 3 ++ Telegram/SourceFiles/ui/special_buttons.cpp | 3 +- Telegram/SourceFiles/window/main_window.cpp | 8 +++++ Telegram/SourceFiles/window/main_window.h | 5 +++ 9 files changed, 66 insertions(+), 4 deletions(-) diff --git a/Telegram/SourceFiles/base/flat_map.h b/Telegram/SourceFiles/base/flat_map.h index 4e65c93088..adc3e24828 100644 --- a/Telegram/SourceFiles/base/flat_map.h +++ b/Telegram/SourceFiles/base/flat_map.h @@ -272,7 +272,6 @@ public: using reference = pair_type&; using const_reference = const pair_type&; - class const_iterator; class iterator : public iterator_base { public: using iterator_base::iterator_base; @@ -292,7 +291,6 @@ public: } }; - class const_reverse_iterator; class reverse_iterator : public reverse_iterator_base { public: using reverse_iterator_base::reverse_iterator_base; diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp b/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp index 8107d47a2b..8b16036b6f 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp +++ b/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp @@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "chat_helpers/tabbed_selector.h" #include "window/window_controller.h" #include "mainwindow.h" +#include "messenger.h" namespace ChatHelpers { namespace { @@ -178,6 +179,7 @@ void TabbedPanel::moveByBottom() { } void TabbedPanel::enterEventHook(QEvent *e) { + Messenger::Instance().registerLeaveSubscription(this); showAnimated(); } @@ -189,6 +191,7 @@ bool TabbedPanel::preventAutoHide() const { } void TabbedPanel::leaveEventHook(QEvent *e) { + Messenger::Instance().unregisterLeaveSubscription(this); if (preventAutoHide()) { return; } diff --git a/Telegram/SourceFiles/messenger.cpp b/Telegram/SourceFiles/messenger.cpp index 97666041db..59981330d8 100644 --- a/Telegram/SourceFiles/messenger.cpp +++ b/Telegram/SourceFiles/messenger.cpp @@ -20,6 +20,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #include "messenger.h" +#include #include "data/data_photo.h" #include "data/data_document.h" #include "base/timer.h" @@ -995,6 +996,36 @@ QPoint Messenger::getPointForCallPanelCenter() const { return QApplication::desktop()->screenGeometry().center(); } +// macOS Qt bug workaround, sometimes no leaveEvent() gets to the nested widgets. +void Messenger::registerLeaveSubscription(QWidget *widget) { +#ifdef Q_OS_MAC + if (auto topLevel = widget->window()) { + if (topLevel == _window.get()) { + auto guarded = weak(widget); + auto subscription = _window->leaveEvents() + | rpl::start_with_next([guarded] { + if (auto w = guarded.data()) { + QEvent ev(QEvent::Leave); + QGuiApplication::sendEvent(w, &ev); + } + }); + _leaveSubscriptions.emplace_back(guarded, std::move(subscription)); + } + } +#endif // Q_OS_MAC +} + +void Messenger::unregisterLeaveSubscription(QWidget *widget) { +#ifdef Q_OS_MAC + _leaveSubscriptions = std::move( + _leaveSubscriptions + ) | ranges::action::remove_if([&](const LeaveSubscription &subscription) { + auto pointer = subscription.pointer.data(); + return !pointer || (pointer == widget); + }); +#endif // Q_OS_MAC +} + void Messenger::QuitAttempt() { auto prevents = false; if (!Sandbox::isSavingSession() && AuthSession::Exists()) { diff --git a/Telegram/SourceFiles/messenger.h b/Telegram/SourceFiles/messenger.h index c2bd2f0977..1a7e72c558 100644 --- a/Telegram/SourceFiles/messenger.h +++ b/Telegram/SourceFiles/messenger.h @@ -174,6 +174,9 @@ public: return _passcodedChanged; } + void registerLeaveSubscription(QWidget *widget); + void unregisterLeaveSubscription(QWidget *widget); + void quitPreventFinished(); void handleAppActivated(); @@ -246,4 +249,14 @@ private: base::DelayedCallTimer _callDelayedTimer; + struct LeaveSubscription { + LeaveSubscription(QPointer pointer, rpl::lifetime &&subscription) + : pointer(pointer), subscription(std::move(subscription)) { + } + + QPointer pointer; + rpl::lifetime subscription; + }; + std::vector _leaveSubscriptions; + }; diff --git a/Telegram/SourceFiles/rpl/consumer.h b/Telegram/SourceFiles/rpl/consumer.h index a80017ceb0..337b946388 100644 --- a/Telegram/SourceFiles/rpl/consumer.h +++ b/Telegram/SourceFiles/rpl/consumer.h @@ -135,7 +135,7 @@ template inline void type_erased_handlers::terminate() { if (!_terminated) { _terminated = true; - details::take(_lifetime).destroy(); + _lifetime.destroy(); } } diff --git a/Telegram/SourceFiles/ui/abstract_button.cpp b/Telegram/SourceFiles/ui/abstract_button.cpp index 93e1814d5c..e59db45ede 100644 --- a/Telegram/SourceFiles/ui/abstract_button.cpp +++ b/Telegram/SourceFiles/ui/abstract_button.cpp @@ -22,6 +22,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include #include +#include "messenger.h" namespace Ui { @@ -109,10 +110,12 @@ void AbstractButton::setOver(bool over, StateChangeSource source) { if (over && !(_state & StateFlag::Over)) { auto was = _state; _state |= StateFlag::Over; + Messenger::Instance().registerLeaveSubscription(this); onStateChanged(was, source); } else if (!over && (_state & StateFlag::Over)) { auto was = _state; _state &= ~State(StateFlag::Over); + Messenger::Instance().unregisterLeaveSubscription(this); onStateChanged(was, source); } updateCursor(); diff --git a/Telegram/SourceFiles/ui/special_buttons.cpp b/Telegram/SourceFiles/ui/special_buttons.cpp index e4e9ee87da..25de799494 100644 --- a/Telegram/SourceFiles/ui/special_buttons.cpp +++ b/Telegram/SourceFiles/ui/special_buttons.cpp @@ -169,7 +169,8 @@ void HistoryDownButton::setUnreadCount(int unreadCount) { } } -EmojiButton::EmojiButton(QWidget *parent, const style::IconButton &st) : RippleButton(parent, st.ripple) +EmojiButton::EmojiButton(QWidget *parent, const style::IconButton &st) +: RippleButton(parent, st.ripple) , _st(st) , _a_loading(animation(this, &EmojiButton::step_loading)) { resize(_st.width, _st.height); diff --git a/Telegram/SourceFiles/window/main_window.cpp b/Telegram/SourceFiles/window/main_window.cpp index d070175b6c..e654713ef5 100644 --- a/Telegram/SourceFiles/window/main_window.cpp +++ b/Telegram/SourceFiles/window/main_window.cpp @@ -261,6 +261,14 @@ void MainWindow::resizeEvent(QResizeEvent *e) { updateControlsGeometry(); } +rpl::producer<> MainWindow::leaveEvents() const { + return _leaveEvents.events(); +} + +void MainWindow::leaveEvent(QEvent *e) { + _leaveEvents.fire({}); +} + void MainWindow::updateControlsGeometry() { auto bodyTop = 0; auto bodyWidth = width(); diff --git a/Telegram/SourceFiles/window/main_window.h b/Telegram/SourceFiles/window/main_window.h index 72b5120860..5ac1d608c0 100644 --- a/Telegram/SourceFiles/window/main_window.h +++ b/Telegram/SourceFiles/window/main_window.h @@ -20,6 +20,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once +#include #include "window/window_title.h" #include "base/timer.h" @@ -96,6 +97,8 @@ public: return _dragFinished; } + rpl::producer<> leaveEvents() const; + public slots: bool minimizeToTray(); void updateGlobalMenu() { @@ -104,6 +107,7 @@ public slots: protected: void resizeEvent(QResizeEvent *e) override; + void leaveEvent(QEvent *e) override; void savePosition(Qt::WindowState state = Qt::WindowActive); void handleStateChanged(Qt::WindowState state); @@ -187,6 +191,7 @@ private: base::Timer _inactivePressTimer; base::Observable _dragFinished; + rpl::event_stream<> _leaveEvents; };