diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index 72e344e2dc..c52e8eb1c8 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Telegram.rc @@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,10,8,0 - PRODUCTVERSION 0,10,8,0 + FILEVERSION 0,10,8,1 + PRODUCTVERSION 0,10,8,1 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -51,10 +51,10 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Telegram Messenger LLP" - VALUE "FileVersion", "0.10.8.0" + VALUE "FileVersion", "0.10.8.1" VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "0.10.8.0" + VALUE "ProductVersion", "0.10.8.1" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index 69891e4ddf..4ecec96054 100644 --- a/Telegram/Resources/winrc/Updater.rc +++ b/Telegram/Resources/winrc/Updater.rc @@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,10,8,0 - PRODUCTVERSION 0,10,8,0 + FILEVERSION 0,10,8,1 + PRODUCTVERSION 0,10,8,1 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -43,10 +43,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram Messenger LLP" VALUE "FileDescription", "Telegram Updater" - VALUE "FileVersion", "0.10.8.0" + VALUE "FileVersion", "0.10.8.1" VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "0.10.8.0" + VALUE "ProductVersion", "0.10.8.1" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 0f7acc35a1..65cf0717e9 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -42,11 +42,10 @@ ApiWrap::ApiWrap(QObject *parent) : QObject(parent) void ApiWrap::init() { } -void ApiWrap::requestMessageData(ChannelData *channel, MsgId msgId, std_::unique_ptr callback) { +void ApiWrap::requestMessageData(ChannelData *channel, MsgId msgId, RequestMessageDataCallback &&callback) { MessageDataRequest &req(channel ? _channelMessageDataRequests[channel][msgId] : _messageDataRequests[msgId]); if (callback) { - MessageDataRequest::CallbackPtr pcallback(callback.release()); - req.callbacks.append(pcallback); + req.callbacks.append(std_::move(callback)); } if (!req.req) _messageDataResolveDelayed->call(); } @@ -138,7 +137,7 @@ void ApiWrap::gotMessageDatas(ChannelData *channel, const MTPmessages_Messages & for (auto i = requests->begin(); i != requests->cend();) { if (i.value().req == req) { for_const (auto &callback, i.value().callbacks) { - callback->call(channel, i.key()); + callback(channel, i.key()); } i = requests->erase(i); } else { diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index e4c83a8d6f..524f195c6b 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -28,8 +28,8 @@ public: ApiWrap(QObject *parent); void init(); - using RequestMessageDataCallback = SharedCallback; - void requestMessageData(ChannelData *channel, MsgId msgId, std_::unique_ptr callback); + using RequestMessageDataCallback = base::lambda_wrap; + void requestMessageData(ChannelData *channel, MsgId msgId, RequestMessageDataCallback &&callback); void requestFullPeer(PeerData *peer); void requestPeer(PeerData *peer); @@ -82,11 +82,8 @@ private: void gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req); struct MessageDataRequest { - MessageDataRequest() : req(0) { - } - typedef SharedCallback::Ptr CallbackPtr; - typedef QList Callbacks; - mtpRequestId req; + using Callbacks = QList; + mtpRequestId req = 0; Callbacks callbacks; }; typedef QMap MessageDataRequests; diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index b5d6fe50aa..079087f5cb 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -1874,7 +1874,7 @@ namespace { } History *history(const PeerId &peer) { - return ::histories.findOrInsert(peer, 0, 0, 0); + return ::histories.findOrInsert(peer); } History *historyFromDialog(const PeerId &peer, int32 unreadCnt, int32 maxInboxRead, int32 maxOutboxRead) { diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp index 968ff4a65a..49937f50b1 100644 --- a/Telegram/SourceFiles/application.cpp +++ b/Telegram/SourceFiles/application.cpp @@ -218,7 +218,6 @@ void Application::singleInstanceChecked() { Logs::multipleInstances(); } - Notify::startObservers(); Sandbox::start(); if (!Logs::started() || (!cManyInstance() && !Logs::instanceChecked())) { @@ -357,8 +356,6 @@ void Application::closeApplication() { } _updateThread = 0; #endif - - Notify::finishObservers(); } #ifndef TDESKTOP_DISABLE_AUTOUPDATE diff --git a/Telegram/SourceFiles/boxes/abstractbox.h b/Telegram/SourceFiles/boxes/abstractbox.h index 5e3861c17b..26520c20d3 100644 --- a/Telegram/SourceFiles/boxes/abstractbox.h +++ b/Telegram/SourceFiles/boxes/abstractbox.h @@ -47,7 +47,7 @@ private: }; -class AbstractBox : public LayerWidget { +class AbstractBox : public LayerWidget, protected base::Subscriber { Q_OBJECT public: diff --git a/Telegram/SourceFiles/boxes/addcontactbox.cpp b/Telegram/SourceFiles/boxes/addcontactbox.cpp index 52377b0665..af35aa794f 100644 --- a/Telegram/SourceFiles/boxes/addcontactbox.cpp +++ b/Telegram/SourceFiles/boxes/addcontactbox.cpp @@ -1362,8 +1362,8 @@ RevokePublicLinkBox::RevokePublicLinkBox(base::lambda_unique &&revokeCal updateMaxHeight(); - connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); connect(_cancel, SIGNAL(clicked()), this, SLOT(onClose())); + subscribe(FileDownload::ImageLoaded(), [this] { update(); }); prepare(); } @@ -1410,10 +1410,16 @@ void RevokePublicLinkBox::mouseReleaseEvent(QMouseEvent *e) { auto text_method = pressed->isMegagroup() ? lng_channels_too_much_public_revoke_confirm_group : lng_channels_too_much_public_revoke_confirm_channel; auto text = text_method(lt_link, qsl("telegram.me/") + pressed->userName(), lt_group, pressed->name); weakRevokeConfirmBox = new ConfirmBox(text, lang(lng_channels_too_much_public_revoke)); - weakRevokeConfirmBox->setConfirmedCallback([this, weak_this = weakThis(), pressed]() { - if (!weak_this) return; + struct Data { + Data(QPointer &&weakThis, PeerData *pressed) : weakThis(std_::move(weakThis)), pressed(pressed) { + } + QPointer weakThis; + PeerData *pressed; + }; + weakRevokeConfirmBox->setConfirmedCallback([this, data = std_::make_unique(weakThis(), pressed)]() { + if (!data->weakThis) return; if (_revokeRequestId) return; - _revokeRequestId = MTP::send(MTPchannels_UpdateUsername(pressed->asChannel()->inputChannel, MTP_string("")), rpcDone(&RevokePublicLinkBox::revokeLinkDone), rpcFail(&RevokePublicLinkBox::revokeLinkFail)); + _revokeRequestId = MTP::send(MTPchannels_UpdateUsername(data->pressed->asChannel()->inputChannel, MTP_string("")), rpcDone(&RevokePublicLinkBox::revokeLinkDone), rpcFail(&RevokePublicLinkBox::revokeLinkFail)); }); Ui::showLayer(weakRevokeConfirmBox, KeepOtherLayers); } diff --git a/Telegram/SourceFiles/boxes/backgroundbox.cpp b/Telegram/SourceFiles/boxes/backgroundbox.cpp index b5a56f8d02..9f2700dea4 100644 --- a/Telegram/SourceFiles/boxes/backgroundbox.cpp +++ b/Telegram/SourceFiles/boxes/backgroundbox.cpp @@ -29,13 +29,14 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org BackgroundInner::BackgroundInner() : _bgCount(0), _rows(0), _over(-1), _overDown(-1) { - connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); if (App::cServerBackgrounds().isEmpty()) { resize(BackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding); MTP::send(MTPaccount_GetWallPapers(), rpcDone(&BackgroundInner::gotWallpapers)); } else { updateWallpapers(); } + + subscribe(FileDownload::ImageLoaded(), [this] { update(); }); setMouseTracking(true); } diff --git a/Telegram/SourceFiles/boxes/backgroundbox.h b/Telegram/SourceFiles/boxes/backgroundbox.h index 66866f1655..ebdcab053a 100644 --- a/Telegram/SourceFiles/boxes/backgroundbox.h +++ b/Telegram/SourceFiles/boxes/backgroundbox.h @@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "abstractbox.h" #include "core/lambda_wrap.h" -class BackgroundInner : public QWidget, public RPCSender { +class BackgroundInner : public TWidget, public RPCSender, private base::Subscriber { Q_OBJECT public: diff --git a/Telegram/SourceFiles/boxes/confirmbox.cpp b/Telegram/SourceFiles/boxes/confirmbox.cpp index 10d67a9cae..61107ba4a1 100644 --- a/Telegram/SourceFiles/boxes/confirmbox.cpp +++ b/Telegram/SourceFiles/boxes/confirmbox.cpp @@ -546,7 +546,7 @@ ConfirmInviteBox::ConfirmInviteBox(const QString &title, const MTPChatPhoto &pho if (!location.isNull()) { _photo = ImagePtr(location); if (!_photo->loaded()) { - connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); + subscribe(FileDownload::ImageLoaded(), [this] { update(); }); _photo->load(); } } diff --git a/Telegram/SourceFiles/boxes/confirmbox.h b/Telegram/SourceFiles/boxes/confirmbox.h index 2f7ab53bd1..ecd8525d37 100644 --- a/Telegram/SourceFiles/boxes/confirmbox.h +++ b/Telegram/SourceFiles/boxes/confirmbox.h @@ -34,7 +34,7 @@ public: void updateLink(); // You can use this instead of connecting to "confirmed()" signal. - void setConfirmedCallback(base::lambda_wrap &&callback) { + void setConfirmedCallback(base::lambda_unique &&callback) { _confirmedCallback = std_::move(callback); } diff --git a/Telegram/SourceFiles/boxes/contactsbox.cpp b/Telegram/SourceFiles/boxes/contactsbox.cpp index f903768da1..16f02d661f 100644 --- a/Telegram/SourceFiles/boxes/contactsbox.cpp +++ b/Telegram/SourceFiles/boxes/contactsbox.cpp @@ -106,7 +106,7 @@ ContactsInner::ContactsInner(UserData *bot) : TWidget() } void ContactsInner::init() { - connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); + subscribe(FileDownload::ImageLoaded(), [this] { update(); }); connect(&_addContactLnk, SIGNAL(clicked()), App::wnd(), SLOT(onShowAddContact())); connect(&_allAdmins, SIGNAL(changed()), this, SLOT(onAllAdminsChanged())); @@ -1750,7 +1750,8 @@ MembersInner::MembersInner(ChannelData *channel, MembersFilter filter) : TWidget , _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.right()) , _about(_aboutWidth) , _aboutHeight(0) { - connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); + subscribe(FileDownload::ImageLoaded(), [this] { update(); }); + connect(App::main(), SIGNAL(peerNameChanged(PeerData*,const PeerData::Names&,const PeerData::NameFirstChars&)), this, SLOT(onPeerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&))); connect(App::main(), SIGNAL(peerPhotoChanged(PeerData*)), this, SLOT(peerUpdated(PeerData*))); diff --git a/Telegram/SourceFiles/boxes/contactsbox.h b/Telegram/SourceFiles/boxes/contactsbox.h index 59c41c09a0..27a13294a7 100644 --- a/Telegram/SourceFiles/boxes/contactsbox.h +++ b/Telegram/SourceFiles/boxes/contactsbox.h @@ -36,7 +36,7 @@ using MembersAlreadyIn = OrderedSet; QString cantInviteError(); class ConfirmBox; -class ContactsInner : public TWidget, public RPCSender { +class ContactsInner : public TWidget, public RPCSender, private base::Subscriber { Q_OBJECT private: @@ -269,7 +269,7 @@ private: }; -class MembersInner : public TWidget, public RPCSender { +class MembersInner : public TWidget, public RPCSender, private base::Subscriber { Q_OBJECT private: diff --git a/Telegram/SourceFiles/boxes/localstoragebox.cpp b/Telegram/SourceFiles/boxes/localstoragebox.cpp index 29b3e62790..23057c10aa 100644 --- a/Telegram/SourceFiles/boxes/localstoragebox.cpp +++ b/Telegram/SourceFiles/boxes/localstoragebox.cpp @@ -33,10 +33,11 @@ LocalStorageBox::LocalStorageBox() : AbstractBox() connect(_clear, SIGNAL(clicked()), this, SLOT(onClear())); connect(_close, SIGNAL(clicked()), this, SLOT(onClose())); - connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); connect(App::wnd(), SIGNAL(tempDirCleared(int)), this, SLOT(onTempDirCleared(int))); connect(App::wnd(), SIGNAL(tempDirClearFailed(int)), this, SLOT(onTempDirClearFailed(int))); + subscribe(FileDownload::ImageLoaded(), [this] { update(); }); + checkLocalStoredCounts(); prepare(); } diff --git a/Telegram/SourceFiles/boxes/sharebox.cpp b/Telegram/SourceFiles/boxes/sharebox.cpp index 37084e2499..71b2d3e3a8 100644 --- a/Telegram/SourceFiles/boxes/sharebox.cpp +++ b/Telegram/SourceFiles/boxes/sharebox.cpp @@ -227,9 +227,9 @@ void ShareBox::onMustScrollTo(int top, int bottom) { to = bottom - (scrollBottom - scrollTop); } if (from != to) { - START_ANIMATION(_scrollAnimation, func([this]() { + _scrollAnimation.start([this]() { scrollArea()->scrollToY(_scrollAnimation.current(scrollArea()->scrollTop())); - }), from, to, st::shareScrollDuration, anim::sineInOut); + }, from, to, st::shareScrollDuration, anim::sineInOut); } } @@ -243,8 +243,6 @@ namespace internal { ShareInner::ShareInner(QWidget *parent) : ScrolledWidget(parent) , _chatsIndexed(std_::make_unique(Dialogs::SortMode::Add)) { - connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); - _rowsTop = st::shareRowsTop; _rowHeight = st::shareRowHeight; setAttribute(Qt::WA_OpaquePaintEvent); @@ -264,7 +262,10 @@ ShareInner::ShareInner(QWidget *parent) : ScrolledWidget(parent) using UpdateFlag = Notify::PeerUpdate::Flag; auto observeEvents = UpdateFlag::NameChanged | UpdateFlag::PhotoChanged; - Notify::registerPeerObserver(observeEvents, this, &ShareInner::notifyPeerUpdated); + subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { + notifyPeerUpdated(update); + })); + subscribe(FileDownload::ImageLoaded(), [this] { update(); }); } void ShareInner::setVisibleTopBottom(int visibleTop, int visibleBottom) { @@ -437,9 +438,9 @@ void ShareInner::setActive(int active) { if (active != _active) { auto changeNameFg = [this](int index, style::color from, style::color to) { if (auto chat = getChatAtIndex(index)) { - START_ANIMATION(chat->nameFg, func([this, chat] { + chat->nameFg.start([this, chat] { repaintChat(chat->peer); - }), from->c, to->c, st::shareActivateDuration, anim::linear); + }, from->c, to->c, st::shareActivateDuration); } }; changeNameFg(_active, st::shareNameActiveFg, st::shareNameFg); @@ -459,16 +460,7 @@ void ShareInner::paintChat(Painter &p, Chat *chat, int index) { auto w = width(); auto photoLeft = (_rowWidth - (st::sharePhotoRadius * 2)) / 2; auto photoTop = st::sharePhotoTop; - if (chat->selection.isNull()) { - if (!chat->wideUserpicCache.isNull()) { - chat->wideUserpicCache = QPixmap(); - } - auto userpicRadius = chat->selected ? st::sharePhotoSmallRadius : st::sharePhotoRadius; - auto userpicShift = st::sharePhotoRadius - userpicRadius; - auto userpicLeft = x + photoLeft + userpicShift; - auto userpicTop = y + photoTop + userpicShift; - chat->peer->paintUserpicLeft(p, userpicRadius * 2, userpicLeft, userpicTop, w); - } else { + if (chat->selection.animating()) { p.setRenderHint(QPainter::SmoothPixmapTransform, true); auto userpicRadius = qRound(WideCacheScale * (st::sharePhotoRadius + (st::sharePhotoSmallRadius - st::sharePhotoRadius) * selectionLevel)); auto userpicShift = WideCacheScale * st::sharePhotoRadius - userpicRadius; @@ -478,6 +470,15 @@ void ShareInner::paintChat(Painter &p, Chat *chat, int index) { auto from = QRect(QPoint(0, 0), chat->wideUserpicCache.size()); p.drawPixmapLeft(to, w, chat->wideUserpicCache, from); p.setRenderHint(QPainter::SmoothPixmapTransform, false); + } else { + if (!chat->wideUserpicCache.isNull()) { + chat->wideUserpicCache = QPixmap(); + } + auto userpicRadius = chat->selected ? st::sharePhotoSmallRadius : st::sharePhotoRadius; + auto userpicShift = st::sharePhotoRadius - userpicRadius; + auto userpicLeft = x + photoLeft + userpicShift; + auto userpicTop = y + photoTop + userpicShift; + chat->peer->paintUserpicLeft(p, userpicRadius * 2, userpicLeft, userpicTop, w); } if (selectionLevel > 0) { @@ -516,11 +517,12 @@ void ShareInner::paintChat(Painter &p, Chat *chat, int index) { p.setRenderHint(QPainter::SmoothPixmapTransform, false); p.setOpacity(1.); - if (chat->nameFg.isNull()) { - p.setPen((index == _active) ? st::shareNameActiveFg : st::shareNameFg); - } else { + if (chat->nameFg.animating()) { p.setPen(chat->nameFg.current()); + } else { + p.setPen((index == _active) ? st::shareNameActiveFg : st::shareNameFg); } + auto nameWidth = (_rowWidth - st::shareColumnSkip); auto nameLeft = st::shareColumnSkip / 2; auto nameTop = photoTop + st::sharePhotoRadius * 2 + st::shareNameTop; @@ -670,21 +672,21 @@ void ShareInner::changeCheckState(Chat *chat) { if (chat->selected) { _selected.insert(chat->peer); chat->icons.push_back(Chat::Icon()); - START_ANIMATION(chat->icons.back().fadeIn, func([this, chat] { + chat->icons.back().fadeIn.start([this, chat] { repaintChat(chat->peer); - }), 0, 1, st::shareSelectDuration, anim::linear); + }, 0, 1, st::shareSelectDuration); } else { _selected.remove(chat->peer); prepareWideCheckIconCache(&chat->icons.back()); - START_ANIMATION(chat->icons.back().fadeOut, func([this, chat] { - removeFadeOutedIcons(chat); + chat->icons.back().fadeOut.start([this, chat] { repaintChat(chat->peer); - }), 1, 0, st::shareSelectDuration, anim::linear); + removeFadeOutedIcons(chat); // this call can destroy current lambda + }, 1, 0, st::shareSelectDuration); } prepareWideUserpicCache(chat); - START_ANIMATION(chat->selection, func([this, chat] { + chat->selection.start([this, chat] { repaintChat(chat->peer); - }), chat->selected ? 0 : 1, chat->selected ? 1 : 0, st::shareSelectDuration, anim_bumpy); + }, chat->selected ? 0 : 1, chat->selected ? 1 : 0, st::shareSelectDuration, anim_bumpy); if (chat->selected) { setActive(chatIndex(chat->peer)); } @@ -692,9 +694,9 @@ void ShareInner::changeCheckState(Chat *chat) { } void ShareInner::removeFadeOutedIcons(Chat *chat) { - while (!chat->icons.empty() && chat->icons.front().fadeIn.isNull() && chat->icons.front().fadeOut.isNull()) { + while (!chat->icons.empty() && !chat->icons.front().fadeIn.animating() && !chat->icons.front().fadeOut.animating()) { if (chat->icons.size() > 1 || !chat->selected) { - chat->icons.pop_front(); + chat->icons.erase(chat->icons.begin()); } else { break; } @@ -1016,18 +1018,6 @@ void shareGameScoreFromItem(HistoryItem *item) { Ui::showLayer(new ShareBox(std_::move(copyCallback), std_::move(submitCallback))); } -class GameMessageResolvedCallback : public SharedCallback { -public: - void call(ChannelData *channel, MsgId msgId) const override { - if (auto item = App::histItemById(channel, msgId)) { - shareGameScoreFromItem(item); - } else { - Ui::showLayer(new InformBox(lang(lng_edit_deleted))); - } - } - -}; - } // namespace void shareGameScoreByHash(const QString &hash) { @@ -1062,7 +1052,13 @@ void shareGameScoreByHash(const QString &hash) { } else if (App::api()) { auto channel = channelId ? App::channelLoaded(channelId) : nullptr; if (channel || !channelId) { - App::api()->requestMessageData(channel, msgId, std_::make_unique()); + App::api()->requestMessageData(channel, msgId, [](ChannelData *channel, MsgId msgId) { + if (auto item = App::histItemById(channel, msgId)) { + shareGameScoreFromItem(item); + } else { + Ui::showLayer(new InformBox(lang(lng_edit_deleted))); + } + }); } } } diff --git a/Telegram/SourceFiles/boxes/sharebox.h b/Telegram/SourceFiles/boxes/sharebox.h index 696a28242e..11288b6d80 100644 --- a/Telegram/SourceFiles/boxes/sharebox.h +++ b/Telegram/SourceFiles/boxes/sharebox.h @@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "abstractbox.h" #include "core/lambda_wrap.h" #include "core/observer.h" +#include "core/vector_of_moveable.h" namespace Dialogs { class Row; @@ -107,7 +108,7 @@ private: namespace internal { -class ShareInner : public ScrolledWidget, public RPCSender, public Notify::Observer { +class ShareInner : public ScrolledWidget, public RPCSender, private base::Subscriber { Q_OBJECT public: @@ -163,7 +164,7 @@ private: FloatAnimation fadeOut; QPixmap wideCheckCache; }; - QList icons; + std_::vector_of_moveable icons; }; void paintChat(Painter &p, Chat *chat, int index); void updateChat(PeerData *peer); diff --git a/Telegram/SourceFiles/boxes/stickersetbox.cpp b/Telegram/SourceFiles/boxes/stickersetbox.cpp index 0f9974954a..6c20fbc79e 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.cpp +++ b/Telegram/SourceFiles/boxes/stickersetbox.cpp @@ -41,7 +41,6 @@ constexpr int kArchivedLimitPerPage = 30; StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : ScrolledWidget() , _input(set) { - connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); switch (set.type()) { case mtpc_inputStickerSetID: _setId = set.c_inputStickerSetID().vid.v; _setAccess = set.c_inputStickerSetID().vaccess_hash.v; break; case mtpc_inputStickerSetShortName: _setShortName = qs(set.c_inputStickerSetShortName().vshort_name); break; @@ -49,6 +48,8 @@ StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : ScrolledWidget MTP::send(MTPmessages_GetStickerSet(_input), rpcDone(&StickerSetInner::gotSet), rpcFail(&StickerSetInner::failedSet)); App::main()->updateStickers(); + subscribe(FileDownload::ImageLoaded(), [this] { update(); }); + setMouseTracking(true); _previewTimer.setSingleShot(true); @@ -62,8 +63,8 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) { _selected = -1; setCursor(style::cur_default); if (set.type() == mtpc_messages_stickerSet) { - auto &d(set.c_messages_stickerSet()); - auto &v(d.vdocuments.c_vector().v); + auto &d = set.c_messages_stickerSet(); + auto &v = d.vdocuments.c_vector().v; _pack.reserve(v.size()); _packOvers.reserve(v.size()); for (int i = 0, l = v.size(); i < l; ++i) { @@ -247,13 +248,13 @@ void StickerSetInner::updateSelected() { void StickerSetInner::startOverAnimation(int index, float64 from, float64 to) { if (index >= 0 && index < _packOvers.size()) { - START_ANIMATION(_packOvers[index], func([this, index]() { + _packOvers[index].start([this, index] { int row = index / StickerPanPerRow; int column = index % StickerPanPerRow; int left = st::stickersPadding.left() + column * st::stickersSize.width(); int top = st::stickersPadding.top() + row * st::stickersSize.height(); rtlupdate(left, top, st::stickersSize.width(), st::stickersSize.height()); - }), from, to, st::emojiPanDuration, anim::linear); + }, from, to, st::emojiPanDuration); } } @@ -515,7 +516,7 @@ StickersInner::StickersInner(const Stickers::Order &archivedIds) : ScrolledWidge } void StickersInner::setup() { - connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(onImageLoaded())); + subscribe(FileDownload::ImageLoaded(), [this] { update(); }); setMouseTracking(true); } diff --git a/Telegram/SourceFiles/boxes/stickersetbox.h b/Telegram/SourceFiles/boxes/stickersetbox.h index 699780a97c..1626fd08a4 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.h +++ b/Telegram/SourceFiles/boxes/stickersetbox.h @@ -21,10 +21,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #pragma once #include "abstractbox.h" +#include "core/vector_of_moveable.h" class ConfirmBox; -class StickerSetInner : public ScrolledWidget, public RPCSender { +class StickerSetInner : public ScrolledWidget, public RPCSender, private base::Subscriber { Q_OBJECT public: @@ -69,7 +70,7 @@ private: return (_setFlags & MTPDstickerSet::Flag::f_masks); } - QVector _packOvers; + std_::vector_of_moveable _packOvers; StickerPack _pack; StickersByEmojiMap _emoji; bool _loaded = false; @@ -206,7 +207,7 @@ int32 stickerPacksCount(bool includeDisabledOfficial = false); namespace internal { -class StickersInner : public ScrolledWidget, public RPCSender { +class StickersInner : public ScrolledWidget, public RPCSender, private base::Subscriber { Q_OBJECT public: diff --git a/Telegram/SourceFiles/core/basic_types.h b/Telegram/SourceFiles/core/basic_types.h index 4e92ce5594..a5401961c0 100644 --- a/Telegram/SourceFiles/core/basic_types.h +++ b/Telegram/SourceFiles/core/basic_types.h @@ -20,6 +20,17 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once +#include +#include + +#include + +#include + +#ifndef OS_MAC_OLD +#include +#endif // OS_MAC_OLD + template void deleteAndMark(T *&link) { delete link; @@ -259,13 +270,6 @@ typedef float float32; typedef double float64; #endif -#include -#include - -#include - -#include - using std::string; using std::exception; #ifdef OS_MAC_OLD @@ -1035,13 +1039,15 @@ struct ComponentWrapStruct { // global scope, so it will be filled by zeros from the start ComponentWrapStruct() { } - ComponentWrapStruct(int size, ComponentConstruct construct, ComponentDestruct destruct, ComponentMove move) + ComponentWrapStruct(std::size_t size, std::size_t align, ComponentConstruct construct, ComponentDestruct destruct, ComponentMove move) : Size(size) + , Align(align) , Construct(construct) , Destruct(destruct) , Move(move) { } - int Size; + std::size_t Size; + std::size_t Align; ComponentConstruct Construct; ComponentDestruct Destruct; ComponentMove Move; @@ -1058,6 +1064,7 @@ extern QAtomicInt ComponentIndexLast; template struct BaseComponent { BaseComponent() { + static_assert(alignof(Type) <= alignof(SmallestSizeType), "Components should align to a pointer!"); } BaseComponent(const BaseComponent &other) = delete; BaseComponent &operator=(const BaseComponent &other) = delete; @@ -1075,8 +1082,11 @@ struct BaseComponent { t_assert(last < 64); if (_index.testAndSetOrdered(0, last + 1)) { ComponentWraps[last] = ComponentWrapStruct( - CeilDivideMinimumOne::Result * sizeof(uint64), - Type::ComponentConstruct, Type::ComponentDestruct, Type::ComponentMove); + CeilDivideMinimumOne::Result * sizeof(SmallestSizeType), + alignof(Type), + Type::ComponentConstruct, + Type::ComponentDestruct, + Type::ComponentMove); } break; } @@ -1088,6 +1098,8 @@ struct BaseComponent { } protected: + using SmallestSizeType = void*; + static void ComponentConstruct(void *location, Composer *composer) { new (location) Type(); } @@ -1102,7 +1114,6 @@ protected: class ComposerMetadata { public: - ComposerMetadata(uint64 mask) : size(0), last(64), _mask(mask) { for (int i = 0; i < 64; ++i) { uint64 m = (1ULL << i); @@ -1147,15 +1158,13 @@ const ComposerMetadata *GetComposerMetadata(uint64 mask); class Composer { public: - Composer(uint64 mask = 0) : _data(zerodata()) { if (mask) { const ComposerMetadata *meta = GetComposerMetadata(mask); int size = sizeof(meta) + meta->size; - void *data = operator new(size); - if (!data) { // terminate if we can't allocate memory - throw "Can't allocate memory!"; - } + + auto data = operator new(size); + t_assert(data != nullptr); _data = data; _meta() = meta; @@ -1163,7 +1172,13 @@ public: int offset = meta->offsets[i]; if (offset >= 0) { try { - ComponentWraps[i].Construct(_dataptrunsafe(offset), this); + auto constructAt = _dataptrunsafe(offset); +#ifndef OS_MAC_OLD + auto space = ComponentWraps[i].Size; + auto alignedAt = std::align(ComponentWraps[i].Align, space, constructAt, space); + t_assert(alignedAt == constructAt); +#endif // OS_MAC_OLD + ComponentWraps[i].Construct(constructAt, this); } catch (...) { while (i > 0) { --i; @@ -1182,7 +1197,7 @@ public: Composer &operator=(const Composer &other) = delete; ~Composer() { if (_data != zerodata()) { - const ComposerMetadata *meta = _meta(); + auto meta = _meta(); for (int i = 0; i < meta->last; ++i) { int offset = meta->offsets[i]; if (offset >= 0) { @@ -1213,7 +1228,7 @@ protected: Composer tmp(mask); tmp.swap(*this); if (_data != zerodata() && tmp._data != zerodata()) { - const ComposerMetadata *meta = _meta(), *wasmeta = tmp._meta(); + auto meta = _meta(), wasmeta = tmp._meta(); for (int i = 0; i < meta->last; ++i) { int offset = meta->offsets[i], wasoffset = wasmeta->offsets[i]; if (offset >= 0 && wasoffset >= 0) { @@ -1252,103 +1267,3 @@ private: } }; - -template -class SharedCallback { -public: - virtual R call(Args... args) const = 0; - virtual ~SharedCallback() { - } - using Ptr = QSharedPointer>; - -}; - -template -class FunctionImplementation { -public: - virtual R call(Args... args) = 0; - virtual void destroy() { delete this; } - virtual ~FunctionImplementation() {} - -}; - -template -class NullFunctionImplementation : public FunctionImplementation { -public: - R call(Args... args) override { return R(); } - void destroy() override {} - static NullFunctionImplementation SharedInstance; - -}; -template -NullFunctionImplementation NullFunctionImplementation::SharedInstance; - -template -class Function { -public: - Function() : _implementation(nullImpl()) {} - Function(FunctionImplementation *implementation) : _implementation(implementation) {} - Function(const Function &other) = delete; - Function &operator=(const Function &other) = delete; - Function(Function &&other) : _implementation(other._implementation) { - other._implementation = nullImpl(); - } - Function &operator=(Function &&other) { - std::swap(_implementation, other._implementation); - return *this; - } - - bool isNull() const { - return (_implementation == nullImpl()); - } - - R call(Args... args) { return _implementation->call(args...); } - ~Function() { - if (_implementation) { - _implementation->destroy(); - _implementation = nullptr; - } - deleteAndMark(_implementation); - } - -private: - static FunctionImplementation *nullImpl() { - return &NullFunctionImplementation::SharedInstance; - } - - FunctionImplementation *_implementation; - -}; - -template -class WrappedFunction : public FunctionImplementation { -public: - using Method = R(*)(Args... args); - WrappedFunction(Method method) : _method(method) {} - R call(Args... args) override { return (*_method)(args...); } - -private: - Method _method; - -}; -template -inline Function func(R(*method)(Args... args)) { - return Function(new WrappedFunction(method)); -} - -template -class ObjectFunction : public FunctionImplementation { -public: - using Method = R(I::*)(Args... args); - ObjectFunction(O *obj, Method method) : _obj(obj), _method(method) {} - R call(Args... args) override { return (_obj->*_method)(args...); } - -private: - O *_obj; - Method _method; - -}; -template -inline Function func(O *obj, R(I::*method)(Args...)) { - return Function(new ObjectFunction(obj, method)); -} diff --git a/Telegram/SourceFiles/core/lambda_wrap.h b/Telegram/SourceFiles/core/lambda_wrap.h index 77982086c5..9305c66945 100644 --- a/Telegram/SourceFiles/core/lambda_wrap.h +++ b/Telegram/SourceFiles/core/lambda_wrap.h @@ -20,6 +20,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once +#ifndef OS_MAC_OLD +#include +#endif // OS_MAC_OLD + namespace base { namespace internal { @@ -50,7 +54,7 @@ struct lambda_wrap_helper_base { const call_type call; const destruct_type destruct; - static constexpr size_t kFullStorageSize = 40U; + static constexpr size_t kFullStorageSize = sizeof(void*) + 24U; static constexpr size_t kStorageSize = kFullStorageSize - sizeof(void*); template @@ -90,43 +94,47 @@ const lambda_wrap_empty lambda_wrap_empty::ins template struct lambda_wrap_helper_move_impl; -template -struct lambda_wrap_helper_move_impl : public lambda_wrap_helper_base { - using JustLambda = std_::decay_simple_t; - using LambdaPtr = std_::unique_ptr; - using Parent = lambda_wrap_helper_base; - static void construct_move_other_method(void *lambda, void *source) { - auto source_lambda = static_cast(source); - new (lambda) LambdaPtr(std_::move(*source_lambda)); - } - static void construct_move_lambda_method(void *lambda, void *source) { - auto source_lambda = static_cast(source); - new (lambda) LambdaPtr(std_::make_unique(static_cast(*source_lambda))); - } - static Return call_method(const void *lambda, Args... args) { - return (**static_cast(lambda))(std_::forward(args)...); - } - static void destruct_method(const void *lambda) { - static_cast(lambda)->~LambdaPtr(); - } - lambda_wrap_helper_move_impl() : Parent( - &Parent::bad_construct_copy, - &lambda_wrap_helper_move_impl::construct_move_other_method, - &lambda_wrap_helper_move_impl::call_method, - &lambda_wrap_helper_move_impl::destruct_method) { - } - -protected: - lambda_wrap_helper_move_impl( - typename Parent::construct_copy_other_type construct_copy_other - ) : Parent( - construct_copy_other, - &lambda_wrap_helper_move_impl::construct_move_other_method, - &lambda_wrap_helper_move_impl::call_method, - &lambda_wrap_helper_move_impl::destruct_method) { - } - -}; +// +// Disable large lambda support. +// If you really need it, just store data in some std_::unique_ptr. +// +//template +//struct lambda_wrap_helper_move_impl : public lambda_wrap_helper_base { +// using JustLambda = std_::decay_simple_t; +// using LambdaPtr = std_::unique_ptr; +// using Parent = lambda_wrap_helper_base; +// static void construct_move_other_method(void *lambda, void *source) { +// auto source_lambda = static_cast(source); +// new (lambda) LambdaPtr(std_::move(*source_lambda)); +// } +// static void construct_move_lambda_method(void *lambda, void *source) { +// auto source_lambda = static_cast(source); +// new (lambda) LambdaPtr(std_::make_unique(static_cast(*source_lambda))); +// } +// static Return call_method(const void *lambda, Args... args) { +// return (**static_cast(lambda))(std_::forward(args)...); +// } +// static void destruct_method(const void *lambda) { +// static_cast(lambda)->~LambdaPtr(); +// } +// lambda_wrap_helper_move_impl() : Parent( +// &Parent::bad_construct_copy, +// &lambda_wrap_helper_move_impl::construct_move_other_method, +// &lambda_wrap_helper_move_impl::call_method, +// &lambda_wrap_helper_move_impl::destruct_method) { +// } +// +//protected: +// lambda_wrap_helper_move_impl( +// typename Parent::construct_copy_other_type construct_copy_other +// ) : Parent( +// construct_copy_other, +// &lambda_wrap_helper_move_impl::construct_move_other_method, +// &lambda_wrap_helper_move_impl::call_method, +// &lambda_wrap_helper_move_impl::destruct_method) { +// } +// +//}; template struct lambda_wrap_helper_move_impl : public lambda_wrap_helper_base { @@ -137,6 +145,12 @@ struct lambda_wrap_helper_move_impl : new (lambda) JustLambda(static_cast(*source_lambda)); } static void construct_move_lambda_method(void *lambda, void *source) { + static_assert(alignof(JustLambda) <= alignof(void*), "Bad lambda alignment."); +#ifndef OS_MAC_OLD + auto space = sizeof(JustLambda); + auto aligned = std::align(alignof(JustLambda), space, lambda, space); + t_assert(aligned == lambda); +#endif // OS_MAC_OLD auto source_lambda = static_cast(source); new (lambda) JustLambda(static_cast(*source_lambda)); } @@ -177,23 +191,27 @@ const lambda_wrap_helper_move lambda_wrap_helper_move struct lambda_wrap_helper_copy_impl; -template -struct lambda_wrap_helper_copy_impl : public lambda_wrap_helper_move_impl { - using JustLambda = std_::decay_simple_t; - using LambdaPtr = std_::unique_ptr; - using Parent = lambda_wrap_helper_move_impl; - static void construct_copy_other_method(void *lambda, const void *source) { - auto source_lambda = static_cast(source); - new (lambda) LambdaPtr(std_::make_unique(*source_lambda->get())); - } - static void construct_copy_lambda_method(void *lambda, const void *source) { - auto source_lambda = static_cast(source); - new (lambda) LambdaPtr(std_::make_unique(static_cast(*source_lambda))); - } - lambda_wrap_helper_copy_impl() : Parent(&lambda_wrap_helper_copy_impl::construct_copy_other_method) { - } - -}; +// +// Disable large lambda support. +// If you really need it, just store data in some QSharedPointer. +// +//template +//struct lambda_wrap_helper_copy_impl : public lambda_wrap_helper_move_impl { +// using JustLambda = std_::decay_simple_t; +// using LambdaPtr = std_::unique_ptr; +// using Parent = lambda_wrap_helper_move_impl; +// static void construct_copy_other_method(void *lambda, const void *source) { +// auto source_lambda = static_cast(source); +// new (lambda) LambdaPtr(std_::make_unique(*source_lambda->get())); +// } +// static void construct_copy_lambda_method(void *lambda, const void *source) { +// auto source_lambda = static_cast(source); +// new (lambda) LambdaPtr(std_::make_unique(static_cast(*source_lambda))); +// } +// lambda_wrap_helper_copy_impl() : Parent(&lambda_wrap_helper_copy_impl::construct_copy_other_method) { +// } +// +//}; template struct lambda_wrap_helper_copy_impl : public lambda_wrap_helper_move_impl { @@ -204,6 +222,12 @@ struct lambda_wrap_helper_copy_impl : new (lambda) JustLambda(static_cast(*source_lambda)); } static void construct_copy_lambda_method(void *lambda, const void *source) { + static_assert(alignof(JustLambda) <= alignof(void*), "Bad lambda alignment."); +#ifndef OS_MAC_OLD + auto space = sizeof(JustLambda); + auto aligned = std::align(alignof(JustLambda), space, lambda, space); + t_assert(aligned == lambda); +#endif // OS_MAC_OLD auto source_lambda = static_cast(source); new (lambda) JustLambda(static_cast(*source_lambda)); } @@ -356,7 +380,7 @@ public: auto temp = other; this->helper_->destruct(this->storage_); this->helper_ = &internal::lambda_wrap_helper_copy::instance; - internal::lambda_wrap_helper_copy::construct_move_lambda_method(this->storage_, &other); + internal::lambda_wrap_helper_copy::construct_copy_lambda_method(this->storage_, &other); return *this; } @@ -373,48 +397,20 @@ public: } // namespace base -// While we still use Function<> +// While we still use rpcDone() and rpcFail() + +#include "mtproto/rpc_sender.h" template -struct LambdaFunctionHelper; +struct LambdaUniqueHelper; template -struct LambdaFunctionHelper { - using FunctionType = Function; +struct LambdaUniqueHelper { using UniqueType = base::lambda_unique; }; template -using LambdaGetFunction = typename LambdaFunctionHelper::FunctionType; - -template -using LambdaGetUnique = typename LambdaFunctionHelper::UniqueType; - -template -class LambdaFunctionImplementation : public FunctionImplementation { -public: - LambdaFunctionImplementation(base::lambda_unique &&lambda) : _lambda(std_::move(lambda)) { - } - R call(Args... args) override { return _lambda(std_::forward(args)...); } - -private: - base::lambda_unique _lambda; - -}; - -template -inline Function func_lambda_wrap_helper(base::lambda_unique &&lambda) { - return Function(new LambdaFunctionImplementation(std_::move(lambda))); -} - -template ::value>> -inline LambdaGetFunction func(Lambda &&lambda) { - return func_lambda_wrap_helper(LambdaGetUnique(std_::move(lambda))); -} - -// While we still use rpcDone() and rpcFail() - -#include "mtproto/rpc_sender.h" +using LambdaGetUnique = typename LambdaUniqueHelper::UniqueType; template class RPCHandlerImplementation : public Base { diff --git a/Telegram/SourceFiles/core/observer.cpp b/Telegram/SourceFiles/core/observer.cpp index cc9b9497f0..c354e16e39 100644 --- a/Telegram/SourceFiles/core/observer.cpp +++ b/Telegram/SourceFiles/core/observer.cpp @@ -21,99 +21,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.h" #include "core/observer.h" -namespace Notify { -namespace internal { -namespace { - -struct StartCallbackData { - void *that; - StartCallback call; -}; -struct FinishCallbackData { - void *that; - FinishCallback call; -}; -struct UnregisterCallbackData { - void *that; - UnregisterCallback call; -}; -using StartCallbacksList = QVector; -using FinishCallbacksList = QVector; -NeverFreedPointer StartCallbacks; -NeverFreedPointer FinishCallbacks; -UnregisterCallbackData UnregisterCallbacks[256]/* = { nullptr }*/; - -ObservedEvent LastRegisteredEvent/* = 0*/; - -} // namespace -} // namespace internal - -void startObservers() { - if (!internal::StartCallbacks) return; - - for (auto &callback : *internal::StartCallbacks) { - callback.call(callback.that); - } -} - -void finishObservers() { - if (!internal::FinishCallbacks) return; - - for (auto &callback : *internal::FinishCallbacks) { - callback.call(callback.that); - } - internal::StartCallbacks.clear(); - internal::FinishCallbacks.clear(); -} - -namespace internal { - -BaseObservedEventRegistrator::BaseObservedEventRegistrator(void *that -, StartCallback startCallback -, FinishCallback finishCallback -, UnregisterCallback unregisterCallback) { - _event = LastRegisteredEvent++; - - StartCallbacks.makeIfNull(); - StartCallbacks->push_back({ that, startCallback }); - - FinishCallbacks.makeIfNull(); - FinishCallbacks->push_back({ that, finishCallback }); - - UnregisterCallbacks[_event] = { that, unregisterCallback }; -} - -} // namespace internal - -// Observer base interface. -Observer::~Observer() { - for_const (auto connection, _connections) { - unregisterObserver(connection); - } -} - -void Observer::observerRegistered(ConnectionId connection) { - _connections.push_back(connection); -} - -void unregisterObserver(ConnectionId connection) { - auto event = static_cast(connection >> 24); - auto connectionIndex = int(connection & 0x00FFFFFFU) - 1; - auto &callback = internal::UnregisterCallbacks[event]; - if (connectionIndex >= 0 && callback.call && callback.that) { - callback.call(callback.that, connectionIndex); - } -} - -namespace internal { - -void observerRegisteredDefault(Observer *observer, ConnectionId connection) { - observer->observerRegistered(connection); -} - -} // namespace internal -} // namespace Notify - namespace base { namespace internal { namespace { diff --git a/Telegram/SourceFiles/core/observer.h b/Telegram/SourceFiles/core/observer.h index ef5ae1dc4f..0b220ce171 100644 --- a/Telegram/SourceFiles/core/observer.h +++ b/Telegram/SourceFiles/core/observer.h @@ -22,230 +22,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "core/vector_of_moveable.h" -namespace Notify { - -using ConnectionId = uint32; - -// startObservers() must be called after main() started (not in a global variable constructor). -// finishObservers() must be called before main() finished (not in a global variable destructor). -void startObservers(); -void finishObservers(); - -using StartObservedEventCallback = void(*)(); -using FinishObservedEventCallback = void(*)(); - -namespace internal { - -using ObservedEvent = uchar; -using StartCallback = void(*)(void*); -using FinishCallback = void(*)(void*); -using UnregisterCallback = void(*)(void*,int connectionIndex); - -class BaseObservedEventRegistrator { -public: - BaseObservedEventRegistrator(void *that - , StartCallback startCallback - , FinishCallback finishCallback - , UnregisterCallback unregisterCallback); - -protected: - inline ObservedEvent event() const { - return _event; - } - -private: - ObservedEvent _event; - -}; - -// Handler is one of Function<> instantiations. -template -struct ObserversList { - struct Entry { - Flags flags; - Handler handler; - }; - std_::vector_of_moveable entries; - QVector freeIndices; -}; - -// If no filtering by flags is done, you can use Flags=int and this value. -constexpr int UniversalFlag = 0x01; - -} // namespace internal - -// Objects of this class should be constructed in global scope. -// startCallback will be called from Notify::startObservers(). -// finishCallback will be called from Notify::finishObservers(). -template -class ObservedEventRegistrator : public internal::BaseObservedEventRegistrator { -public: - ObservedEventRegistrator(StartObservedEventCallback startCallback, - FinishObservedEventCallback finishCallback) : internal::BaseObservedEventRegistrator(static_cast(this), - ObservedEventRegistrator::start, - ObservedEventRegistrator::finish, - ObservedEventRegistrator::unregister) - , _startCallback(startCallback), _finishCallback(finishCallback) { - } - - bool started() const { - return _list != nullptr; - } - - ConnectionId registerObserver(Flags flags, Handler &&handler) { - t_assert(started()); - - int connectionIndex = doRegisterObserver(flags, std_::forward(handler)); - return (static_cast(event()) << 24) | static_cast(connectionIndex + 1); - } - - template - void notify(Flags flags, Args&&... args) { - t_assert(started()); - - auto &entries = _list->entries; - // This way of iterating (i < entries.size() should be used - // because some entries can be removed from the end of the - // entries list while the loop is still running. - for (int i = 0; i < entries.size(); ++i) { - auto &entry = entries[i]; - if (!entry.handler.isNull() && (flags & entry.flags)) { - entry.handler.call(std_::forward(args)...); - } - } - } - -private: - using Self = ObservedEventRegistrator; - static void start(void *vthat) { - Self *that = static_cast(vthat); - - t_assert(!that->started()); - if (that->_startCallback) that->_startCallback(); - that->_list = new internal::ObserversList(); - } - static void finish(void *vthat) { - Self *that = static_cast(vthat); - - if (that->_finishCallback) that->_finishCallback(); - delete that->_list; - that->_list = nullptr; - } - static void unregister(void *vthat, int connectionIndex) { - Self *that = static_cast(vthat); - - t_assert(that->started()); - - auto &entries = that->_list->entries; - if (entries.size() <= connectionIndex) return; - - if (entries.size() == connectionIndex + 1) { - for (entries.pop_back(); !entries.isEmpty() && entries.back().handler.isNull();) { - entries.pop_back(); - } - } else { - entries[connectionIndex].handler = Handler(); - that->_list->freeIndices.push_back(connectionIndex); - } - } - - int doRegisterObserver(Flags flags, Handler &&handler) { - while (!_list->freeIndices.isEmpty()) { - auto freeIndex = _list->freeIndices.back(); - _list->freeIndices.pop_back(); - - if (freeIndex < _list->entries.size()) { - _list->entries[freeIndex] = { flags, std_::move(handler) }; - return freeIndex; - } - } - _list->entries.push_back({ flags, std_::move(handler) }); - return _list->entries.size() - 1; - } - - StartObservedEventCallback _startCallback; - FinishObservedEventCallback _finishCallback; - internal::ObserversList *_list = nullptr; - -}; - -// If no filtering of notifications by Flags is intended use this class. -template -class SimpleObservedEventRegistrator { -public: - SimpleObservedEventRegistrator(StartObservedEventCallback startCallback, - FinishObservedEventCallback finishCallback) : _implementation(startCallback, finishCallback) { - } - - bool started() const { - return _implementation.started(); - } - - ConnectionId registerObserver(Handler &&handler) { - return _implementation.registerObserver(internal::UniversalFlag, std_::forward(handler)); - } - - template - void notify(Args&&... args) { - return _implementation.notify(internal::UniversalFlag, std_::forward(args)...); - } - -private: - ObservedEventRegistrator _implementation; - -}; - -// Each observer type should have observerRegistered(Notify::ConnectionId connection) method. -// Usually it is done by deriving the type from the Notify::Observer base class. -// In destructor it should call Notify::unregisterObserver(connection) for all the connections. - -class Observer; -namespace internal { -void observerRegisteredDefault(Observer *observer, ConnectionId connection); -} // namespace internal - -void unregisterObserver(ConnectionId connection); - -class Observer { -public: - virtual ~Observer() = 0; - -private: - void observerRegistered(ConnectionId connection); - friend void internal::observerRegisteredDefault(Observer *observer, ConnectionId connection); - - QVector _connections; - -}; - -namespace internal { - -template -struct ObserverRegisteredGeneric { - static inline void call(ObserverType *observer, ConnectionId connection) { - observer->observerRegistered(connection); - } -}; - -template -struct ObserverRegisteredGeneric { - static inline void call(ObserverType *observer, ConnectionId connection) { - observerRegisteredDefault(observer, connection); - } -}; - -} // namespace internal - -template -inline void observerRegistered(ObserverType *observer, ConnectionId connection) { - // For derivatives of the Observer class we call special friend function observerRegistered(). - // For all other classes we call just a member function observerRegistered(). - using ObserverRegistered = internal::ObserverRegisteredGeneric::value>; - ObserverRegistered::call(observer, connection); -} - -} // namespace Notify - namespace base { namespace internal { @@ -271,10 +47,10 @@ using SubscriptionHandler = typename SubscriptionHandlerHelper::type; class BaseObservableData { }; -template +template class CommonObservableData; -template +template class ObservableData; } // namespace internal @@ -317,43 +93,41 @@ private: Node *_node = nullptr; RemoveMethod _removeMethod; - template + template friend class internal::CommonObservableData; - template + template friend class internal::ObservableData; }; -template +template class Observable; namespace internal { -template +template class CommonObservable { public: - using Handler = typename CommonObservableData::Handler; - Subscription add_subscription(Handler &&handler) { if (!_data) { - _data = MakeShared>(this); + _data = MakeShared>(this); } return _data->append(std_::forward(handler)); } private: - QSharedPointer> _data; + QSharedPointer> _data; - friend class CommonObservableData; - friend class Observable; + friend class CommonObservableData; + friend class Observable; }; } // namespace internal -template -class Observable : public internal::CommonObservable { +template > +class Observable : public internal::CommonObservable { public: void notify(EventType &&event, bool sync = false) { if (this->_data) { @@ -368,12 +142,10 @@ public: namespace internal { -template +template class CommonObservableData : public BaseObservableData { public: - using Handler = SubscriptionHandler; - - CommonObservableData(CommonObservable *observable) : _observable(observable) { + CommonObservableData(CommonObservable *observable) : _observable(observable) { } Subscription append(Handler &&handler) { @@ -444,20 +216,20 @@ private: } } - CommonObservable *_observable = nullptr; + CommonObservable *_observable = nullptr; Node *_begin = nullptr; Node *_current = nullptr; Node *_end = nullptr; ObservableCallHandlers _callHandlers; - friend class ObservableData; + friend class ObservableData; }; -template -class ObservableData : public CommonObservableData { +template +class ObservableData : public CommonObservableData { public: - using CommonObservableData::CommonObservableData; + using CommonObservableData::CommonObservableData; void notify(EventType &&event, bool sync) { if (_handling) { @@ -501,10 +273,10 @@ private: }; -template <> -class ObservableData : public CommonObservableData { +template +class ObservableData : public CommonObservableData { public: - using CommonObservableData::CommonObservableData; + using CommonObservableData::CommonObservableData; void notify(bool sync) { if (_handling) { @@ -514,20 +286,20 @@ public: ++_eventsCount; callHandlers(); } else { - if (!_callHandlers) { - _callHandlers = [this]() { + if (!this->_callHandlers) { + this->_callHandlers = [this]() { callHandlers(); }; } if (!_eventsCount) { - RegisterPendingObservable(&_callHandlers); + RegisterPendingObservable(&this->_callHandlers); } ++_eventsCount; } } ~ObservableData() { - UnregisterObservable(&_callHandlers); + UnregisterObservable(&this->_callHandlers); } private: @@ -535,12 +307,12 @@ private: _handling = true; auto eventsCount = createAndSwap(_eventsCount); for (int i = 0; i != eventsCount; ++i) { - notifyEnumerate([this]() { - _current->handler(); + this->notifyEnumerate([this]() { + this->_current->handler(); }); } _handling = false; - UnregisterActiveObservable(&_callHandlers); + UnregisterActiveObservable(&this->_callHandlers); } int _eventsCount = 0; @@ -550,12 +322,12 @@ private: } // namespace internal -template <> -class Observable : public internal::CommonObservable { +template +class Observable : public internal::CommonObservable { public: void notify(bool sync = false) { - if (_data) { - _data->notify(sync); + if (this->_data) { + this->_data->notify(sync); } } @@ -563,14 +335,14 @@ public: class Subscriber { protected: - template - int subscribe(base::Observable &observable, Lambda &&handler) { + template + int subscribe(base::Observable &observable, Lambda &&handler) { _subscriptions.push_back(observable.add_subscription(std_::forward(handler))); return _subscriptions.size() - 1; } - template - int subscribe(base::Observable *observable, Lambda &&handler) { + template + int subscribe(base::Observable *observable, Lambda &&handler) { return subscribe(*observable, std_::forward(handler)); } diff --git a/Telegram/SourceFiles/core/vector_of_moveable.h b/Telegram/SourceFiles/core/vector_of_moveable.h index fbc9bd4b9f..6d34bdb834 100644 --- a/Telegram/SourceFiles/core/vector_of_moveable.h +++ b/Telegram/SourceFiles/core/vector_of_moveable.h @@ -93,6 +93,7 @@ public: *prev = std_::move(*next); } --_size; + end()->~T(); return it; } @@ -143,15 +144,21 @@ public: } inline const T &at(int index) const { if (index < 0 || index >= _size) { -#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0) - throw std::exception(); -#else // QT_VERSION < 5.5.0 +#ifndef OS_MAC_OLD throw std::out_of_range(""); -#endif // QT_VERSION < 5.5.0 +#else // OS_MAC_OLD + throw std::exception(); +#endif // OS_MAC_OLD } return data()[index]; } + void reserve(int newCapacity) { + if (newCapacity > _capacity) { + reallocate(newCapacity); + } + } + inline ~vector_of_moveable() { clear(); } diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index 23ee2bd5b0..87b63fb6a2 100644 --- a/Telegram/SourceFiles/core/version.h +++ b/Telegram/SourceFiles/core/version.h @@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "core/basic_types.h" -#define BETA_VERSION_MACRO (0ULL) +#define BETA_VERSION_MACRO (10008001ULL) constexpr int AppVersion = 10008; constexpr str_const AppVersionStr = "0.10.8"; diff --git a/Telegram/SourceFiles/dialogswidget.cpp b/Telegram/SourceFiles/dialogswidget.cpp index eed96774f3..38e9caf2b3 100644 --- a/Telegram/SourceFiles/dialogswidget.cpp +++ b/Telegram/SourceFiles/dialogswidget.cpp @@ -46,13 +46,15 @@ DialogsInner::DialogsInner(QWidget *parent, MainWidget *main) : SplittedWidget(p if (Global::DialogsModeEnabled()) { importantDialogs = std_::make_unique(Dialogs::SortMode::Date); } - connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); connect(main, SIGNAL(peerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&)), this, SLOT(onPeerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&))); connect(main, SIGNAL(peerPhotoChanged(PeerData*)), this, SLOT(onPeerPhotoChanged(PeerData*))); connect(main, SIGNAL(dialogRowReplaced(Dialogs::Row*,Dialogs::Row*)), this, SLOT(onDialogRowReplaced(Dialogs::Row*,Dialogs::Row*))); connect(&_addContactLnk, SIGNAL(clicked()), App::wnd(), SLOT(onShowAddContact())); connect(&_cancelSearchInPeer, SIGNAL(clicked()), this, SIGNAL(cancelSearchInPeer())); _cancelSearchInPeer.hide(); + + subscribe(FileDownload::ImageLoaded(), [this] { update(); }); + refresh(); } diff --git a/Telegram/SourceFiles/dialogswidget.h b/Telegram/SourceFiles/dialogswidget.h index 8891478f6c..743705025d 100644 --- a/Telegram/SourceFiles/dialogswidget.h +++ b/Telegram/SourceFiles/dialogswidget.h @@ -42,7 +42,7 @@ enum DialogsSearchRequestType { DialogsSearchMigratedFromOffset, }; -class DialogsInner : public SplittedWidget, public RPCSender { +class DialogsInner : public SplittedWidget, public RPCSender, private base::Subscriber { Q_OBJECT public: diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index 05a513636c..53c8d32dba 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org class LayerWidget; namespace base { -template +template class Observable; } // namespace base namespace InlineBots { diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 77d143b589..021a22197f 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -574,6 +574,15 @@ History *Histories::find(const PeerId &peerId) { return (i == map.cend()) ? 0 : i.value(); } +History *Histories::findOrInsert(const PeerId &peerId) { + auto i = map.constFind(peerId); + if (i == map.cend()) { + auto history = peerIsChannel(peerId) ? static_cast(new ChannelHistory(peerId)) : (new History(peerId)); + i = map.insert(peerId, history); + } + return i.value(); +} + History *Histories::findOrInsert(const PeerId &peerId, int32 unreadCount, int32 maxInboxRead, int32 maxOutboxRead) { auto i = map.constFind(peerId); if (i == map.cend()) { @@ -584,10 +593,10 @@ History *Histories::findOrInsert(const PeerId &peerId, int32 unreadCount, int32 history->outboxReadBefore = maxOutboxRead + 1; } else { auto history = i.value(); - if (unreadCount >= history->unreadCount()) { + if (unreadCount > history->unreadCount()) { history->setUnreadCount(unreadCount); - history->inboxReadBefore = maxInboxRead + 1; } + accumulate_max(history->inboxReadBefore, maxInboxRead + 1); accumulate_max(history->outboxReadBefore, maxOutboxRead + 1); } return i.value(); @@ -1442,8 +1451,8 @@ MsgId History::inboxRead(MsgId upTo) { updateChatListEntry(); if (peer->migrateTo()) { - if (History *h = App::historyLoaded(peer->migrateTo()->id)) { - h->updateChatListEntry(); + if (auto migrateTo = App::historyLoaded(peer->migrateTo()->id)) { + migrateTo->updateChatListEntry(); } } @@ -2635,10 +2644,12 @@ void HistoryMessageReplyMarkup::create(const MTPReplyMarkup &markup) { } } -void HistoryDependentItemCallback::call(ChannelData *channel, MsgId msgId) const { - if (HistoryItem *item = App::histItemById(_dependent)) { - item->updateDependencyItem(); - } +ApiWrap::RequestMessageDataCallback historyDependentItemCallback(const FullMsgId &msgId) { + return [dependent = msgId](ChannelData *channel, MsgId msgId) { + if (HistoryItem *item = App::histItemById(dependent)) { + item->updateDependencyItem(); + } + }; } void HistoryMessageUnreadBar::init(int count) { @@ -4901,7 +4912,9 @@ bool HistoryGif::playInline(bool autoplay) { if (!cAutoPlayGif()) { App::stopGifItems(); } - _gif = new Media::Clip::Reader(_data->location(), _data->data(), func(_parent, &HistoryItem::clipCallback)); + _gif = new Media::Clip::Reader(_data->location(), _data->data(), [this](Media::Clip::Notification notification) { + _parent->clipCallback(notification); + }); App::regGifItem(_gif, _parent); if (gif()) _gif->setAutoplay(); } @@ -6828,7 +6841,7 @@ void HistoryMessage::createComponents(const CreateConfig &config) { if (auto reply = Get()) { reply->replyToMsgId = config.replyTo; if (!reply->updateData(this) && App::api()) { - App::api()->requestMessageData(history()->peer->asChannel(), reply->replyToMsgId, std_::make_unique(fullId())); + App::api()->requestMessageData(history()->peer->asChannel(), reply->replyToMsgId, historyDependentItemCallback(fullId())); } } if (auto via = Get()) { @@ -8379,7 +8392,7 @@ void HistoryService::createFromMtp(const MTPDmessageService &message) { if (auto dependent = GetDependentData()) { dependent->msgId = message.vreply_to_msg_id.v; if (!updateDependent() && App::api()) { - App::api()->requestMessageData(history()->peer->asChannel(), dependent->msgId, std_::make_unique(fullId())); + App::api()->requestMessageData(history()->peer->asChannel(), dependent->msgId, historyDependentItemCallback(fullId())); } } } diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index 72cc5f101e..ecba44ef3e 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -48,6 +48,7 @@ public: void step_typings(uint64 ms, bool timer); History *find(const PeerId &peerId); + History *findOrInsert(const PeerId &peerId); History *findOrInsert(const PeerId &peerId, int32 unreadCount, int32 maxInboxRead, int32 maxOutboxRead); void clear(); @@ -934,17 +935,6 @@ private: StylePtr _st; }; -class HistoryDependentItemCallback : public SharedCallback { -public: - HistoryDependentItemCallback(FullMsgId dependent) : _dependent(dependent) { - } - void call(ChannelData *channel, MsgId msgId) const override; - -private: - FullMsgId _dependent; - -}; - // any HistoryItem can have this Interface for // displaying the day mark above the message struct HistoryMessageDate : public BaseComponent { diff --git a/Telegram/SourceFiles/history/field_autocomplete.cpp b/Telegram/SourceFiles/history/field_autocomplete.cpp index bf8687542c..5b710363fc 100644 --- a/Telegram/SourceFiles/history/field_autocomplete.cpp +++ b/Telegram/SourceFiles/history/field_autocomplete.cpp @@ -44,8 +44,6 @@ FieldAutocomplete::FieldAutocomplete(QWidget *parent) : TWidget(parent) connect(_inner, SIGNAL(stickerChosen(DocumentData*,FieldAutocomplete::ChooseMethod)), this, SIGNAL(stickerChosen(DocumentData*,FieldAutocomplete::ChooseMethod))); connect(_inner, SIGNAL(mustScrollTo(int, int)), _scroll, SLOT(scrollToY(int, int))); - connect(App::wnd(), SIGNAL(imageLoaded()), _inner, SLOT(update())); - setFocusPolicy(Qt::NoFocus); _scroll->setFocusPolicy(Qt::NoFocus); _scroll->viewport()->setFocusPolicy(Qt::NoFocus); @@ -539,6 +537,7 @@ FieldAutocompleteInner::FieldAutocompleteInner(FieldAutocomplete *parent, Mentio , _previewShown(false) { _previewTimer.setSingleShot(true); connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreview())); + subscribe(FileDownload::ImageLoaded(), [this] { update(); }); } void FieldAutocompleteInner::paintEvent(QPaintEvent *e) { @@ -933,7 +932,4 @@ void FieldAutocompleteInner::onPreview() { } } -FieldAutocompleteInner::~FieldAutocompleteInner() { -} - } // namespace internal diff --git a/Telegram/SourceFiles/history/field_autocomplete.h b/Telegram/SourceFiles/history/field_autocomplete.h index 71b4cba99d..9f824a8297 100644 --- a/Telegram/SourceFiles/history/field_autocomplete.h +++ b/Telegram/SourceFiles/history/field_autocomplete.h @@ -138,7 +138,7 @@ private: namespace internal { -class FieldAutocompleteInner final : public TWidget { +class FieldAutocompleteInner final : public TWidget, private base::Subscriber { Q_OBJECT public: @@ -150,8 +150,6 @@ public: void setRecentInlineBotsInRows(int32 bots); - ~FieldAutocompleteInner(); - signals: void mentionChosen(UserData *user, FieldAutocomplete::ChooseMethod method) const; void hashtagChosen(QString hashtag, FieldAutocomplete::ChooseMethod method) const; diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 1acf31a2d4..e956aaecf9 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -101,6 +101,14 @@ public: constexpr int ScrollDateHideTimeout = 1000; +ApiWrap::RequestMessageDataCallback replyEditMessageDataCallback() { + return [](ChannelData *channel, MsgId msgId) { + if (App::main()) { + App::main()->messageDataReceived(channel, msgId); + } + }; +} + } // namespace // flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html @@ -1684,7 +1692,7 @@ void HistoryInner::toggleScrollDateShown() { _scrollDateShown = !_scrollDateShown; auto from = _scrollDateShown ? 0. : 1.; auto to = _scrollDateShown ? 1. : 0.; - START_ANIMATION(_scrollDateOpacity, func(this, &HistoryInner::repaintScrollDateCallback), from, to, st::btnAttachEmoji.duration, anim::linear); + _scrollDateOpacity.start([this] { repaintScrollDateCallback(); }, from, to, st::btnAttachEmoji.duration); } void HistoryInner::repaintScrollDateCallback() { @@ -3032,7 +3040,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent) setAcceptDrops(true); - connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); + subscribe(FileDownload::ImageLoaded(), [this] { update(); }); connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); connect(&_reportSpamPanel, SIGNAL(reportClicked()), this, SLOT(onReportSpamClicked())); connect(&_reportSpamPanel, SIGNAL(hideClicked()), this, SLOT(onReportSpamHide())); @@ -4117,7 +4125,7 @@ void HistoryWidget::applyDraft(bool parseLinks) { if (_editMsgId || _replyToId) { updateReplyEditTexts(); if (!_replyEditMsg && App::api()) { - App::api()->requestMessageData(_peer->asChannel(), _editMsgId ? _editMsgId : _replyToId, std_::make_unique()); + App::api()->requestMessageData(_peer->asChannel(), _editMsgId ? _editMsgId : _replyToId, replyEditMessageDataCallback()); } } } @@ -7633,7 +7641,7 @@ bool HistoryWidget::pinnedMsgVisibilityUpdated() { update(); } if (!_pinnedBar->msg && App::api()) { - App::api()->requestMessageData(_peer->asChannel(), _pinnedBar->msgId, std_::make_unique()); + App::api()->requestMessageData(_peer->asChannel(), _pinnedBar->msgId, replyEditMessageDataCallback()); } } else if (_pinnedBar) { destroyPinnedBar(); @@ -7652,12 +7660,6 @@ void HistoryWidget::destroyPinnedBar() { _inPinnedMsg = false; } -void HistoryWidget::ReplyEditMessageDataCallback::call(ChannelData *channel, MsgId msgId) const { - if (App::main()) { - App::main()->messageDataReceived(channel, msgId); - } -} - bool HistoryWidget::sendExistingDocument(DocumentData *doc, const QString &caption) { if (!_history || !doc || !canSendMessages(_peer)) { return false; diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index e875851208..ab8d8282c8 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -908,11 +908,6 @@ private: void destroyPinnedBar(); void unpinDone(const MTPUpdates &updates); - class ReplyEditMessageDataCallback : public SharedCallback { - public: - void call(ChannelData *channel, MsgId msgId) const override; - }; - bool sendExistingDocument(DocumentData *doc, const QString &caption); void sendExistingPhoto(PhotoData *photo, const QString &caption); diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp index 28eb740445..d03c778d15 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp @@ -135,7 +135,9 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons bool loaded = document->loaded(), loading = document->loading(), displayLoading = document->displayLoading(); if (loaded && !gif() && _gif != Media::Clip::BadReader) { Gif *that = const_cast(this); - that->_gif = new Media::Clip::Reader(document->location(), document->data(), func(that, &Gif::clipCallback)); + that->_gif = new Media::Clip::Reader(document->location(), document->data(), [that](Media::Clip::Notification notification) { + that->clipCallback(notification); + }); if (gif()) _gif->setAutoplay(); } @@ -165,9 +167,9 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons } if (radial || (!_gif && !loaded && !loading) || (_gif == Media::Clip::BadReader)) { - float64 radialOpacity = (radial && loaded) ? _animation->radial.opacity() : 1; + auto radialOpacity = (radial && loaded) ? _animation->radial.opacity() : 1.; if (_animation && _animation->_a_over.animating(context->ms)) { - float64 over = _animation->_a_over.current(); + auto over = _animation->_a_over.current(); p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over)); p.fillRect(r, st::black); } else { @@ -219,7 +221,7 @@ void Gif::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { bool wasactive = (_state & StateFlag::DeleteOver); if (active != wasactive) { auto from = active ? 0. : 1., to = active ? 1. : 0.; - START_ANIMATION(_a_deleteOver, func(this, &Gif::update), from, to, st::stickersRowDuration, anim::linear); + _a_deleteOver.start([this] { update(); }, from, to, st::stickersRowDuration); if (active) { _state |= StateFlag::DeleteOver; } else { @@ -233,7 +235,7 @@ void Gif::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { if (!getShownDocument()->loaded()) { ensureAnimation(); auto from = active ? 0. : 1., to = active ? 1. : 0.; - START_ANIMATION(_animation->_a_over, func(this, &Gif::update), from, to, st::stickersRowDuration, anim::linear); + _animation->_a_over.start([this] { update(); }, from, to, st::stickersRowDuration); } if (active) { _state |= StateFlag::Over; @@ -386,7 +388,7 @@ void Sticker::preload() const { void Sticker::paint(Painter &p, const QRect &clip, const PaintContext *context) const { bool loaded = getShownDocument()->loaded(); - float64 over = _a_over.isNull() ? (_active ? 1 : 0) : _a_over.current(); + auto over = _a_over.current(_active ? 1. : 0.); if (over > 0) { p.setOpacity(over); App::roundRect(p, QRect(QPoint(0, 0), st::stickerPanSize), st::emojiPanHover, StickerHoverCorners); @@ -415,7 +417,7 @@ void Sticker::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { _active = active; auto from = active ? 0. : 1., to = active ? 1. : 0.; - START_ANIMATION(_a_over, func(this, &Sticker::update), from, to, st::stickersRowDuration, anim::linear); + _a_over.start([this] { update(); }, from, to, st::stickersRowDuration); } } ItemBase::clickHandlerActiveChanged(p, active); diff --git a/Telegram/SourceFiles/layerwidget.cpp b/Telegram/SourceFiles/layerwidget.cpp index 5c11325681..fb5374dd31 100644 --- a/Telegram/SourceFiles/layerwidget.cpp +++ b/Telegram/SourceFiles/layerwidget.cpp @@ -437,7 +437,7 @@ MediaPreviewWidget::MediaPreviewWidget(QWidget *parent) : TWidget(parent) , _a_shown(animation(this, &MediaPreviewWidget::step_shown)) , _emojiSize(EmojiSizes[EIndex + 1] / cIntRetinaFactor()) { setAttribute(Qt::WA_TransparentForMouseEvents); - connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); + subscribe(FileDownload::ImageLoaded(), [this] { update(); }); } void MediaPreviewWidget::paintEvent(QPaintEvent *e) { @@ -456,11 +456,11 @@ void MediaPreviewWidget::paintEvent(QPaintEvent *e) { p.drawPixmap((width() - w) / 2, (height() - h) / 2, image); if (!_emojiList.isEmpty()) { int emojiCount = _emojiList.size(); - int emojiWidth = emojiCount * _emojiSize + (emojiCount - 1) * st::stickerEmojiSkip; + int emojiWidth = (emojiCount * _emojiSize) + (emojiCount - 1) * st::stickerEmojiSkip; int emojiLeft = (width() - emojiWidth) / 2; - int esize = _emojiSize * cIntRetinaFactor(); + int esize = EmojiSizes[EIndex + 1]; for_const (auto emoji, _emojiList) { - p.drawPixmapLeft(emojiLeft, (height() - h) / 2 - _emojiSize * 2, width(), App::emojiLarge(), QRect(emoji->x * esize, emoji->y * esize, esize, esize)); + p.drawPixmapLeft(emojiLeft, (height() - h) / 2 - (_emojiSize * 2), width(), App::emojiLarge(), QRect(emoji->x * esize, emoji->y * esize, esize, esize)); emojiLeft += _emojiSize + st::stickerEmojiSkip; } } @@ -638,7 +638,9 @@ QPixmap MediaPreviewWidget::currentImage() const { if (_document->loaded()) { if (!_gif && _gif != Media::Clip::BadReader) { auto that = const_cast(this); - that->_gif = new Media::Clip::Reader(_document->location(), _document->data(), func(that, &MediaPreviewWidget::clipCallback)); + that->_gif = new Media::Clip::Reader(_document->location(), _document->data(), [this, that](Media::Clip::Notification notification) { + that->clipCallback(notification); + }); if (gif()) _gif->setAutoplay(); } } diff --git a/Telegram/SourceFiles/layerwidget.h b/Telegram/SourceFiles/layerwidget.h index 14d1fbc84e..3161e00435 100644 --- a/Telegram/SourceFiles/layerwidget.h +++ b/Telegram/SourceFiles/layerwidget.h @@ -129,7 +129,7 @@ private: }; -class MediaPreviewWidget : public TWidget { +class MediaPreviewWidget : public TWidget, private base::Subscriber { Q_OBJECT public: diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index bc86c12692..87117f65e6 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -2897,18 +2897,18 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha bool isFinal = true; switch (diff.type()) { case mtpc_updates_channelDifferenceEmpty: { - const auto &d(diff.c_updates_channelDifferenceEmpty()); + auto &d = diff.c_updates_channelDifferenceEmpty(); if (d.has_timeout()) timeout = d.vtimeout.v; isFinal = d.is_final(); channel->ptsInit(d.vpts.v); } break; case mtpc_updates_channelDifferenceTooLong: { - const auto &d(diff.c_updates_channelDifferenceTooLong()); + auto &d = diff.c_updates_channelDifferenceTooLong(); App::feedUsers(d.vusers); App::feedChats(d.vchats); - History *h = App::historyLoaded(channel->id); + auto h = App::historyLoaded(channel->id); if (h) { h->setNotLoadedAtBottom(); } @@ -2934,7 +2934,7 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha } break; case mtpc_updates_channelDifference: { - const auto &d(diff.c_updates_channelDifference()); + auto &d = diff.c_updates_channelDifference(); App::feedUsers(d.vusers); App::feedChats(d.vchats); @@ -2943,11 +2943,11 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha feedMessageIds(d.vother_updates); // feed messages and groups, copy from App::feedMsgs - History *h = App::history(channel->id); - const auto &vmsgs(d.vnew_messages.c_vector().v); - QMap msgsIds; - for (int32 i = 0, l = vmsgs.size(); i < l; ++i) { - const auto &msg(vmsgs.at(i)); + auto h = App::history(channel->id); + auto &vmsgs = d.vnew_messages.c_vector().v; + QMap msgsIds; + for (int i = 0, l = vmsgs.size(); i < l; ++i) { + auto &msg = vmsgs[i]; switch (msg.type()) { case mtpc_message: { const auto &d(msg.c_message()); @@ -2961,9 +2961,9 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha case mtpc_messageService: msgsIds.insert((uint64(uint32(msg.c_messageService().vid.v)) << 32) | uint64(i), i + 1); break; } } - for (QMap::const_iterator i = msgsIds.cbegin(), e = msgsIds.cend(); i != e; ++i) { - if (i.value() > 0) { // add message - const auto &msg(vmsgs.at(i.value() - 1)); + for_const (auto msgIndex, msgsIds) { + if (msgIndex > 0) { // add message + auto &msg = vmsgs.at(msgIndex - 1); if (channel->id != peerFromMessage(msg)) { LOG(("API Error: message with invalid peer returned in channelDifference, channelId: %1, peer: %2").arg(peerToChannel(channel->id)).arg(peerFromMessage(msg))); continue; // wtf @@ -4043,7 +4043,7 @@ DataIsLoadedResult allDataLoadedForMessage(const MTPMessage &msg) { void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { switch (updates.type()) { case mtpc_updates: { - const auto &d(updates.c_updates()); + auto &d = updates.c_updates(); if (d.vseq.v) { if (d.vseq.v <= updSeq) return; if (d.vseq.v > updSeq + 1) { @@ -4060,7 +4060,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { } break; case mtpc_updatesCombined: { - const auto &d(updates.c_updatesCombined()); + auto &d = updates.c_updatesCombined(); if (d.vseq_start.v) { if (d.vseq_start.v <= updSeq) return; if (d.vseq_start.v > updSeq + 1) { @@ -4077,15 +4077,14 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { } break; case mtpc_updateShort: { - const auto &d(updates.c_updateShort()); - + auto &d = updates.c_updateShort(); feedUpdate(d.vupdate); updSetState(0, d.vdate.v, updQts, updSeq); } break; case mtpc_updateShortMessage: { - const auto &d(updates.c_updateShortMessage()); + auto &d = updates.c_updateShortMessage(); if (!App::userLoaded(d.vuser_id.v) || (d.has_via_bot_id() && !App::userLoaded(d.vvia_bot_id.v)) || (d.has_entities() && !mentionUsersLoaded(d.ventities)) @@ -4099,7 +4098,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { // update before applying skipped MTPDmessage::Flags flags = mtpCastFlags(d.vflags.v) | MTPDmessage::Flag::f_from_id; - HistoryItem *item = App::histories().addNewMessage(MTP_message(MTP_flags(flags), d.vid, d.is_out() ? MTP_int(MTP::authedId()) : d.vuser_id, MTP_peerUser(d.is_out() ? d.vuser_id : MTP_int(MTP::authedId())), d.vfwd_from, d.vvia_bot_id, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint()), NewMessageUnread); + auto item = App::histories().addNewMessage(MTP_message(MTP_flags(flags), d.vid, d.is_out() ? MTP_int(MTP::authedId()) : d.vuser_id, MTP_peerUser(d.is_out() ? d.vuser_id : MTP_int(MTP::authedId())), d.vfwd_from, d.vvia_bot_id, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint()), NewMessageUnread); if (item) { _history->peerMessagesUpdated(item->history()->peer->id); } @@ -4110,7 +4109,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { } break; case mtpc_updateShortChatMessage: { - const auto &d(updates.c_updateShortChatMessage()); + auto &d = updates.c_updateShortChatMessage(); bool noFrom = !App::userLoaded(d.vfrom_id.v); if (!App::chatLoaded(d.vchat_id.v) || noFrom @@ -4127,7 +4126,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { // update before applying skipped MTPDmessage::Flags flags = mtpCastFlags(d.vflags.v) | MTPDmessage::Flag::f_from_id; - HistoryItem *item = App::histories().addNewMessage(MTP_message(MTP_flags(flags), d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), d.vfwd_from, d.vvia_bot_id, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint()), NewMessageUnread); + auto item = App::histories().addNewMessage(MTP_message(MTP_flags(flags), d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), d.vfwd_from, d.vvia_bot_id, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint()), NewMessageUnread); if (item) { _history->peerMessagesUpdated(item->history()->peer->id); } @@ -4138,7 +4137,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { } break; case mtpc_updateShortSentMessage: { - const auto &d(updates.c_updateShortSentMessage()); + auto &d = updates.c_updateShortSentMessage(); if (randomId) { PeerId peerId = 0; QString text; @@ -4148,7 +4147,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { if (peerId) { if (auto item = App::histItemById(peerToChannel(peerId), d.vid.v)) { if (d.has_entities() && !mentionUsersLoaded(d.ventities)) { - api()->requestMessageData(item->history()->peer->asChannel(), item->id, nullptr); + api()->requestMessageData(item->history()->peer->asChannel(), item->id, ApiWrap::RequestMessageDataCallback()); } auto entities = d.has_entities() ? entitiesFromMTP(d.ventities.c_vector().v) : EntitiesInText(); item->setText({ text, entities }); @@ -4524,13 +4523,13 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updatePrivacy: { - const auto &d(update.c_updatePrivacy()); + auto &d = update.c_updatePrivacy(); } break; /////// Channel updates case mtpc_updateChannel: { - const auto &d(update.c_updateChannel()); - if (ChannelData *channel = App::channelLoaded(d.vchannel_id.v)) { + auto &d = update.c_updateChannel(); + if (auto channel = App::channelLoaded(d.vchannel_id.v)) { App::markPeerUpdated(channel); channel->inviter = 0; if (!channel->amIn()) { @@ -4544,7 +4543,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { case mtpc_updateNewChannelMessage: { auto &d = update.c_updateNewChannelMessage(); - ChannelData *channel = App::channelLoaded(peerToChannel(peerFromMessage(d.vmessage))); + auto channel = App::channelLoaded(peerToChannel(peerFromMessage(d.vmessage))); DataIsLoadedResult isDataLoaded = allDataLoadedForMessage(d.vmessage); if (!requestingDifference() && (!channel || isDataLoaded != DataIsLoadedResult::Ok)) { MTP_LOG(0, ("getDifference { good - after not all data loaded in updateNewChannelMessage }%1").arg(cTestMode() ? " TESTMODE" : "")); @@ -4579,8 +4578,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } } if (needToAdd) { - HistoryItem *item = App::histories().addNewMessage(d.vmessage, NewMessageUnread); - if (item) { + if (auto item = App::histories().addNewMessage(d.vmessage, NewMessageUnread)) { _history->peerMessagesUpdated(item->history()->peer->id); } } @@ -4590,8 +4588,8 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateEditChannelMessage: { - const auto &d(update.c_updateEditChannelMessage()); - ChannelData *channel = App::channelLoaded(peerToChannel(peerFromMessage(d.vmessage))); + auto &d = update.c_updateEditChannelMessage(); + auto channel = App::channelLoaded(peerToChannel(peerFromMessage(d.vmessage))); if (channel && !_handlingChannelDifference) { if (channel->ptsRequesting()) { // skip global updates while getting channel difference @@ -4610,7 +4608,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateEditMessage: { - const auto &d(update.c_updateEditMessage()); + auto &d = update.c_updateEditMessage(); if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) { return; @@ -4623,9 +4621,9 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateChannelPinnedMessage: { - const auto &d(update.c_updateChannelPinnedMessage()); + auto &d = update.c_updateChannelPinnedMessage(); - if (ChannelData *channel = App::channelLoaded(d.vchannel_id.v)) { + if (auto channel = App::channelLoaded(d.vchannel_id.v)) { if (channel->isMegagroup()) { channel->mgInfo->pinnedMsgId = d.vid.v; if (App::api()) { @@ -4636,13 +4634,12 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateReadChannelInbox: { - auto &d(update.c_updateReadChannelInbox()); - auto channel = App::channelLoaded(d.vchannel_id.v); + auto &d = update.c_updateReadChannelInbox(); App::feedInboxRead(peerFromChannel(d.vchannel_id.v), d.vmax_id.v); } break; case mtpc_updateReadChannelOutbox: { - auto &d(update.c_updateReadChannelOutbox()); + auto &d = update.c_updateReadChannelOutbox(); auto peerId = peerFromChannel(d.vchannel_id.v); auto when = requestingDifference() ? 0 : unixtime(); App::feedOutboxRead(peerId, d.vmax_id.v, when); @@ -4652,8 +4649,8 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateDeleteChannelMessages: { - const auto &d(update.c_updateDeleteChannelMessages()); - ChannelData *channel = App::channelLoaded(d.vchannel_id.v); + auto &d = update.c_updateDeleteChannelMessages(); + auto channel = App::channelLoaded(d.vchannel_id.v); if (channel && !_handlingChannelDifference) { if (channel->ptsRequesting()) { // skip global updates while getting channel difference @@ -4673,8 +4670,8 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateChannelTooLong: { - const auto &d(update.c_updateChannelTooLong()); - if (ChannelData *channel = App::channelLoaded(d.vchannel_id.v)) { + auto &d = update.c_updateChannelTooLong(); + if (auto channel = App::channelLoaded(d.vchannel_id.v)) { if (!d.has_pts() || channel->pts() < d.vpts.v) { getChannelDifference(channel); } @@ -4682,8 +4679,8 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateChannelMessageViews: { - const auto &d(update.c_updateChannelMessageViews()); - if (HistoryItem *item = App::histItemById(d.vchannel_id.v, d.vid.v)) { + auto &d = update.c_updateChannelMessageViews(); + if (auto item = App::histItemById(d.vchannel_id.v, d.vid.v)) { item->setViewsCount(d.vviews.v); } } break; diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index 14fbdb2d6c..a8e56c1482 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -406,8 +406,7 @@ MainWindow::MainWindow() { connect(&_autoLockTimer, SIGNAL(timeout()), this, SLOT(checkAutoLock())); - connect(this, SIGNAL(imageLoaded()), this, SLOT(notifyUpdateAllPhotos())); - + subscribe(FileDownload::ImageLoaded(), [this] { notifyUpdateAllPhotos(); }); subscribe(Global::RefSelfChanged(), [this]() { updateGlobalMenu(); }); setAttribute(Qt::WA_NoSystemBackground); diff --git a/Telegram/SourceFiles/mainwindow.h b/Telegram/SourceFiles/mainwindow.h index bc28dada08..cd289b8981 100644 --- a/Telegram/SourceFiles/mainwindow.h +++ b/Telegram/SourceFiles/mainwindow.h @@ -288,9 +288,7 @@ signals: void tempDirClearFailed(int task); void newAuthorization(); - void imageLoaded(); - - private slots: +private slots: void onStateChanged(Qt::WindowState state); void onSettingsDestroyed(QObject *was); diff --git a/Telegram/SourceFiles/media/media_clip_ffmpeg.cpp b/Telegram/SourceFiles/media/media_clip_ffmpeg.cpp index 5fd4f0baeb..aef676db3d 100644 --- a/Telegram/SourceFiles/media/media_clip_ffmpeg.cpp +++ b/Telegram/SourceFiles/media/media_clip_ffmpeg.cpp @@ -209,6 +209,9 @@ bool FFMpegReaderImplementation::renderFrame(QImage &to, bool &hasAlpha, const Q } QSize toSize(size.isEmpty() ? QSize(_width, _height) : size); + if (!size.isEmpty() && rotationSwapWidthHeight()) { + toSize.transpose(); + } if (to.isNull() || to.size() != toSize) { to = QImage(toSize, QImage::Format_ARGB32); } @@ -231,6 +234,15 @@ bool FFMpegReaderImplementation::renderFrame(QImage &to, bool &hasAlpha, const Q return false; } } + if (_rotation != Rotation::None) { + QTransform rotationTransform; + switch (_rotation) { + case Rotation::Degrees90: rotationTransform.rotate(90); break; + case Rotation::Degrees180: rotationTransform.rotate(180); break; + case Rotation::Degrees270: rotationTransform.rotate(270); break; + } + to = to.transformed(rotationTransform); + } // Read some future packets for audio stream. if (_audioStreamId >= 0) { @@ -247,6 +259,15 @@ bool FFMpegReaderImplementation::renderFrame(QImage &to, bool &hasAlpha, const Q return true; } +FFMpegReaderImplementation::Rotation FFMpegReaderImplementation::rotationFromDegrees(int degrees) const { + switch (degrees) { + case 90: return Rotation::Degrees90; + case 180: return Rotation::Degrees180; + case 270: return Rotation::Degrees270; + } + return Rotation::None; +} + bool FFMpegReaderImplementation::start(Mode mode, int64 &positionMs) { _mode = mode; @@ -286,6 +307,16 @@ bool FFMpegReaderImplementation::start(Mode mode, int64 &positionMs) { } _packetNull.stream_index = _streamId; + auto rotateTag = av_dict_get(_fmtContext->streams[_streamId]->metadata, "rotate", NULL, 0); + if (rotateTag && *rotateTag->value) { + auto stringRotateTag = QString::fromUtf8(rotateTag->value); + auto toIntSucceeded = false; + auto rotateDegrees = stringRotateTag.toInt(&toIntSucceeded); + if (toIntSucceeded) { + _rotation = rotationFromDegrees(rotateDegrees); + } + } + _codecContext = avcodec_alloc_context3(nullptr); if (!_codecContext) { LOG(("Audio Error: Unable to avcodec_alloc_context3 %1").arg(logData())); diff --git a/Telegram/SourceFiles/media/media_clip_ffmpeg.h b/Telegram/SourceFiles/media/media_clip_ffmpeg.h index 6d1ef3ea56..2810e7e7fe 100644 --- a/Telegram/SourceFiles/media/media_clip_ffmpeg.h +++ b/Telegram/SourceFiles/media/media_clip_ffmpeg.h @@ -71,6 +71,17 @@ private: int64 countPacketMs(AVPacket *packet) const; PacketResult readAndProcessPacket(); + enum class Rotation { + None, + Degrees90, + Degrees180, + Degrees270, + }; + Rotation rotationFromDegrees(int degrees) const; + bool rotationSwapWidthHeight() const { + return (_rotation == Rotation::Degrees90) || (_rotation == Rotation::Degrees270); + } + void startPacket(); void finishPacket(); void clearPacketQueue(); @@ -80,6 +91,8 @@ private: Mode _mode = Mode::Normal; + Rotation _rotation = Rotation::None; + uchar *_ioBuffer = nullptr; AVIOContext *_ioContext = nullptr; AVFormatContext *_fmtContext = nullptr; diff --git a/Telegram/SourceFiles/media/media_clip_reader.cpp b/Telegram/SourceFiles/media/media_clip_reader.cpp index 49ddc2f06e..792cefaa4f 100644 --- a/Telegram/SourceFiles/media/media_clip_reader.cpp +++ b/Telegram/SourceFiles/media/media_clip_reader.cpp @@ -180,8 +180,8 @@ void Reader::moveToNextWrite() const { void Reader::callback(Reader *reader, int32 threadIndex, Notification notification) { // check if reader is not deleted already - if (managers.size() > threadIndex && managers.at(threadIndex)->carries(reader)) { - reader->_callback.call(notification); + if (managers.size() > threadIndex && managers.at(threadIndex)->carries(reader) && reader->_callback) { + reader->_callback(notification); } } @@ -588,15 +588,12 @@ void Manager::start(Reader *reader) { } void Manager::update(Reader *reader) { - QReadLocker lock(&_readerPointersMutex); - auto i = _readerPointers.constFind(reader); + QMutexLocker lock(&_readerPointersMutex); + auto i = _readerPointers.find(reader); if (i == _readerPointers.cend()) { - lock.unlock(); - - QWriteLocker lock(&_readerPointersMutex); - _readerPointers.insert(reader, MutableAtomicInt(1)); + _readerPointers.insert(reader, QAtomicInt(1)); } else { - i->v.storeRelease(1); + i->storeRelease(1); } emit processDelayed(); } @@ -604,13 +601,13 @@ void Manager::update(Reader *reader) { void Manager::stop(Reader *reader) { if (!carries(reader)) return; - QWriteLocker lock(&_readerPointersMutex); + QMutexLocker lock(&_readerPointersMutex); _readerPointers.remove(reader); emit processDelayed(); } bool Manager::carries(Reader *reader) const { - QReadLocker lock(&_readerPointersMutex); + QMutexLocker lock(&_readerPointersMutex); return _readerPointers.contains(reader); } @@ -629,19 +626,13 @@ Manager::ReaderPointers::const_iterator Manager::constUnsafeFindReaderPointer(Re } bool Manager::handleProcessResult(ReaderPrivate *reader, ProcessResult result, uint64 ms) { - QReadLocker lock(&_readerPointersMutex); - auto it = constUnsafeFindReaderPointer(reader); + QMutexLocker lock(&_readerPointersMutex); + auto it = unsafeFindReaderPointer(reader); if (result == ProcessResult::Error) { if (it != _readerPointers.cend()) { - lock.unlock(); - QWriteLocker lock(&_readerPointersMutex); - - auto i = unsafeFindReaderPointer(reader); - if (i != _readerPointers.cend()) { - i.key()->error(); - emit callback(i.key(), i.key()->threadIndex(), NotificationReinit); - _readerPointers.erase(i); - } + it.key()->error(); + emit callback(it.key(), it.key()->threadIndex(), NotificationReinit); + _readerPointers.erase(it); } return false; } else if (result == ProcessResult::Finished) { @@ -663,8 +654,8 @@ bool Manager::handleProcessResult(ReaderPrivate *reader, ProcessResult result, u // See if we need to pause GIF because it is not displayed right now. if (!reader->_autoPausedGif && reader->_mode == Reader::Mode::Gif && result == ProcessResult::Repaint) { int32 ishowing, iprevious; - Reader::Frame *showing = it.key()->frameToShow(&ishowing), *previous = it.key()->frameToWriteNext(false, &iprevious); - t_assert(previous != 0 && showing != 0 && ishowing >= 0 && iprevious >= 0); + auto showing = it.key()->frameToShow(&ishowing), previous = it.key()->frameToWriteNext(false, &iprevious); + t_assert(previous != nullptr && showing != nullptr && ishowing >= 0 && iprevious >= 0); if (reader->_frames[ishowing].when > 0 && showing->displayed.loadAcquire() <= 0) { // current frame was not shown if (reader->_frames[ishowing].when + WaitBeforeGifPause < ms || (reader->_frames[iprevious].when && previous->displayed.loadAcquire() <= 0)) { reader->_autoPausedGif = true; @@ -675,7 +666,7 @@ bool Manager::handleProcessResult(ReaderPrivate *reader, ProcessResult result, u } if (result == ProcessResult::Started || result == ProcessResult::CopyFrame) { t_assert(reader->_frame >= 0); - Reader::Frame *frame = it.key()->_frames + reader->_frame; + auto frame = it.key()->_frames + reader->_frame; frame->clear(); frame->pix = reader->frame()->pix; frame->original = reader->frame()->original; @@ -710,8 +701,8 @@ Manager::ResultHandleState Manager::handleResult(ReaderPrivate *reader, ProcessR if (result == ProcessResult::Repaint) { { - QReadLocker lock(&_readerPointersMutex); - ReaderPointers::const_iterator it = constUnsafeFindReaderPointer(reader); + QMutexLocker lock(&_readerPointersMutex); + auto it = constUnsafeFindReaderPointer(reader); if (it != _readerPointers.cend()) { int32 index = 0; Reader *r = it.key(); @@ -742,9 +733,9 @@ void Manager::process() { bool checkAllReaders = false; uint64 ms = getms(), minms = ms + 86400 * 1000ULL; { - QReadLocker lock(&_readerPointersMutex); + QMutexLocker lock(&_readerPointersMutex); for (auto it = _readerPointers.begin(), e = _readerPointers.end(); it != e; ++it) { - if (it->v.loadAcquire() && it.key()->_private != nullptr) { + if (it->loadAcquire() && it.key()->_private != nullptr) { auto i = _readers.find(it.key()->_private); if (i == _readers.cend()) { _readers.insert(it.key()->_private, 0); @@ -759,9 +750,9 @@ void Manager::process() { i.key()->resumeVideo(ms); } } - Reader::Frame *frame = it.key()->frameToWrite(); + auto frame = it.key()->frameToWrite(); if (frame) it.key()->_private->_request = frame->request; - it->v.storeRelease(0); + it->storeRelease(0); } } checkAllReaders = (_readers.size() > _readerPointers.size()); @@ -787,8 +778,8 @@ void Manager::process() { i.value() = (ms + 86400 * 1000ULL); } } else if (checkAllReaders) { - QReadLocker lock(&_readerPointersMutex); - ReaderPointers::const_iterator it = constUnsafeFindReaderPointer(reader); + QMutexLocker lock(&_readerPointersMutex); + auto it = constUnsafeFindReaderPointer(reader); if (it == _readerPointers.cend()) { _loadLevel.fetchAndAddRelaxed(-1 * (reader->_width > 0 ? reader->_width * reader->_height : AverageGifSize)); delete reader; @@ -820,8 +811,8 @@ void Manager::finish() { void Manager::clear() { { - QWriteLocker lock(&_readerPointersMutex); - for (ReaderPointers::iterator it = _readerPointers.begin(), e = _readerPointers.end(); it != e; ++it) { + QMutexLocker lock(&_readerPointersMutex); + for (auto it = _readerPointers.begin(), e = _readerPointers.end(); it != e; ++it) { it.key()->_private = nullptr; } _readerPointers.clear(); diff --git a/Telegram/SourceFiles/media/media_clip_reader.h b/Telegram/SourceFiles/media/media_clip_reader.h index d2a3f7be60..220632c551 100644 --- a/Telegram/SourceFiles/media/media_clip_reader.h +++ b/Telegram/SourceFiles/media/media_clip_reader.h @@ -52,7 +52,7 @@ enum ReaderSteps { class ReaderPrivate; class Reader { public: - using Callback = Function; + using Callback = base::lambda_unique; enum class Mode { Gif, Video, @@ -211,14 +211,9 @@ private: void clear(); QAtomicInt _loadLevel; - struct MutableAtomicInt { - MutableAtomicInt(int value) : v(value) { - } - mutable QAtomicInt v; - }; - typedef QMap ReaderPointers; + using ReaderPointers = QMap; ReaderPointers _readerPointers; - mutable QReadWriteLock _readerPointersMutex; + mutable QMutex _readerPointersMutex; ReaderPointers::const_iterator constUnsafeFindReaderPointer(ReaderPrivate *reader) const; ReaderPointers::iterator unsafeFindReaderPointer(ReaderPrivate *reader); diff --git a/Telegram/SourceFiles/media/player/media_player_button.cpp b/Telegram/SourceFiles/media/player/media_player_button.cpp index 92788e5a01..43abc77a6b 100644 --- a/Telegram/SourceFiles/media/player/media_player_button.cpp +++ b/Telegram/SourceFiles/media/player/media_player_button.cpp @@ -66,9 +66,7 @@ void TitleButton::updatePauseState() { void TitleButton::setShowPause(bool showPause) { if (_showPause != showPause) { _showPause = showPause; - START_ANIMATION(_iconTransformToPause, func([this]() { - update(); - }), _showPause ? 0. : 1., _showPause ? 1. : 0., st::mediaPlayerTitleButtonTransformDuration, anim::linear); + _iconTransformToPause.start([this] { update(); }, _showPause ? 0. : 1., _showPause ? 1. : 0., st::mediaPlayerTitleButtonTransformDuration); update(); } } @@ -97,9 +95,7 @@ void TitleButton::paintEvent(QPaintEvent *e) { void TitleButton::onStateChanged(int oldState, ButtonStateChangeSource source) { if ((oldState & StateOver) != (_state & StateOver)) { auto over = (_state & StateOver); - START_ANIMATION(_iconFg, func([this]() { - update(); - }), over ? st::titleButtonFg->c : st::titleButtonActiveFg->c, over ? st::titleButtonActiveFg->c : st::titleButtonFg->c, st::titleButtonDuration, anim::linear); + _iconFg.start([this] { update(); }, over ? st::titleButtonFg->c : st::titleButtonActiveFg->c, over ? st::titleButtonActiveFg->c : st::titleButtonFg->c, st::titleButtonDuration); } } diff --git a/Telegram/SourceFiles/media/player/media_player_instance.cpp b/Telegram/SourceFiles/media/player/media_player_instance.cpp index f7c99fb23f..d6be8535e2 100644 --- a/Telegram/SourceFiles/media/player/media_player_instance.cpp +++ b/Telegram/SourceFiles/media/player/media_player_instance.cpp @@ -56,7 +56,10 @@ Instance::Instance() { handleSongUpdate(audioId); } }); - Notify::registerPeerObserver(Notify::PeerUpdate::Flag::SharedMediaChanged, this, &Instance::notifyPeerUpdated); + auto observeEvents = Notify::PeerUpdate::Flag::SharedMediaChanged; + subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { + notifyPeerUpdated(update); + })); } void Instance::notifyPeerUpdated(const Notify::PeerUpdate &update) { diff --git a/Telegram/SourceFiles/media/player/media_player_instance.h b/Telegram/SourceFiles/media/player/media_player_instance.h index beecddbe89..48ef5f358b 100644 --- a/Telegram/SourceFiles/media/player/media_player_instance.h +++ b/Telegram/SourceFiles/media/player/media_player_instance.h @@ -53,7 +53,7 @@ struct UpdatedEvent { const AudioPlaybackState *playbackState; }; -class Instance : private base::Subscriber, public Notify::Observer { +class Instance : private base::Subscriber { public: void play(); void pause(); diff --git a/Telegram/SourceFiles/media/player/media_player_widget.cpp b/Telegram/SourceFiles/media/player/media_player_widget.cpp index bc94160f32..fc2a2d8f80 100644 --- a/Telegram/SourceFiles/media/player/media_player_widget.cpp +++ b/Telegram/SourceFiles/media/player/media_player_widget.cpp @@ -51,7 +51,7 @@ Widget::Widget(QWidget *parent) : TWidget(parent) } bool Widget::overlaps(const QRect &globalRect) { - if (isHidden() || !_a_appearance.isNull()) return false; + if (isHidden() || _a_appearance.animating()) return false; auto marginLeft = rtl() ? 0 : contentLeft(); auto marginRight = rtl() ? contentLeft() : 0; @@ -171,18 +171,18 @@ void Widget::onHideStart() { void Widget::startAnimation() { auto from = _hiding ? 1. : 0.; auto to = _hiding ? 0. : 1.; - if (_a_appearance.isNull()) { + if (!_a_appearance.animating()) { showChildren(); _cache = myGrab(this); } hideChildren(); - START_ANIMATION(_a_appearance, func([this]() { + _a_appearance.start([this]() { update(); if (!_a_appearance.animating(getms()) && _hiding) { _hiding = false; hidingFinished(); } - }), from, to, st::defaultInnerDropdown.duration, anim::linear); + }, from, to, st::defaultInnerDropdown.duration); } void Widget::hidingFinished() { diff --git a/Telegram/SourceFiles/media/view/media_clip_controller.cpp b/Telegram/SourceFiles/media/view/media_clip_controller.cpp index 91c53cd9a1..c4a7af66ca 100644 --- a/Telegram/SourceFiles/media/view/media_clip_controller.cpp +++ b/Telegram/SourceFiles/media/view/media_clip_controller.cpp @@ -41,8 +41,8 @@ Controller::Controller(QWidget *parent) : TWidget(parent) , _toPlayLeft(this, st::mediaviewPlayProgressLabel) , _fadeAnimation(std_::make_unique(this)) { _fadeAnimation->show(); - _fadeAnimation->setFinishedCallback(func(this, &Controller::fadeFinished)); - _fadeAnimation->setUpdatedCallback(func(this, &Controller::fadeUpdated)); + _fadeAnimation->setFinishedCallback([this] { fadeFinished(); }); + _fadeAnimation->setUpdatedCallback([this](float64 opacity) { fadeUpdated(opacity); }); _volumeController->setVolume(Global::VideoVolume()); diff --git a/Telegram/SourceFiles/media/view/media_clip_playback.cpp b/Telegram/SourceFiles/media/view/media_clip_playback.cpp index b3732dc875..3117250d58 100644 --- a/Telegram/SourceFiles/media/view/media_clip_playback.cpp +++ b/Telegram/SourceFiles/media/view/media_clip_playback.cpp @@ -55,6 +55,7 @@ void Playback::updateState(const AudioPlaybackState &playbackState) { _position = position; _duration = duration; } + _slider->update(); } } // namespace Clip diff --git a/Telegram/SourceFiles/media/view/media_clip_volume_controller.cpp b/Telegram/SourceFiles/media/view/media_clip_volume_controller.cpp index 8ffed03f22..c1b83746f6 100644 --- a/Telegram/SourceFiles/media/view/media_clip_volume_controller.cpp +++ b/Telegram/SourceFiles/media/view/media_clip_volume_controller.cpp @@ -100,7 +100,7 @@ void VolumeController::setOver(bool over) { _over = over; auto from = _over ? 0. : 1., to = _over ? 1. : 0.; - START_ANIMATION(_a_over, func(this, &VolumeController::updateCallback), from, to, st::mediaviewOverDuration, anim::linear); + _a_over.start([this] { update(); }, from, to, st::mediaviewOverDuration); } } // namespace Clip diff --git a/Telegram/SourceFiles/media/view/media_clip_volume_controller.h b/Telegram/SourceFiles/media/view/media_clip_volume_controller.h index cf062ce097..69389eeab9 100644 --- a/Telegram/SourceFiles/media/view/media_clip_volume_controller.h +++ b/Telegram/SourceFiles/media/view/media_clip_volume_controller.h @@ -43,9 +43,6 @@ protected: void leaveEvent(QEvent *e) override; private: - void updateCallback() { - update(); - } void setOver(bool over); void changeVolume(float64 newVolume); diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index 833019e502..eae0ffdfc4 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -1368,7 +1368,9 @@ void MediaView::createClipReader() { _current = _doc->thumb->pixNoCache(_doc->thumb->width(), _doc->thumb->height(), ImagePixSmooth | ImagePixBlurred, st::mvDocIconSize, st::mvDocIconSize); } auto mode = _doc->isVideo() ? Media::Clip::Reader::Mode::Video : Media::Clip::Reader::Mode::Gif; - _gif = std_::make_unique(_doc->location(), _doc->data(), func(this, &MediaView::clipCallback), mode); + _gif = std_::make_unique(_doc->location(), _doc->data(), [this](Media::Clip::Notification notification) { + clipCallback(notification); + }, mode); // Correct values will be set when gif gets inited. _videoPaused = _videoIsSilent = _videoStopped = false; @@ -1439,7 +1441,9 @@ void MediaView::restartVideoAtSeekPosition(int64 positionMs) { if (_current.isNull()) { _current = _gif->current(_gif->width(), _gif->height(), _gif->width(), _gif->height(), getms()); } - _gif = std_::make_unique(_doc->location(), _doc->data(), func(this, &MediaView::clipCallback), Media::Clip::Reader::Mode::Video, positionMs); + _gif = std_::make_unique(_doc->location(), _doc->data(), [this](Media::Clip::Notification notification) { + clipCallback(notification); + }, Media::Clip::Reader::Mode::Video, positionMs); // Correct values will be set when gif gets inited. _videoPaused = _videoIsSilent = _videoStopped = false; diff --git a/Telegram/SourceFiles/mtproto/facade.cpp b/Telegram/SourceFiles/mtproto/facade.cpp index 43498d474b..a09c9842c8 100644 --- a/Telegram/SourceFiles/mtproto/facade.cpp +++ b/Telegram/SourceFiles/mtproto/facade.cpp @@ -206,7 +206,7 @@ namespace { } req = i.value(); } - if (internal::Session *session = internal::getSession(newdcWithShift)) { + if (auto session = internal::getSession(newdcWithShift)) { internal::registerRequest(requestId, (dcWithShift < 0) ? -newdcWithShift : newdcWithShift); session->sendPrepared(req); } diff --git a/Telegram/SourceFiles/mtproto/file_download.cpp b/Telegram/SourceFiles/mtproto/file_download.cpp index e4623dbc97..513fbfd8e0 100644 --- a/Telegram/SourceFiles/mtproto/file_download.cpp +++ b/Telegram/SourceFiles/mtproto/file_download.cpp @@ -207,9 +207,8 @@ void FileLoader::localLoaded(const StorageImageSaved &result, const QByteArray & _fileIsOpen = false; psPostprocessFile(QFileInfo(_file).absoluteFilePath()); } - emit App::wnd()->imageLoaded(); emit progress(this); - FileDownload::internal::notifyImageLoaded(); + FileDownload::ImageLoaded().notify(); loadNext(); } @@ -516,8 +515,6 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe } removeFromQueue(); - emit App::wnd()->imageLoaded(); - if (!_queue->queries) { App::app()->killDownloadSessionsStart(_dc); } @@ -544,7 +541,7 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe } emit progress(this); if (_complete) { - FileDownload::internal::notifyImageLoaded(); + FileDownload::ImageLoaded().notify(); } loadNext(); } @@ -669,13 +666,11 @@ void webFileLoader::onFinished(const QByteArray &data) { } removeFromQueue(); - emit App::wnd()->imageLoaded(); - if (_localStatus == LocalNotFound || _localStatus == LocalFailed) { Local::writeWebFile(_url, _data); } emit progress(this); - FileDownload::internal::notifyImageLoaded(); + FileDownload::ImageLoaded().notify(); loadNext(); } @@ -1093,21 +1088,12 @@ namespace MTP { namespace FileDownload { namespace { -using internal::ImageLoadedHandler; - -Notify::SimpleObservedEventRegistrator creator(nullptr, nullptr); +base::Observable ImageLoadedObservable; } // namespace -namespace internal { - -Notify::ConnectionId plainRegisterImageLoadedObserver(ImageLoadedHandler &&handler) { - return creator.registerObserver(std_::forward(handler)); +base::Observable &ImageLoaded() { + return ImageLoadedObservable; } -void notifyImageLoaded() { - creator.notify(); -} - -} // namespace internal -} +} // namespace FileDownload diff --git a/Telegram/SourceFiles/mtproto/file_download.h b/Telegram/SourceFiles/mtproto/file_download.h index 94b65fb2b4..f4453ee7f3 100644 --- a/Telegram/SourceFiles/mtproto/file_download.h +++ b/Telegram/SourceFiles/mtproto/file_download.h @@ -396,19 +396,7 @@ void reinitWebLoadManager(); void stopWebLoadManager(); namespace FileDownload { -namespace internal { -using ImageLoadedHandler = Function; -Notify::ConnectionId plainRegisterImageLoadedObserver(ImageLoadedHandler &&handler); - -void notifyImageLoaded(); - -} // namespace internal - -template -void registerImageLoadedObserver(ObserverType *observer, void (ObserverType::*handler)()) { - auto connection = internal::plainRegisterImageLoadedObserver(func(observer, handler)); - Notify::observerRegistered(observer, connection); -} +base::Observable &ImageLoaded(); } // namespace FileDownload diff --git a/Telegram/SourceFiles/observer_peer.cpp b/Telegram/SourceFiles/observer_peer.cpp index 13bfe074a4..e4d463e5f4 100644 --- a/Telegram/SourceFiles/observer_peer.cpp +++ b/Telegram/SourceFiles/observer_peer.cpp @@ -31,8 +31,6 @@ void emitPeerUpdated(); namespace Notify { namespace { -using internal::PeerUpdateHandler; - using SmallUpdatesList = QVector; NeverFreedPointer SmallUpdates; using AllUpdatesList = QMap; @@ -46,19 +44,11 @@ void FinishCallback() { SmallUpdates.clear(); AllUpdates.clear(); } -ObservedEventRegistrator creator(StartCallback, FinishCallback); + +base::Observable PeerUpdatedObservable; } // namespace -namespace internal { - -ConnectionId plainRegisterPeerObserver(PeerUpdate::Flags events, PeerUpdateHandler &&handler) { - constexpr auto tmp = sizeof(PeerUpdate); - return creator.registerObserver(events, std_::forward(handler)); -} - -} // namespace internal - void mergePeerUpdate(PeerUpdate &mergeTo, const PeerUpdate &mergeFrom) { if (!(mergeTo.flags & PeerUpdate::Flag::NameChanged)) { if (mergeFrom.flags & PeerUpdate::Flag::NameChanged) { @@ -73,7 +63,8 @@ void mergePeerUpdate(PeerUpdate &mergeTo, const PeerUpdate &mergeFrom) { } void peerUpdatedDelayed(const PeerUpdate &update) { - t_assert(creator.started()); + SmallUpdates.makeIfNull(); + AllUpdates.makeIfNull(); Global::RefHandleDelayedPeerUpdates().call(); @@ -85,6 +76,7 @@ void peerUpdatedDelayed(const PeerUpdate &update) { return; } } + if (AllUpdates->isEmpty()) { if (existingUpdatesCount < 5) { SmallUpdates->push_back(update); @@ -102,24 +94,27 @@ void peerUpdatedDelayed(const PeerUpdate &update) { } void peerUpdatedSendDelayed() { - if (!creator.started()) return; - App::emitPeerUpdated(); - if (SmallUpdates->isEmpty()) return; + if (!SmallUpdates || !AllUpdates || SmallUpdates->empty()) return; auto smallList = createAndSwap(*SmallUpdates); auto allList = createAndSwap(*AllUpdates); - for_const (auto &update, smallList) { - creator.notify(update.flags, update); + for (auto &update : smallList) { + PeerUpdated().notify(std_::move(update), true); } - for_const (auto &update, allList) { - creator.notify(update.flags, update); + for (auto &update : allList) { + PeerUpdated().notify(std_::move(update), true); } + if (SmallUpdates->isEmpty()) { std::swap(smallList, *SmallUpdates); SmallUpdates->resize(0); } } +base::Observable &PeerUpdated() { + return PeerUpdatedObservable; +} + } // namespace Notify diff --git a/Telegram/SourceFiles/observer_peer.h b/Telegram/SourceFiles/observer_peer.h index fe0e26cbca..7dd1317d01 100644 --- a/Telegram/SourceFiles/observer_peer.h +++ b/Telegram/SourceFiles/observer_peer.h @@ -89,17 +89,22 @@ inline void peerUpdatedDelayed(PeerData *peer, PeerUpdate::Flags events) { } void peerUpdatedSendDelayed(); -namespace internal { +class PeerUpdatedHandler { +public: + template + PeerUpdatedHandler(PeerUpdate::Flags events, Lambda &&handler) : _events(events), _handler(std_::move(handler)) { + } + void operator()(const PeerUpdate &update) const { + if (update.flags & _events) { + _handler(update); + } + } -using PeerUpdateHandler = Function; -ConnectionId plainRegisterPeerObserver(PeerUpdate::Flags events, PeerUpdateHandler &&handler); +private: + PeerUpdate::Flags _events; + base::lambda_unique _handler; -} // namespace internal - -template -void registerPeerObserver(PeerUpdate::Flags events, ObserverType *observer, void (ObserverType::*handler)(const PeerUpdate &)) { - auto connection = internal::plainRegisterPeerObserver(events, func(observer, handler)); - observerRegistered(observer, connection); -} +}; +base::Observable &PeerUpdated(); } // namespace Notify diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index 786ffd2fd2..f287c96e12 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -89,7 +89,7 @@ OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, PeerD , _touchAccelerationTime(0) , _touchTime(0) , _menu(0) { - connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); + subscribe(FileDownload::ImageLoaded(), [this] { update(); }); resize(_width, st::wndMinHeight); diff --git a/Telegram/SourceFiles/overviewwidget.h b/Telegram/SourceFiles/overviewwidget.h index adfb28ee26..7a2c2b130e 100644 --- a/Telegram/SourceFiles/overviewwidget.h +++ b/Telegram/SourceFiles/overviewwidget.h @@ -33,7 +33,7 @@ class Date; } // namespace Overview class OverviewWidget; -class OverviewInner : public QWidget, public AbstractTooltipShower, public RPCSender { +class OverviewInner : public QWidget, public AbstractTooltipShower, public RPCSender, private base::Subscriber { Q_OBJECT public: diff --git a/Telegram/SourceFiles/profile/profile_actions_widget.cpp b/Telegram/SourceFiles/profile/profile_actions_widget.cpp index df96da74bb..f8c04ae0f9 100644 --- a/Telegram/SourceFiles/profile/profile_actions_widget.cpp +++ b/Telegram/SourceFiles/profile/profile_actions_widget.cpp @@ -39,7 +39,9 @@ ActionsWidget::ActionsWidget(QWidget *parent, PeerData *peer) : BlockWidget(pare | UpdateFlag::UserIsBlocked | UpdateFlag::BotCommandsChanged | UpdateFlag::MembersChanged; - Notify::registerPeerObserver(observeEvents, this, &ActionsWidget::notifyPeerUpdated); + subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { + notifyPeerUpdated(update); + })); validateBlockStatus(); refreshButtons(); diff --git a/Telegram/SourceFiles/profile/profile_block_widget.h b/Telegram/SourceFiles/profile/profile_block_widget.h index 7b77d27702..d185f9f044 100644 --- a/Telegram/SourceFiles/profile/profile_block_widget.h +++ b/Telegram/SourceFiles/profile/profile_block_widget.h @@ -24,7 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org namespace Profile { -class BlockWidget : public ScrolledWidget, public Notify::Observer { +class BlockWidget : public ScrolledWidget, protected base::Subscriber { Q_OBJECT public: diff --git a/Telegram/SourceFiles/profile/profile_cover.cpp b/Telegram/SourceFiles/profile/profile_cover.cpp index 056b2f07cf..cb13f68fc2 100644 --- a/Telegram/SourceFiles/profile/profile_cover.cpp +++ b/Telegram/SourceFiles/profile/profile_cover.cpp @@ -68,8 +68,12 @@ CoverWidget::CoverWidget(QWidget *parent, PeerData *peer) : TWidget(parent) auto observeEvents = ButtonsUpdateFlags | UpdateFlag::NameChanged | UpdateFlag::UserOnlineChanged; - Notify::registerPeerObserver(observeEvents, this, &CoverWidget::notifyPeerUpdated); - FileDialog::registerObserver(this, &CoverWidget::notifyFileQueryUpdated); + subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { + notifyPeerUpdated(update); + })); + subscribe(FileDialog::QueryDone(), [this](const FileDialog::QueryUpdate &update) { + notifyFileQueryUpdated(update); + }); connect(App::app(), SIGNAL(peerPhotoDone(PeerId)), this, SLOT(onPhotoUploadStatusChanged(PeerId))); connect(App::app(), SIGNAL(peerPhotoFail(PeerId)), this, SLOT(onPhotoUploadStatusChanged(PeerId))); @@ -285,7 +289,7 @@ void CoverWidget::dragEnterEvent(QDragEnterEvent *e) { void CoverWidget::dragLeaveEvent(QDragLeaveEvent *e) { if (_dropArea && !_dropArea->hiding()) { - _dropArea->hideAnimated(func(this, &CoverWidget::dropAreaHidden)); + _dropArea->hideAnimated([this](CoverDropArea *area) { dropAreaHidden(area); }); } } @@ -306,7 +310,7 @@ void CoverWidget::dropEvent(QDropEvent *e) { } if (!_dropArea->hiding()) { - _dropArea->hideAnimated(func(this, &CoverWidget::dropAreaHidden)); + _dropArea->hideAnimated([this](CoverDropArea *area) { dropAreaHidden(area); }); } e->acceptProposedAction(); diff --git a/Telegram/SourceFiles/profile/profile_cover.h b/Telegram/SourceFiles/profile/profile_cover.h index 5b3c8023b8..3abd8e66e7 100644 --- a/Telegram/SourceFiles/profile/profile_cover.h +++ b/Telegram/SourceFiles/profile/profile_cover.h @@ -40,7 +40,7 @@ class BackButton; class UserpicButton; class CoverDropArea; -class CoverWidget final : public TWidget, public Notify::Observer { +class CoverWidget final : public TWidget, private base::Subscriber { Q_OBJECT public: diff --git a/Telegram/SourceFiles/profile/profile_cover_drop_area.cpp b/Telegram/SourceFiles/profile/profile_cover_drop_area.cpp index e3370f66d4..e23e8fc748 100644 --- a/Telegram/SourceFiles/profile/profile_cover_drop_area.cpp +++ b/Telegram/SourceFiles/profile/profile_cover_drop_area.cpp @@ -57,7 +57,9 @@ void CoverDropArea::paintEvent(QPaintEvent *e) { _cache = QPixmap(); if (_hiding) { hide(); - _hideFinishCallback.call(this); + if (_hideFinishCallback) { + _hideFinishCallback(this); + } return; } } @@ -93,7 +95,7 @@ void CoverDropArea::setupAnimation() { _cache = myGrab(this); } auto from = _hiding ? 1. : 0., to = _hiding ? 0. : 1.; - START_ANIMATION(_a_appearance, func(this, &CoverDropArea::refreshCallback), from, to, st::profileDropAreaDuration, anim::linear); + _a_appearance.start([this]() { update(); }, from, to, st::profileDropAreaDuration); } } // namespace Profile diff --git a/Telegram/SourceFiles/profile/profile_cover_drop_area.h b/Telegram/SourceFiles/profile/profile_cover_drop_area.h index 871523ff86..063e223ea3 100644 --- a/Telegram/SourceFiles/profile/profile_cover_drop_area.h +++ b/Telegram/SourceFiles/profile/profile_cover_drop_area.h @@ -28,7 +28,7 @@ public: void showAnimated(); - using HideFinishCallback = Function; + using HideFinishCallback = base::lambda_unique; void hideAnimated(HideFinishCallback &&callback); bool hiding() const { @@ -39,9 +39,6 @@ protected: void paintEvent(QPaintEvent *e) override; private: - void refreshCallback() { - update(); - } void setupAnimation(); QString _title, _subtitle; diff --git a/Telegram/SourceFiles/profile/profile_fixed_bar.cpp b/Telegram/SourceFiles/profile/profile_fixed_bar.cpp index 8d2cde28b9..c936b22969 100644 --- a/Telegram/SourceFiles/profile/profile_fixed_bar.cpp +++ b/Telegram/SourceFiles/profile/profile_fixed_bar.cpp @@ -83,7 +83,9 @@ FixedBar::FixedBar(QWidget *parent, PeerData *peer) : TWidget(parent) auto observeEvents = ButtonsUpdateFlags | UpdateFlag::MigrationChanged; - Notify::registerPeerObserver(observeEvents, this, &FixedBar::notifyPeerUpdate); + subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { + notifyPeerUpdate(update); + })); refreshRightActions(); } diff --git a/Telegram/SourceFiles/profile/profile_fixed_bar.h b/Telegram/SourceFiles/profile/profile_fixed_bar.h index 3030eef49c..18fa64d05f 100644 --- a/Telegram/SourceFiles/profile/profile_fixed_bar.h +++ b/Telegram/SourceFiles/profile/profile_fixed_bar.h @@ -34,7 +34,7 @@ namespace Profile { class BackButton; -class FixedBar final : public TWidget, public Notify::Observer { +class FixedBar final : public TWidget, private base::Subscriber { Q_OBJECT public: diff --git a/Telegram/SourceFiles/profile/profile_info_widget.cpp b/Telegram/SourceFiles/profile/profile_info_widget.cpp index bbb62d9e2a..e1d2b72478 100644 --- a/Telegram/SourceFiles/profile/profile_info_widget.cpp +++ b/Telegram/SourceFiles/profile/profile_info_widget.cpp @@ -36,7 +36,9 @@ InfoWidget::InfoWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, pe | UpdateFlag::UsernameChanged | UpdateFlag::UserPhoneChanged | UpdateFlag::UserCanShareContact; - Notify::registerPeerObserver(observeEvents, this, &InfoWidget::notifyPeerUpdated); + subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { + notifyPeerUpdated(update); + })); refreshLabels(); } @@ -149,15 +151,13 @@ void InfoWidget::refreshAbout() { textParseEntities(aboutText, TextParseLinks | TextParseMentions | TextParseHashtags | TextParseBotCommands, &aboutEntities); _about->setMarkedText({ aboutText, aboutEntities }); _about->setSelectable(true); - _about->setClickHandlerHook(func(this, &InfoWidget::aboutClickHandlerHook)); + _about->setClickHandlerHook([this](const ClickHandlerPtr &handler, Qt::MouseButton button) { + BotCommandClickHandler::setPeerForCommand(peer()); + return true; + }); } } -bool InfoWidget::aboutClickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button) { - BotCommandClickHandler::setPeerForCommand(peer()); - return true; -} - void InfoWidget::refreshMobileNumber() { TextWithEntities phoneText; if (auto user = peer()->asUser()) { diff --git a/Telegram/SourceFiles/profile/profile_info_widget.h b/Telegram/SourceFiles/profile/profile_info_widget.h index 16be5604bf..37618ab77b 100644 --- a/Telegram/SourceFiles/profile/profile_info_widget.h +++ b/Telegram/SourceFiles/profile/profile_info_widget.h @@ -51,8 +51,6 @@ private: void refreshChannelLink(); void refreshVisibility(); - bool aboutClickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button); - // labelWidget may be nullptr. void setLabeledText(ChildWidget *labelWidget, const QString &label, ChildWidget *textWidget, const TextWithEntities &textWithEntities, const QString ©Text); diff --git a/Telegram/SourceFiles/profile/profile_invite_link_widget.cpp b/Telegram/SourceFiles/profile/profile_invite_link_widget.cpp index f0a5245784..c33bad2e14 100644 --- a/Telegram/SourceFiles/profile/profile_invite_link_widget.cpp +++ b/Telegram/SourceFiles/profile/profile_invite_link_widget.cpp @@ -33,7 +33,9 @@ using UpdateFlag = Notify::PeerUpdate::Flag; InviteLinkWidget::InviteLinkWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_invite_link_section)) { auto observeEvents = UpdateFlag::InviteLinkChanged | UpdateFlag::UsernameChanged; - Notify::registerPeerObserver(observeEvents, this, &InviteLinkWidget::notifyPeerUpdated); + subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { + notifyPeerUpdated(update); + })); refreshLink(); refreshVisibility(); @@ -99,19 +101,17 @@ void InviteLinkWidget::refreshLink() { _link->setMarkedText(linkData); _link->setSelectable(true); _link->setContextCopyText(QString()); - _link->setClickHandlerHook(func(this, &InviteLinkWidget::clickHandlerHook)); - } -} + _link->setClickHandlerHook([this](const ClickHandlerPtr &handler, Qt::MouseButton button) { + auto link = getInviteLink(); + if (link.isEmpty()) { + return true; + } -bool InviteLinkWidget::clickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button) { - auto link = getInviteLink(); - if (link.isEmpty()) { - return true; + QApplication::clipboard()->setText(link); + Ui::showLayer(new InformBox(lang(lng_group_invite_copied))); + return false; + }); } - - QApplication::clipboard()->setText(link); - Ui::showLayer(new InformBox(lang(lng_group_invite_copied))); - return false; } } // namespace Profile diff --git a/Telegram/SourceFiles/profile/profile_invite_link_widget.h b/Telegram/SourceFiles/profile/profile_invite_link_widget.h index 65ef20b719..e01c043fff 100644 --- a/Telegram/SourceFiles/profile/profile_invite_link_widget.h +++ b/Telegram/SourceFiles/profile/profile_invite_link_widget.h @@ -46,8 +46,6 @@ private: void refreshLink(); void refreshVisibility(); - bool clickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button); - ChildWidget _link = { nullptr }; }; diff --git a/Telegram/SourceFiles/profile/profile_members_widget.cpp b/Telegram/SourceFiles/profile/profile_members_widget.cpp index 472c1b64d6..665b4dc015 100644 --- a/Telegram/SourceFiles/profile/profile_members_widget.cpp +++ b/Telegram/SourceFiles/profile/profile_members_widget.cpp @@ -49,16 +49,14 @@ MembersWidget::MembersWidget(QWidget *parent, PeerData *peer, TitleVisibility ti auto observeEvents = UpdateFlag::AdminsChanged | UpdateFlag::MembersChanged | UpdateFlag::UserOnlineChanged; - Notify::registerPeerObserver(observeEvents, this, &MembersWidget::notifyPeerUpdated); - FileDownload::registerImageLoadedObserver(this, &MembersWidget::repaintCallback); + subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { + notifyPeerUpdated(update); + })); + subscribe(FileDownload::ImageLoaded(), [this] { update(); }); refreshMembers(); } -void MembersWidget::repaintCallback() { - update(); -} - void MembersWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) { if (update.peer != peer()) { if (update.flags & UpdateFlag::UserOnlineChanged) { @@ -83,7 +81,7 @@ void MembersWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) { } } } - repaintCallback(); + this->update(); } void MembersWidget::refreshUserOnline(UserData *user) { @@ -315,17 +313,15 @@ void MembersWidget::refreshLimitReached() { QString link = textRichPrepare(lang(lng_profile_migrate_learn_more)); QString text = qsl("%1%2%3\n%4 [a href=\"https://telegram.org/blog/supergroups5k\"]%5[/a]").arg(textcmdStartSemibold()).arg(title).arg(textcmdStopSemibold()).arg(body).arg(link); _limitReachedInfo->setRichText(text); - _limitReachedInfo->setClickHandlerHook(func(this, &MembersWidget::limitReachedHook)); + _limitReachedInfo->setClickHandlerHook([this](const ClickHandlerPtr &handler, Qt::MouseButton button) { + Ui::showLayer(new ConvertToSupergroupBox(peer()->asChat())); + return false; + }); } else if (!limitReachedShown && _limitReachedInfo) { _limitReachedInfo.destroy(); } } -bool MembersWidget::limitReachedHook(const ClickHandlerPtr &handler, Qt::MouseButton button) { - Ui::showLayer(new ConvertToSupergroupBox(peer()->asChat())); - return false; -} - void MembersWidget::checkSelfAdmin(ChatData *chat) { if (chat->participants.isEmpty()) return; @@ -608,7 +604,9 @@ ChannelMembersWidget::ChannelMembersWidget(QWidget *parent, PeerData *peer) : Bl | UpdateFlag::ChannelCanViewMembers | UpdateFlag::AdminsChanged | UpdateFlag::MembersChanged; - Notify::registerPeerObserver(observeEvents, this, &ChannelMembersWidget::notifyPeerUpdated); + subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { + notifyPeerUpdated(update); + })); refreshButtons(); } diff --git a/Telegram/SourceFiles/profile/profile_members_widget.h b/Telegram/SourceFiles/profile/profile_members_widget.h index 83ed921af1..6e7cb28b31 100644 --- a/Telegram/SourceFiles/profile/profile_members_widget.h +++ b/Telegram/SourceFiles/profile/profile_members_widget.h @@ -78,7 +78,6 @@ private slots: private: // Observed notifications. void notifyPeerUpdated(const Notify::PeerUpdate &update); - void repaintCallback(); void preloadUserPhotos(); diff --git a/Telegram/SourceFiles/profile/profile_settings_widget.cpp b/Telegram/SourceFiles/profile/profile_settings_widget.cpp index c79d9e180e..d94ec98689 100644 --- a/Telegram/SourceFiles/profile/profile_settings_widget.cpp +++ b/Telegram/SourceFiles/profile/profile_settings_widget.cpp @@ -51,7 +51,9 @@ SettingsWidget::SettingsWidget(QWidget *parent, PeerData *peer) : BlockWidget(pa observeEvents |= UpdateFlag::UsernameChanged | UpdateFlag::InviteLinkChanged; } } - Notify::registerPeerObserver(observeEvents, this, &SettingsWidget::notifyPeerUpdated); + subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { + notifyPeerUpdated(update); + })); refreshButtons(); _enableNotifications->finishAnimations(); diff --git a/Telegram/SourceFiles/profile/profile_shared_media_widget.cpp b/Telegram/SourceFiles/profile/profile_shared_media_widget.cpp index 23c4063956..4bb82923d7 100644 --- a/Telegram/SourceFiles/profile/profile_shared_media_widget.cpp +++ b/Telegram/SourceFiles/profile/profile_shared_media_widget.cpp @@ -51,7 +51,10 @@ QString getButtonText(MediaOverviewType type, int count) { SharedMediaWidget::SharedMediaWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_shared_media)) , _history(App::history(peer)) , _migrated(peer->migrateFrom() ? App::history(peer->migrateFrom()) : nullptr) { - Notify::registerPeerObserver(Notify::PeerUpdate::Flag::SharedMediaChanged, this, &SharedMediaWidget::notifyPeerUpdated); + auto observeEvents = Notify::PeerUpdate::Flag::SharedMediaChanged; + subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { + notifyPeerUpdated(update); + })); App::main()->preloadOverviews(peer); if (_migrated) { diff --git a/Telegram/SourceFiles/profile/profile_userpic_button.cpp b/Telegram/SourceFiles/profile/profile_userpic_button.cpp index 048777f1bf..547d93a107 100644 --- a/Telegram/SourceFiles/profile/profile_userpic_button.cpp +++ b/Telegram/SourceFiles/profile/profile_userpic_button.cpp @@ -36,8 +36,16 @@ UserpicButton::UserpicButton(QWidget *parent, PeerData *peer) : Button(parent), _userpic = prepareUserpicPixmap(); } - Notify::registerPeerObserver(Notify::PeerUpdate::Flag::PhotoChanged, this, &UserpicButton::notifyPeerUpdated); - FileDownload::registerImageLoadedObserver(this, &UserpicButton::notifyImageLoaded); + auto observeEvents = Notify::PeerUpdate::Flag::PhotoChanged; + subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { + notifyPeerUpdated(update); + })); + subscribe(FileDownload::ImageLoaded(), [this] { + if (_waiting && _peer->userpicLoaded()) { + _waiting = false; + startNewPhotoShowing(); + } + }); } void UserpicButton::showFinished() { @@ -45,7 +53,7 @@ void UserpicButton::showFinished() { _notShownYet = false; if (!_waiting) { _a_appearance.finish(); - START_ANIMATION(_a_appearance, func(this, &UserpicButton::refreshCallback), 0, 1, st::profilePhotoDuration, anim::linear); + _a_appearance.start([this] { update(); }, 0, 1, st::profilePhotoDuration); } } } @@ -68,13 +76,6 @@ void UserpicButton::notifyPeerUpdated(const Notify::PeerUpdate &update) { this->update(); } -void UserpicButton::notifyImageLoaded() { - if (_waiting && _peer->userpicLoaded()) { - _waiting = false; - startNewPhotoShowing(); - } -} - void UserpicButton::processPeerPhoto() { bool hasPhoto = (_peer->photoId && _peer->photoId != UnknownPeerPhotoId); setCursor(hasPhoto ? style::cur_pointer : style::cur_default); @@ -100,7 +101,7 @@ void UserpicButton::startNewPhotoShowing() { } _a_appearance.finish(); - START_ANIMATION(_a_appearance, func(this, &UserpicButton::refreshCallback), 0, 1, st::profilePhotoDuration, anim::linear); + _a_appearance.start([this] { update(); }, 0, 1, st::profilePhotoDuration); update(); } diff --git a/Telegram/SourceFiles/profile/profile_userpic_button.h b/Telegram/SourceFiles/profile/profile_userpic_button.h index 8dc63b1f6b..0bec52b7a2 100644 --- a/Telegram/SourceFiles/profile/profile_userpic_button.h +++ b/Telegram/SourceFiles/profile/profile_userpic_button.h @@ -28,7 +28,7 @@ struct PeerUpdate; namespace Profile { -class UserpicButton final : public Button, public Notify::Observer { +class UserpicButton final : public Button, private base::Subscriber { public: UserpicButton(QWidget *parent, PeerData *peer); @@ -41,11 +41,6 @@ protected: private: void notifyPeerUpdated(const Notify::PeerUpdate &update); - void notifyImageLoaded(); - - void refreshCallback() { - update(); - } void processPeerPhoto(); void processNewPeerPhoto(); diff --git a/Telegram/SourceFiles/settings/settings_background_widget.cpp b/Telegram/SourceFiles/settings/settings_background_widget.cpp index 61c7cf27f9..ac25cbd539 100644 --- a/Telegram/SourceFiles/settings/settings_background_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_background_widget.cpp @@ -163,9 +163,11 @@ void BackgroundRow::updateImage() { } BackgroundWidget::BackgroundWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_background)) { - FileDialog::registerObserver(this, &BackgroundWidget::notifyFileQueryUpdated); createControls(); + subscribe(FileDialog::QueryDone(), [this](const FileDialog::QueryUpdate &update) { + notifyFileQueryUpdated(update); + }); subscribe(Window::chatBackground(), [this](const Window::ChatBackgroundUpdate &update) { using Update = Window::ChatBackgroundUpdate; if (update.type == Update::Type::New) { diff --git a/Telegram/SourceFiles/settings/settings_block_widget.h b/Telegram/SourceFiles/settings/settings_block_widget.h index 2118db4844..6f34ae1528 100644 --- a/Telegram/SourceFiles/settings/settings_block_widget.h +++ b/Telegram/SourceFiles/settings/settings_block_widget.h @@ -32,7 +32,7 @@ class WidgetSlideWrap; namespace Settings { -class BlockWidget : public ScrolledWidget, public Notify::Observer, protected base::Subscriber { +class BlockWidget : public ScrolledWidget, protected base::Subscriber { Q_OBJECT public: diff --git a/Telegram/SourceFiles/settings/settings_cover.cpp b/Telegram/SourceFiles/settings/settings_cover.cpp index 11047c0672..01ab0d4500 100644 --- a/Telegram/SourceFiles/settings/settings_cover.cpp +++ b/Telegram/SourceFiles/settings/settings_cover.cpp @@ -57,8 +57,12 @@ CoverWidget::CoverWidget(QWidget *parent, UserData *self) : BlockWidget(parent, connect(_editNameInline, SIGNAL(clicked()), this, SLOT(onEditName())); auto observeEvents = Notify::PeerUpdate::Flag::NameChanged; - Notify::registerPeerObserver(observeEvents, this, &CoverWidget::notifyPeerUpdated); - FileDialog::registerObserver(this, &CoverWidget::notifyFileQueryUpdated); + subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { + notifyPeerUpdated(update); + })); + subscribe(FileDialog::QueryDone(), [this](const FileDialog::QueryUpdate &update) { + notifyFileQueryUpdated(update); + }); connect(App::app(), SIGNAL(peerPhotoDone(PeerId)), this, SLOT(onPhotoUploadStatusChanged(PeerId))); connect(App::app(), SIGNAL(peerPhotoFail(PeerId)), this, SLOT(onPhotoUploadStatusChanged(PeerId))); @@ -217,7 +221,7 @@ void CoverWidget::dragEnterEvent(QDragEnterEvent *e) { void CoverWidget::dragLeaveEvent(QDragLeaveEvent *e) { if (_dropArea && !_dropArea->hiding()) { - _dropArea->hideAnimated(func(this, &CoverWidget::dropAreaHidden)); + _dropArea->hideAnimated([this](Profile::CoverDropArea *area) { dropAreaHidden(area); }); } } @@ -228,7 +232,7 @@ void CoverWidget::dropEvent(QDropEvent *e) { if (mimeData->hasImage()) { img = qvariant_cast(mimeData->imageData()); } else { - const auto &urls = mimeData->urls(); + auto urls = mimeData->urls(); if (urls.size() == 1) { auto &url = urls.at(0); if (url.isLocalFile()) { @@ -238,7 +242,7 @@ void CoverWidget::dropEvent(QDropEvent *e) { } if (!_dropArea->hiding()) { - _dropArea->hideAnimated(func(this, &CoverWidget::dropAreaHidden)); + _dropArea->hideAnimated([this](Profile::CoverDropArea *area) { dropAreaHidden(area); }); } e->acceptProposedAction(); diff --git a/Telegram/SourceFiles/settings/settings_general_widget.cpp b/Telegram/SourceFiles/settings/settings_general_widget.cpp index 60b2a15e28..4945dd5c8c 100644 --- a/Telegram/SourceFiles/settings/settings_general_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_general_widget.cpp @@ -171,7 +171,9 @@ GeneralWidget::GeneralWidget(QWidget *parent, UserData *self) : BlockWidget(pare , _changeLanguage(this, lang(lng_settings_change_lang), st::defaultBoxLinkButton) { connect(_changeLanguage, SIGNAL(clicked()), this, SLOT(onChangeLanguage())); subscribe(Global::RefChooseCustomLang(), [this]() { chooseCustomLang(); }); - FileDialog::registerObserver(this, &GeneralWidget::notifyFileQueryUpdated); + subscribe(FileDialog::QueryDone(), [this](const FileDialog::QueryUpdate &update) { + notifyFileQueryUpdated(update); + }); refreshControls(); } diff --git a/Telegram/SourceFiles/settings/settings_info_widget.cpp b/Telegram/SourceFiles/settings/settings_info_widget.cpp index 88acf95b46..a814317d9d 100644 --- a/Telegram/SourceFiles/settings/settings_info_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_info_widget.cpp @@ -34,7 +34,9 @@ using UpdateFlag = Notify::PeerUpdate::Flag; InfoWidget::InfoWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_info)) { auto observeEvents = UpdateFlag::UsernameChanged | UpdateFlag::UserPhoneChanged; - Notify::registerPeerObserver(observeEvents, this, &InfoWidget::notifyPeerUpdated); + subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { + notifyPeerUpdated(update); + })); createControls(); } @@ -81,7 +83,10 @@ void InfoWidget::refreshUsername() { usernameText.entities.push_back(EntityInText(EntityInTextCustomUrl, 0, usernameText.text.size(), qsl("https://telegram.me/") + self()->username)); setLabeledText(_username, lang(lng_profile_username), usernameText, TextWithEntities(), copyText); if (auto text = _username->entity()->textLabel()) { - text->setClickHandlerHook(func(this, &InfoWidget::usernameClickHandlerHook)); + text->setClickHandlerHook([](const ClickHandlerPtr &handler, Qt::MouseButton button) { + Ui::showLayer(new UsernameBox()); + return false; + }); } } @@ -96,19 +101,20 @@ void InfoWidget::refreshLink() { } setLabeledText(_link, lang(lng_profile_link), linkText, linkTextShort, QString()); if (auto text = _link->entity()->textLabel()) { - text->setClickHandlerHook(func(this, &InfoWidget::usernameClickHandlerHook)); + text->setClickHandlerHook([](const ClickHandlerPtr &handler, Qt::MouseButton button) { + Ui::showLayer(new UsernameBox()); + return false; + }); } if (auto shortText = _link->entity()->shortTextLabel()) { shortText->setExpandLinksMode(ExpandLinksUrlOnly); - shortText->setClickHandlerHook(func(this, &InfoWidget::usernameClickHandlerHook)); + shortText->setClickHandlerHook([](const ClickHandlerPtr &handler, Qt::MouseButton button) { + Ui::showLayer(new UsernameBox()); + return false; + }); } } -bool InfoWidget::usernameClickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button) { - Ui::showLayer(new UsernameBox()); - return false; -} - void InfoWidget::setLabeledText(ChildWidget &row, const QString &label, const TextWithEntities &textWithEntities, const TextWithEntities &shortTextWithEntities, const QString ©Text) { if (textWithEntities.text.isEmpty()) { row->slideUp(); diff --git a/Telegram/SourceFiles/settings/settings_info_widget.h b/Telegram/SourceFiles/settings/settings_info_widget.h index 6ffdc791d1..52a6f2b058 100644 --- a/Telegram/SourceFiles/settings/settings_info_widget.h +++ b/Telegram/SourceFiles/settings/settings_info_widget.h @@ -38,8 +38,6 @@ private: // Observed notifications. void notifyPeerUpdated(const Notify::PeerUpdate &update); - bool usernameClickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button); - void createControls(); void refreshControls(); void refreshMobileNumber(); diff --git a/Telegram/SourceFiles/settings/settings_inner_widget.cpp b/Telegram/SourceFiles/settings/settings_inner_widget.cpp index 70b4099864..15b342cca3 100644 --- a/Telegram/SourceFiles/settings/settings_inner_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_inner_widget.cpp @@ -59,6 +59,7 @@ void InnerWidget::selfUpdated() { void InnerWidget::refreshBlocks() { _cover.destroyDelayed(); for_const (auto block, _blocks) { + block->hide(); block->deleteLater(); } _blocks.clear(); @@ -81,6 +82,9 @@ void InnerWidget::refreshBlocks() { if (_cover) { _cover->show(); + if (_showFinished) { + _cover->showFinished(); + } } for_const (auto block, _blocks) { block->show(); @@ -89,6 +93,7 @@ void InnerWidget::refreshBlocks() { } void InnerWidget::showFinished() { + _showFinished = true; if (_cover) { _cover->showFinished(); } diff --git a/Telegram/SourceFiles/settings/settings_inner_widget.h b/Telegram/SourceFiles/settings/settings_inner_widget.h index 570c7958e8..a14cccf393 100644 --- a/Telegram/SourceFiles/settings/settings_inner_widget.h +++ b/Telegram/SourceFiles/settings/settings_inner_widget.h @@ -65,6 +65,7 @@ private: UserData *_self = nullptr; int _contentLeft = 0; + bool _showFinished = false; int _visibleTop = 0; int _visibleBottom = 0; diff --git a/Telegram/SourceFiles/settings/settings_widget.cpp b/Telegram/SourceFiles/settings/settings_widget.cpp index 5c591cb000..114883840c 100644 --- a/Telegram/SourceFiles/settings/settings_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_widget.cpp @@ -26,6 +26,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "styles/style_settings.h" #include "ui/scrollarea.h" #include "mainwindow.h" +#include "mainwidget.h" #include "localstorage.h" #include "boxes/confirmbox.h" #include "application.h" @@ -80,6 +81,11 @@ void fillCodes() { }); Ui::showLayer(box.release()); }); + Codes.insert(qsl("getdifference"), []() { + if (auto main = App::main()) { + main->getDifference(); + } + }); } void codesFeedString(const QString &text) { diff --git a/Telegram/SourceFiles/stickers/emoji_pan.cpp b/Telegram/SourceFiles/stickers/emoji_pan.cpp index a6060ffda4..d7a73e2217 100644 --- a/Telegram/SourceFiles/stickers/emoji_pan.cpp +++ b/Telegram/SourceFiles/stickers/emoji_pan.cpp @@ -801,7 +801,6 @@ StickerPanInner::StickerPanInner() : ScrolledWidget() setFocusPolicy(Qt::NoFocus); setAttribute(Qt::WA_OpaquePaintEvent); - connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(onImageLoaded())); connect(&_settings, SIGNAL(clicked()), this, SLOT(onSettings())); _previewTimer.setSingleShot(true); @@ -809,6 +808,11 @@ StickerPanInner::StickerPanInner() : ScrolledWidget() _updateInlineItems.setSingleShot(true); connect(&_updateInlineItems, SIGNAL(timeout()), this, SLOT(onUpdateInlineItems())); + + subscribe(FileDownload::ImageLoaded(), [this] { + update(); + readVisibleSets(); + }); } void StickerPanInner::setMaxHeight(int32 h) { @@ -855,11 +859,6 @@ void StickerPanInner::readVisibleSets() { } } -void StickerPanInner::onImageLoaded() { - update(); - readVisibleSets(); -} - int StickerPanInner::featuredRowHeight() const { return st::featuredStickersHeader + st::stickerPanSize.height() + st::featuredStickersSkip; } diff --git a/Telegram/SourceFiles/stickers/emoji_pan.h b/Telegram/SourceFiles/stickers/emoji_pan.h index 92da29b81f..71b542af7f 100644 --- a/Telegram/SourceFiles/stickers/emoji_pan.h +++ b/Telegram/SourceFiles/stickers/emoji_pan.h @@ -207,7 +207,7 @@ struct StickerIcon { int pixh = 0; }; -class StickerPanInner : public ScrolledWidget { +class StickerPanInner : public ScrolledWidget, private base::Subscriber { Q_OBJECT public: @@ -274,7 +274,6 @@ private slots: void onPreview(); void onUpdateInlineItems(); void onSwitchPm(); - void onImageLoaded(); signals: void selected(DocumentData *sticker); diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index 3608e44fb5..d4da9c335d 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -27,12 +27,11 @@ static const ChannelId NoChannel = 0; typedef int32 MsgId; struct FullMsgId { - FullMsgId() : channel(NoChannel), msg(0) { - } + FullMsgId() = default; FullMsgId(ChannelId channel, MsgId msg) : channel(channel), msg(msg) { } - ChannelId channel; - MsgId msg; + ChannelId channel = NoChannel; + MsgId msg = 0; }; typedef uint64 PeerId; diff --git a/Telegram/SourceFiles/ui/animation.cpp b/Telegram/SourceFiles/ui/animation.cpp index 3f6d97a372..83e3bc7298 100644 --- a/Telegram/SourceFiles/ui/animation.cpp +++ b/Telegram/SourceFiles/ui/animation.cpp @@ -120,7 +120,7 @@ AnimationManager::AnimationManager() : _timer(this), _iterating(false) { void AnimationManager::start(Animation *obj) { if (_iterating) { - _starting.insert(obj, NullType()); + _starting.insert(obj); if (!_stopping.isEmpty()) { _stopping.remove(obj); } @@ -128,21 +128,21 @@ void AnimationManager::start(Animation *obj) { if (_objects.isEmpty()) { _timer.start(AnimationTimerDelta); } - _objects.insert(obj, NullType()); + _objects.insert(obj); } } void AnimationManager::stop(Animation *obj) { if (_iterating) { - _stopping.insert(obj, NullType()); + _stopping.insert(obj); if (!_starting.isEmpty()) { _starting.remove(obj); } } else { - AnimatingObjects::iterator i = _objects.find(obj); + auto i = _objects.find(obj); if (i != _objects.cend()) { _objects.erase(i); - if (_objects.isEmpty()) { + if (_objects.empty()) { _timer.stop(); } } @@ -152,26 +152,26 @@ void AnimationManager::stop(Animation *obj) { void AnimationManager::timeout() { _iterating = true; uint64 ms = getms(); - for (AnimatingObjects::const_iterator i = _objects.begin(), e = _objects.end(); i != e; ++i) { - if (!_stopping.contains(i.key())) { - i.key()->step(ms, true); + for_const (auto object, _objects) { + if (!_stopping.contains(object)) { + object->step(ms, true); } } _iterating = false; if (!_starting.isEmpty()) { - for (AnimatingObjects::iterator i = _starting.begin(), e = _starting.end(); i != e; ++i) { - _objects.insert(i.key(), NullType()); + for_const (auto object, _starting) { + _objects.insert(object); } _starting.clear(); } if (!_stopping.isEmpty()) { - for (AnimatingObjects::iterator i = _stopping.begin(), e = _stopping.end(); i != e; ++i) { - _objects.remove(i.key()); + for_const (auto object, _stopping) { + _objects.remove(object); } _stopping.clear(); } - if (!_objects.size()) { + if (_objects.empty()) { _timer.stop(); } } diff --git a/Telegram/SourceFiles/ui/animation.h b/Telegram/SourceFiles/ui/animation.h index 8fc5201cfb..4130012c66 100644 --- a/Telegram/SourceFiles/ui/animation.h +++ b/Telegram/SourceFiles/ui/animation.h @@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #pragma once #include "core/basic_types.h" +#include "core/lambda_wrap.h" #include #include @@ -57,6 +58,7 @@ namespace anim { class fvalue { // float animated value public: + using ValueType = float64; fvalue() { } @@ -88,15 +90,14 @@ namespace anim { _delta = 0; } - typedef float64 Type; - private: - float64 _cur, _from, _delta; + }; class ivalue { // int animated value public: + using ValueType = int32; ivalue() { } @@ -128,16 +129,15 @@ namespace anim { _delta = 0; } - typedef int32 Type; - private: - int32 _cur; float64 _from, _delta; + }; class cvalue { // QColor animated value public: + using ValueType = QColor; cvalue() { } @@ -199,12 +199,10 @@ namespace anim { _delta_r = _delta_g = _delta_b = _delta_a = 0; } - typedef QColor Type; - private: - QColor _cur; float64 _from_r, _from_g, _from_b, _from_a, _delta_r, _delta_g, _delta_b, _delta_a; + }; void startManager(); @@ -380,105 +378,81 @@ AnimationCallbacks animation(Param param, Type *obj, typename AnimationCallbacks template class SimpleAnimation { public: - using Callback = Function; + using ValueType = typename AnimType::ValueType; + using Callback = base::lambda_unique; - SimpleAnimation() { + bool animating() const { + if (_data) { + if (_data->a_animation.animating()) { + return true; + } + _data.reset(); + } + return false; } - bool animating(uint64 ms) { - if (_data && _data->_a.animating()) { - _data->_a.step(ms); - return _data && _data->_a.animating(); + if (animating()) { + _data->a_animation.step(ms); + return animating(); } return false; } - bool isNull() const { - return !_data; + ValueType current() const { + t_assert(_data != nullptr); + return _data->value.current(); } - - typename AnimType::Type current() { - return _data ? _data->a.current() : typename AnimType::Type(); + ValueType current(const ValueType &def) const { + return _data ? current() : def; } - - typename AnimType::Type current(const typename AnimType::Type &def) { - return _data ? _data->a.current() : def; - } - - typename AnimType::Type current(uint64 ms, const typename AnimType::Type &def) { + ValueType current(uint64 ms, const ValueType &def) { return animating(ms) ? current() : def; } - void setup(const typename AnimType::Type &from, Callback &&update) { + template + void start(Lambda &&updateCallback, const ValueType &from, const ValueType &to, float64 duration, anim::transition transition = anim::linear) { if (!_data) { - _data = new Data(from, std_::move(update), animation(this, &SimpleAnimation::step)); - } else { - _data->a = AnimType(from, from); - } - } - - void start(const typename AnimType::Type &to, float64 duration, anim::transition transition = anim::linear) { - if (_data) { - _data->a.start(to); - _data->_a.start(); - _data->duration = duration; - _data->transition = transition; + _data = std_::make_unique(from, std_::move(updateCallback)); } + _data->value.start(to); + _data->duration = duration; + _data->transition = transition; + _data->a_animation.start(); } void finish() { - if (isNull()) { - return; + if (_data) { + _data->value.finish(); + _data->a_animation.stop(); + _data.reset(); } - - _data->a.finish(); - _data->_a.stop(); - delete _data; - _data = nullptr; - } - - ~SimpleAnimation() { - deleteAndMark(_data); } private: struct Data { - Data(const typename AnimType::Type &from, Callback &&update, AnimationCallbacks &&acb) - : a(from, from) - , _a(std_::move(acb)) - , update(std_::move(update)) - , duration(0) - , transition(anim::linear) { + Data(const ValueType &from, Callback &&updateCallback) + : value(from, from) + , a_animation(animation(this, &Data::step)) + , updateCallback(std_::move(updateCallback)) { } - AnimType a; - Animation _a; - Callback update; - float64 duration; - anim::transition transition; + void step(float64 ms, bool timer) { + auto dt = (ms >= duration) ? 1. : (ms / duration); + if (dt >= 1) { + value.finish(); + a_animation.stop(); + } else { + value.update(dt, transition); + } + updateCallback(); + } + + AnimType value; + Animation a_animation; + Callback updateCallback; + float64 duration = 0.; + anim::transition transition = anim::linear; }; - Data *_data = nullptr; - - void step(float64 ms, bool timer) { - float64 dt = (ms >= _data->duration) ? 1 : (ms / _data->duration); - if (dt >= 1) { - _data->a.finish(); - _data->_a.stop(); - } else { - _data->a.update(dt, _data->transition); - } - - Callback callbackCache, *toCall = &_data->update; - if (!_data->_a.animating()) { - callbackCache = std_::move(_data->update); - toCall = &callbackCache; - - delete _data; - _data = nullptr; - } - if (timer) { - toCall->call(); - } - } + mutable std_::unique_ptr _data; }; @@ -486,18 +460,8 @@ using FloatAnimation = SimpleAnimation; using IntAnimation = SimpleAnimation; using ColorAnimation = SimpleAnimation; -// Macro allows us to lazily create updateCallback. -#define ENSURE_ANIMATION(animation, updateCallback, from) \ -if ((animation).isNull()) { \ - (animation).setup((from), (updateCallback)); \ -} - -#define START_ANIMATION(animation, updateCallback, from, to, duration, transition) \ -ENSURE_ANIMATION(animation, updateCallback, from); \ -(animation).start((to), (duration), (transition)) - class AnimationManager : public QObject { -Q_OBJECT + Q_OBJECT public: AnimationManager(); @@ -511,7 +475,7 @@ public slots: void clipCallback(Media::Clip::Reader *reader, qint32 threadIndex, qint32 notification); private: - typedef QMap AnimatingObjects; + using AnimatingObjects = OrderedSet; AnimatingObjects _objects, _starting, _stopping; QTimer _timer; bool _iterating; diff --git a/Telegram/SourceFiles/ui/buttons/history_down_button.cpp b/Telegram/SourceFiles/ui/buttons/history_down_button.cpp index 2b1fd86e98..773742426f 100644 --- a/Telegram/SourceFiles/ui/buttons/history_down_button.cpp +++ b/Telegram/SourceFiles/ui/buttons/history_down_button.cpp @@ -118,7 +118,7 @@ void HistoryDownButton::hideAnimated() { void HistoryDownButton::toggleAnimated() { _shown = !_shown; float64 from = _shown ? 0. : 1., to = _shown ? 1. : 0.; - START_ANIMATION(_a_show, func(this, &HistoryDownButton::repaintCallback), from, to, st::btnAttachEmoji.duration, anim::linear); + _a_show.start([this] { update(); }, from, to, st::btnAttachEmoji.duration); } void HistoryDownButton::finishAnimation() { diff --git a/Telegram/SourceFiles/ui/buttons/history_down_button.h b/Telegram/SourceFiles/ui/buttons/history_down_button.h index 43dbd098c1..8030a905e9 100644 --- a/Telegram/SourceFiles/ui/buttons/history_down_button.h +++ b/Telegram/SourceFiles/ui/buttons/history_down_button.h @@ -47,9 +47,6 @@ protected: private: void toggleAnimated(); - void repaintCallback() { - update(); - } void step_arrowOver(float64 ms, bool timer); QPixmap _cache; diff --git a/Telegram/SourceFiles/ui/buttons/icon_button.cpp b/Telegram/SourceFiles/ui/buttons/icon_button.cpp index 43498c7cce..2a562d2894 100644 --- a/Telegram/SourceFiles/ui/buttons/icon_button.cpp +++ b/Telegram/SourceFiles/ui/buttons/icon_button.cpp @@ -49,7 +49,7 @@ void IconButton::onStateChanged(int oldState, ButtonStateChangeSource source) { if (over != (oldState & StateOver)) { auto from = over ? 0. : 1.; auto to = over ? 1. : 0.; - START_ANIMATION(_a_over, func(this, &IconButton::updateCallback), from, to, _st.duration, anim::linear); + _a_over.start([this] { update(); }, from, to, _st.duration); } } diff --git a/Telegram/SourceFiles/ui/buttons/icon_button.h b/Telegram/SourceFiles/ui/buttons/icon_button.h index 758c59567e..488a49df12 100644 --- a/Telegram/SourceFiles/ui/buttons/icon_button.h +++ b/Telegram/SourceFiles/ui/buttons/icon_button.h @@ -37,10 +37,6 @@ protected: void onStateChanged(int oldState, ButtonStateChangeSource source) override; private: - void updateCallback() { - update(); - } - const style::IconButton &_st; const style::icon *_iconOverride = nullptr; diff --git a/Telegram/SourceFiles/ui/effects/fade_animation.cpp b/Telegram/SourceFiles/ui/effects/fade_animation.cpp index 9936c51e58..5e2663a5d9 100644 --- a/Telegram/SourceFiles/ui/effects/fade_animation.cpp +++ b/Telegram/SourceFiles/ui/effects/fade_animation.cpp @@ -65,7 +65,9 @@ void FadeAnimation::stopAnimation() { _cache = QPixmap(); updateCallback(); _widget->showChildren(); - _finishedCallback.call(); + if (_finishedCallback) { + _finishedCallback(); + } } if (_visible == _widget->isHidden()) { _widget->setVisible(_visible); @@ -91,7 +93,9 @@ void FadeAnimation::startAnimation(int duration) { _cache = myGrab(_widget); _widget->hideChildren(); } - START_ANIMATION(_animation, func(this, &FadeAnimation::updateCallback), _visible ? 0. : 1., _visible ? 1. : 0., duration, anim::linear); + auto from = _visible ? 0. : 1.; + auto to = _visible ? 1. : 0.; + _animation.start([this]() { updateCallback(); }, from, to, duration); updateCallback(); if (_widget->isHidden()) { _widget->show(); @@ -101,7 +105,9 @@ void FadeAnimation::startAnimation(int duration) { void FadeAnimation::updateCallback() { if (_animation.animating(getms())) { _widget->update(); - _updatedCallback.call(_animation.current()); + if (_updatedCallback) { + _updatedCallback(_animation.current(_visible ? 1. : 0.)); + } } else { stopAnimation(); } diff --git a/Telegram/SourceFiles/ui/effects/fade_animation.h b/Telegram/SourceFiles/ui/effects/fade_animation.h index aaf95129fa..4ed09de046 100644 --- a/Telegram/SourceFiles/ui/effects/fade_animation.h +++ b/Telegram/SourceFiles/ui/effects/fade_animation.h @@ -31,10 +31,10 @@ public: bool paint(Painter &p); void refreshCache(); - using FinishedCallback = Function; + using FinishedCallback = base::lambda_unique; void setFinishedCallback(FinishedCallback &&callback); - using UpdatedCallback = Function; + using UpdatedCallback = base::lambda_unique; void setUpdatedCallback(UpdatedCallback &&callback); void show(); diff --git a/Telegram/SourceFiles/ui/filedialog.cpp b/Telegram/SourceFiles/ui/filedialog.cpp index 45a947ceb8..4601b616e8 100644 --- a/Telegram/SourceFiles/ui/filedialog.cpp +++ b/Telegram/SourceFiles/ui/filedialog.cpp @@ -255,7 +255,7 @@ QString filedialogAllFilesFilter() { namespace FileDialog { namespace { -using internal::QueryUpdateHandler; +base::Observable QueryDoneObservable; struct Query { enum class Type { @@ -285,16 +285,10 @@ void StartCallback() { Queries.makeIfNull(); } -void FinishCallback() { - Queries.clear(); -} - -Notify::SimpleObservedEventRegistrator creator(StartCallback, FinishCallback); - } // namespace QueryId queryReadFile(const QString &caption, const QString &filter) { - t_assert(creator.started()); + Queries.makeIfNull(); Queries->push_back(Query(Query::Type::ReadFile, caption, filter)); Global::RefHandleFileDialogQueue().call(); @@ -302,7 +296,7 @@ QueryId queryReadFile(const QString &caption, const QString &filter) { } QueryId queryReadFiles(const QString &caption, const QString &filter) { - t_assert(creator.started()); + Queries.makeIfNull(); Queries->push_back(Query(Query::Type::ReadFiles, caption, filter)); Global::RefHandleFileDialogQueue().call(); @@ -310,7 +304,7 @@ QueryId queryReadFiles(const QString &caption, const QString &filter) { } QueryId queryWriteFile(const QString &caption, const QString &filter, const QString &filePath) { - t_assert(creator.started()); + Queries.makeIfNull(); Queries->push_back(Query(Query::Type::WriteFile, caption, filter, filePath)); Global::RefHandleFileDialogQueue().call(); @@ -318,7 +312,7 @@ QueryId queryWriteFile(const QString &caption, const QString &filter, const QStr } QueryId queryReadFolder(const QString &caption) { - t_assert(creator.started()); + Queries.makeIfNull(); Queries->push_back(Query(Query::Type::ReadFolder, caption)); Global::RefHandleFileDialogQueue().call(); @@ -326,7 +320,7 @@ QueryId queryReadFolder(const QString &caption) { } bool processQuery() { - if (!creator.started() || !Global::started() || Queries->isEmpty()) return false; + if (!Queries || !Global::started() || Queries->isEmpty()) return false; auto query = Queries->front(); Queries->pop_front(); @@ -374,17 +368,14 @@ bool processQuery() { } // No one knows what happened during filedialogGet*() call in the event loop. - if (!creator.started() || !Global::started()) return false; + if (!Queries || !Global::started()) return false; - creator.notify(update); + QueryDone().notify(std_::move(update)); return true; } -namespace internal { - -Notify::ConnectionId plainRegisterObserver(QueryUpdateHandler &&handler) { - return creator.registerObserver(std_::forward(handler)); +base::Observable &QueryDone() { + return QueryDoneObservable; } -} // namespace internal } // namespace FileDialog diff --git a/Telegram/SourceFiles/ui/filedialog.h b/Telegram/SourceFiles/ui/filedialog.h index c3d7742945..fac4b2a7de 100644 --- a/Telegram/SourceFiles/ui/filedialog.h +++ b/Telegram/SourceFiles/ui/filedialog.h @@ -63,17 +63,6 @@ QueryId queryReadFolder(const QString &caption); // NB! This function enters an event loop. bool processQuery(); -namespace internal { - -using QueryUpdateHandler = Function; -Notify::ConnectionId plainRegisterObserver(QueryUpdateHandler &&handler); - -} // namespace internal - -template -void registerObserver(ObserverType *observer, void (ObserverType::*handler)(const QueryUpdate &)) { - auto connection = internal::plainRegisterObserver(func(observer, handler)); - Notify::observerRegistered(observer, connection); -} +base::Observable &QueryDone(); } // namespace FileDialog diff --git a/Telegram/SourceFiles/ui/flatbutton.cpp b/Telegram/SourceFiles/ui/flatbutton.cpp index 3ed82ca7bf..167d30f867 100644 --- a/Telegram/SourceFiles/ui/flatbutton.cpp +++ b/Telegram/SourceFiles/ui/flatbutton.cpp @@ -332,7 +332,7 @@ void EmojiButton::setLoading(bool loading) { if (_loading != loading) { _loading = loading; auto from = loading ? 0. : 1., to = loading ? 1. : 0.; - START_ANIMATION(a_loading, func(this, &EmojiButton::updateCallback), from, to, st::emojiCircleDuration, anim::linear); + a_loading.start([this] { update(); }, from, to, st::emojiCircleDuration); if (loading) { _a_loading.start(); } else { diff --git a/Telegram/SourceFiles/ui/flatbutton.h b/Telegram/SourceFiles/ui/flatbutton.h index 83d725615d..090b3232f0 100644 --- a/Telegram/SourceFiles/ui/flatbutton.h +++ b/Telegram/SourceFiles/ui/flatbutton.h @@ -147,12 +147,9 @@ private: void step_loading(uint64 ms, bool timer) { if (timer) { - updateCallback(); + update(); } } - void updateCallback() { - update(); - } }; diff --git a/Telegram/SourceFiles/ui/flatlabel.cpp b/Telegram/SourceFiles/ui/flatlabel.cpp index 9430098dc3..dc73d2b062 100644 --- a/Telegram/SourceFiles/ui/flatlabel.cpp +++ b/Telegram/SourceFiles/ui/flatlabel.cpp @@ -236,7 +236,7 @@ Text::StateResult FlatLabel::dragActionFinish(const QPoint &p, Qt::MouseButton b _selectionType = TextSelectType::Letters; if (activated) { - if (_clickHandlerHook.isNull() || _clickHandlerHook.call(activated, button)) { + if (!_clickHandlerHook || _clickHandlerHook(activated, button)) { App::activateClickHandler(activated, button); } } diff --git a/Telegram/SourceFiles/ui/flatlabel.h b/Telegram/SourceFiles/ui/flatlabel.h index fb00def184..912144c11f 100644 --- a/Telegram/SourceFiles/ui/flatlabel.h +++ b/Telegram/SourceFiles/ui/flatlabel.h @@ -47,7 +47,7 @@ public: void setLink(uint16 lnkIndex, const ClickHandlerPtr &lnk); - using ClickHandlerHook = Function; + using ClickHandlerHook = base::lambda_unique; void setClickHandlerHook(ClickHandlerHook &&hook); // ClickHandlerHost interface diff --git a/Telegram/SourceFiles/ui/inner_dropdown.cpp b/Telegram/SourceFiles/ui/inner_dropdown.cpp index ad6ccf2384..8065c18e05 100644 --- a/Telegram/SourceFiles/ui/inner_dropdown.cpp +++ b/Telegram/SourceFiles/ui/inner_dropdown.cpp @@ -160,12 +160,12 @@ void InnerDropdown::onHideStart() { void InnerDropdown::startAnimation() { auto from = _hiding ? 1. : 0.; auto to = _hiding ? 0. : 1.; - if (_a_appearance.isNull()) { + if (!_a_appearance.animating()) { showChildren(); _cache = myGrab(this); } hideChildren(); - START_ANIMATION(_a_appearance, func(this, &InnerDropdown::repaintCallback), from, to, _st.duration, anim::linear); + _a_appearance.start([this] { repaintCallback(); }, from, to, _st.duration); } void InnerDropdown::hidingFinished() { @@ -186,7 +186,7 @@ void InnerDropdown::showingStarted() { void InnerDropdown::repaintCallback() { update(); - if (!_a_appearance.animating(getms()) && _hiding) { + if (!_a_appearance.animating() && _hiding) { _hiding = false; hidingFinished(); } diff --git a/Telegram/SourceFiles/ui/inner_dropdown.h b/Telegram/SourceFiles/ui/inner_dropdown.h index 55974f78e9..56f28caecb 100644 --- a/Telegram/SourceFiles/ui/inner_dropdown.h +++ b/Telegram/SourceFiles/ui/inner_dropdown.h @@ -35,7 +35,7 @@ public: void setOwnedWidget(ScrolledWidget *widget); bool overlaps(const QRect &globalRect) { - if (isHidden() || !_a_appearance.isNull()) return false; + if (isHidden() || _a_appearance.animating()) return false; return rect().marginsRemoved(_st.padding).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size())); } diff --git a/Telegram/SourceFiles/ui/twidget.cpp b/Telegram/SourceFiles/ui/twidget.cpp index 2bfac39d8f..20053a7b59 100644 --- a/Telegram/SourceFiles/ui/twidget.cpp +++ b/Telegram/SourceFiles/ui/twidget.cpp @@ -86,7 +86,7 @@ enum class Mode { }; void ToggleableShadow::setMode(Mode mode) { if (mode == Mode::ShownFast || mode == Mode::HiddenFast) { - if (!_a_opacity.isNull()) { + if (!_a_opacity.animating()) { _a_opacity.finish(); update(); } @@ -94,18 +94,12 @@ void ToggleableShadow::setMode(Mode mode) { if (_shown && (mode == Mode::Hidden || mode == Mode::HiddenFast)) { _shown = false; if (mode == Mode::Hidden) { - if (_a_opacity.isNull()) { - _a_opacity.setup(1., func(this, &ToggleableShadow::repaintCallback)); - } - _a_opacity.start(0., st::shadowToggleDuration); + _a_opacity.start([this] { update(); }, 1., 0., st::shadowToggleDuration); } } else if (!_shown && (mode == Mode::Shown || mode == Mode::ShownFast)) { _shown = true; if (mode == Mode::Shown) { - if (_a_opacity.isNull()) { - _a_opacity.setup(0., func(this, &ToggleableShadow::repaintCallback)); - } - _a_opacity.start(1., st::shadowToggleDuration); + _a_opacity.start([this] { update(); }, 0., 1., st::shadowToggleDuration); } } } diff --git a/Telegram/SourceFiles/ui/twidget.h b/Telegram/SourceFiles/ui/twidget.h index 31ae6d2f40..f54112647c 100644 --- a/Telegram/SourceFiles/ui/twidget.h +++ b/Telegram/SourceFiles/ui/twidget.h @@ -268,17 +268,13 @@ public: void setMode(Mode mode); bool isFullyShown() const { - return _shown && _a_opacity.isNull(); + return _shown && !_a_opacity.animating(); } protected: void paintEvent(QPaintEvent *e) override; private: - void repaintCallback() { - update(); - } - const style::color &_color; FloatAnimation _a_opacity; bool _shown = true; diff --git a/Telegram/SourceFiles/ui/widgets/media_slider.cpp b/Telegram/SourceFiles/ui/widgets/media_slider.cpp index 4b21ed2e21..51d85cf5bf 100644 --- a/Telegram/SourceFiles/ui/widgets/media_slider.cpp +++ b/Telegram/SourceFiles/ui/widgets/media_slider.cpp @@ -158,7 +158,7 @@ void MediaSlider::setOver(bool over) { _over = over; auto from = _over ? 0. : 1., to = _over ? 1. : 0.; - START_ANIMATION(_a_over, func([this]() { update(); }), from, to, _st.duration, anim::linear); + _a_over.start([this] { update(); }, from, to, _st.duration); } } // namespace Ui diff --git a/Telegram/SourceFiles/window/section_widget.cpp b/Telegram/SourceFiles/window/section_widget.cpp index 47c0854467..a1f13eed20 100644 --- a/Telegram/SourceFiles/window/section_widget.cpp +++ b/Telegram/SourceFiles/window/section_widget.cpp @@ -50,8 +50,8 @@ void SectionWidget::showAnimated(SlideDirection direction, const SectionSlidePar _showAnimation = std_::make_unique(); _showAnimation->setDirection(direction); - _showAnimation->setRepaintCallback(func(this, &SectionWidget::repaintCallback)); - _showAnimation->setFinishedCallback(func(this, &SectionWidget::showFinished)); + _showAnimation->setRepaintCallback([this] { update(); }); + _showAnimation->setFinishedCallback([this] { showFinished(); }); _showAnimation->setPixmaps(params.oldContentCache, myContentCache); _showAnimation->setTopBarShadow(params.withTopBarShadow); _showAnimation->start(); diff --git a/Telegram/SourceFiles/window/section_widget.h b/Telegram/SourceFiles/window/section_widget.h index b77377fbed..ca72b0dd77 100644 --- a/Telegram/SourceFiles/window/section_widget.h +++ b/Telegram/SourceFiles/window/section_widget.h @@ -89,10 +89,6 @@ protected: } private: - // QWidget::update() method is overloaded and we need template deduction. - void repaintCallback() { - update(); - } void showFinished(); std_::unique_ptr _showAnimation; diff --git a/Telegram/SourceFiles/window/slide_animation.cpp b/Telegram/SourceFiles/window/slide_animation.cpp index 5f53e98fa5..fb9ab988e9 100644 --- a/Telegram/SourceFiles/window/slide_animation.cpp +++ b/Telegram/SourceFiles/window/slide_animation.cpp @@ -92,7 +92,9 @@ void SlideAnimation::step(float64 ms, bool timer) { a_coordUnder.finish(); a_coordOver.finish(); - _finishedCallback.call(); + if (_finishedCallback) { + _finishedCallback(); + } return; } } @@ -100,8 +102,8 @@ void SlideAnimation::step(float64 ms, bool timer) { a_coordUnder.update(dt, st::slideFunction); a_coordOver.update(dt, st::slideFunction); a_progress.update(dt, st::slideFunction); - if (timer) { - _repaintCallback.call(); + if (timer && _repaintCallback) { + _repaintCallback(); } } diff --git a/Telegram/SourceFiles/window/slide_animation.h b/Telegram/SourceFiles/window/slide_animation.h index 5ce4068aec..53a24c3b6d 100644 --- a/Telegram/SourceFiles/window/slide_animation.h +++ b/Telegram/SourceFiles/window/slide_animation.h @@ -37,10 +37,10 @@ public: void setPixmaps(const QPixmap &oldContentCache, const QPixmap &newContentCache); void setTopBarShadow(bool enabled); - using RepaintCallback = Function; + using RepaintCallback = base::lambda_unique; void setRepaintCallback(RepaintCallback &&callback); - using FinishedCallback = Function; + using FinishedCallback = base::lambda_unique; void setFinishedCallback(FinishedCallback &&callback); void start(); diff --git a/Telegram/build/version b/Telegram/build/version index 8cf1ec88d0..a56338061e 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -3,4 +3,4 @@ AppVersionStrMajor 0.10 AppVersionStrSmall 0.10.8 AppVersionStr 0.10.8 AlphaChannel 0 -BetaVersion 0 +BetaVersion 10008001