Merge branch 'master' into player

Conflicts:
	Telegram/SourceFiles/core/observer.h
	Telegram/SourceFiles/mainwindow.h
	Telegram/SourceFiles/media/view/media_clip_playback.cpp
	Telegram/SourceFiles/media/view/media_clip_playback.h
This commit is contained in:
John Preston 2016-09-29 00:16:02 +03:00
commit 0562024444
114 changed files with 743 additions and 1196 deletions

View File

@ -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"

View File

@ -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"

View File

@ -42,11 +42,10 @@ ApiWrap::ApiWrap(QObject *parent) : QObject(parent)
void ApiWrap::init() {
}
void ApiWrap::requestMessageData(ChannelData *channel, MsgId msgId, std_::unique_ptr<RequestMessageDataCallback> 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 {

View File

@ -28,8 +28,8 @@ public:
ApiWrap(QObject *parent);
void init();
using RequestMessageDataCallback = SharedCallback<void, ChannelData*, MsgId>;
void requestMessageData(ChannelData *channel, MsgId msgId, std_::unique_ptr<RequestMessageDataCallback> callback);
using RequestMessageDataCallback = base::lambda_wrap<void(ChannelData*, MsgId)>;
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<void, ChannelData*, MsgId>::Ptr CallbackPtr;
typedef QList<CallbackPtr> Callbacks;
mtpRequestId req;
using Callbacks = QList<RequestMessageDataCallback>;
mtpRequestId req = 0;
Callbacks callbacks;
};
typedef QMap<MsgId, MessageDataRequest> MessageDataRequests;

View File

@ -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) {

View File

@ -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

View File

@ -47,7 +47,7 @@ private:
};
class AbstractBox : public LayerWidget {
class AbstractBox : public LayerWidget, protected base::Subscriber {
Q_OBJECT
public:

View File

@ -1362,8 +1362,8 @@ RevokePublicLinkBox::RevokePublicLinkBox(base::lambda_unique<void()> &&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<TWidget> &&weakThis, PeerData *pressed) : weakThis(std_::move(weakThis)), pressed(pressed) {
}
QPointer<TWidget> weakThis;
PeerData *pressed;
};
weakRevokeConfirmBox->setConfirmedCallback([this, data = std_::make_unique<Data>(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);
}

View File

@ -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);
}

View File

@ -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:

View File

@ -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();
}
}

View File

@ -34,7 +34,7 @@ public:
void updateLink();
// You can use this instead of connecting to "confirmed()" signal.
void setConfirmedCallback(base::lambda_wrap<void()> &&callback) {
void setConfirmedCallback(base::lambda_unique<void()> &&callback) {
_confirmedCallback = std_::move(callback);
}

View File

@ -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*)));

View File

@ -36,7 +36,7 @@ using MembersAlreadyIn = OrderedSet<UserData*>;
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:

View File

@ -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();
}

View File

@ -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::IndexedList>(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<void, ChannelData*, MsgId> {
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<GameMessageResolvedCallback>());
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)));
}
});
}
}
}

View File

@ -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<Icon> icons;
std_::vector_of_moveable<Icon> icons;
};
void paintChat(Painter &p, Chat *chat, int index);
void updateChat(PeerData *peer);

View File

@ -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);
}

View File

@ -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<FloatAnimation> _packOvers;
std_::vector_of_moveable<FloatAnimation> _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:

View File

@ -20,6 +20,17 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include <string>
#include <exception>
#include <QtCore/QReadWriteLock>
#include <ctime>
#ifndef OS_MAC_OLD
#include <memory>
#endif // OS_MAC_OLD
template <typename T>
void deleteAndMark(T *&link) {
delete link;
@ -259,13 +270,6 @@ typedef float float32;
typedef double float64;
#endif
#include <string>
#include <exception>
#include <QtCore/QReadWriteLock>
#include <ctime>
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 <typename Type>
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<sizeof(Type), sizeof(uint64)>::Result * sizeof(uint64),
Type::ComponentConstruct, Type::ComponentDestruct, Type::ComponentMove);
CeilDivideMinimumOne<sizeof(Type), sizeof(SmallestSizeType)>::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 <typename R, typename... Args>
class SharedCallback {
public:
virtual R call(Args... args) const = 0;
virtual ~SharedCallback() {
}
using Ptr = QSharedPointer<SharedCallback<R, Args...>>;
};
template <typename R, typename... Args>
class FunctionImplementation {
public:
virtual R call(Args... args) = 0;
virtual void destroy() { delete this; }
virtual ~FunctionImplementation() {}
};
template <typename R, typename... Args>
class NullFunctionImplementation : public FunctionImplementation<R, Args...> {
public:
R call(Args... args) override { return R(); }
void destroy() override {}
static NullFunctionImplementation<R, Args...> SharedInstance;
};
template <typename R, typename... Args>
NullFunctionImplementation<R, Args...> NullFunctionImplementation<R, Args...>::SharedInstance;
template <typename R, typename... Args>
class Function {
public:
Function() : _implementation(nullImpl()) {}
Function(FunctionImplementation<R, Args...> *implementation) : _implementation(implementation) {}
Function(const Function<R, Args...> &other) = delete;
Function<R, Args...> &operator=(const Function<R, Args...> &other) = delete;
Function(Function<R, Args...> &&other) : _implementation(other._implementation) {
other._implementation = nullImpl();
}
Function<R, Args...> &operator=(Function<R, Args...> &&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<R, Args...> *nullImpl() {
return &NullFunctionImplementation<R, Args...>::SharedInstance;
}
FunctionImplementation<R, Args...> *_implementation;
};
template <typename R, typename... Args>
class WrappedFunction : public FunctionImplementation<R, Args...> {
public:
using Method = R(*)(Args... args);
WrappedFunction(Method method) : _method(method) {}
R call(Args... args) override { return (*_method)(args...); }
private:
Method _method;
};
template <typename R, typename... Args>
inline Function<R, Args...> func(R(*method)(Args... args)) {
return Function<R, Args...>(new WrappedFunction<R, Args...>(method));
}
template <typename O, typename I, typename R, typename... Args>
class ObjectFunction : public FunctionImplementation<R, Args...> {
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 <typename O, typename I, typename R, typename... Args>
inline Function<R, Args...> func(O *obj, R(I::*method)(Args...)) {
return Function<R, Args...>(new ObjectFunction<O, I, R, Args...>(obj, method));
}

View File

@ -20,6 +20,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#ifndef OS_MAC_OLD
#include <memory>
#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 <typename Lambda>
@ -90,43 +94,47 @@ const lambda_wrap_empty<Return, Args...> lambda_wrap_empty<Return, Args...>::ins
template <typename Lambda, typename IsLarge, typename Return, typename ...Args> struct lambda_wrap_helper_move_impl;
template <typename Lambda, typename Return, typename ...Args>
struct lambda_wrap_helper_move_impl<Lambda, std_::true_type, Return, Args...> : public lambda_wrap_helper_base<Return, Args...> {
using JustLambda = std_::decay_simple_t<Lambda>;
using LambdaPtr = std_::unique_ptr<JustLambda>;
using Parent = lambda_wrap_helper_base<Return, Args...>;
static void construct_move_other_method(void *lambda, void *source) {
auto source_lambda = static_cast<LambdaPtr*>(source);
new (lambda) LambdaPtr(std_::move(*source_lambda));
}
static void construct_move_lambda_method(void *lambda, void *source) {
auto source_lambda = static_cast<JustLambda*>(source);
new (lambda) LambdaPtr(std_::make_unique<JustLambda>(static_cast<JustLambda&&>(*source_lambda)));
}
static Return call_method(const void *lambda, Args... args) {
return (**static_cast<const LambdaPtr*>(lambda))(std_::forward<Args>(args)...);
}
static void destruct_method(const void *lambda) {
static_cast<const LambdaPtr*>(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<struct>.
//
//template <typename Lambda, typename Return, typename ...Args>
//struct lambda_wrap_helper_move_impl<Lambda, std_::true_type, Return, Args...> : public lambda_wrap_helper_base<Return, Args...> {
// using JustLambda = std_::decay_simple_t<Lambda>;
// using LambdaPtr = std_::unique_ptr<JustLambda>;
// using Parent = lambda_wrap_helper_base<Return, Args...>;
// static void construct_move_other_method(void *lambda, void *source) {
// auto source_lambda = static_cast<LambdaPtr*>(source);
// new (lambda) LambdaPtr(std_::move(*source_lambda));
// }
// static void construct_move_lambda_method(void *lambda, void *source) {
// auto source_lambda = static_cast<JustLambda*>(source);
// new (lambda) LambdaPtr(std_::make_unique<JustLambda>(static_cast<JustLambda&&>(*source_lambda)));
// }
// static Return call_method(const void *lambda, Args... args) {
// return (**static_cast<const LambdaPtr*>(lambda))(std_::forward<Args>(args)...);
// }
// static void destruct_method(const void *lambda) {
// static_cast<const LambdaPtr*>(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 <typename Lambda, typename Return, typename ...Args>
struct lambda_wrap_helper_move_impl<Lambda, std_::false_type, Return, Args...> : public lambda_wrap_helper_base<Return, Args...> {
@ -137,6 +145,12 @@ struct lambda_wrap_helper_move_impl<Lambda, std_::false_type, Return, Args...> :
new (lambda) JustLambda(static_cast<JustLambda&&>(*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<JustLambda*>(source);
new (lambda) JustLambda(static_cast<JustLambda&&>(*source_lambda));
}
@ -177,23 +191,27 @@ const lambda_wrap_helper_move<Lambda, Return, Args...> lambda_wrap_helper_move<L
template <typename Lambda, typename IsLarge, typename Return, typename ...Args> struct lambda_wrap_helper_copy_impl;
template <typename Lambda, typename Return, typename ...Args>
struct lambda_wrap_helper_copy_impl<Lambda, std_::true_type, Return, Args...> : public lambda_wrap_helper_move_impl<Lambda, std_::true_type, Return, Args...> {
using JustLambda = std_::decay_simple_t<Lambda>;
using LambdaPtr = std_::unique_ptr<JustLambda>;
using Parent = lambda_wrap_helper_move_impl<Lambda, std_::true_type, Return, Args...>;
static void construct_copy_other_method(void *lambda, const void *source) {
auto source_lambda = static_cast<const LambdaPtr*>(source);
new (lambda) LambdaPtr(std_::make_unique<JustLambda>(*source_lambda->get()));
}
static void construct_copy_lambda_method(void *lambda, const void *source) {
auto source_lambda = static_cast<const JustLambda*>(source);
new (lambda) LambdaPtr(std_::make_unique<JustLambda>(static_cast<const JustLambda &>(*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<struct>.
//
//template <typename Lambda, typename Return, typename ...Args>
//struct lambda_wrap_helper_copy_impl<Lambda, std_::true_type, Return, Args...> : public lambda_wrap_helper_move_impl<Lambda, std_::true_type, Return, Args...> {
// using JustLambda = std_::decay_simple_t<Lambda>;
// using LambdaPtr = std_::unique_ptr<JustLambda>;
// using Parent = lambda_wrap_helper_move_impl<Lambda, std_::true_type, Return, Args...>;
// static void construct_copy_other_method(void *lambda, const void *source) {
// auto source_lambda = static_cast<const LambdaPtr*>(source);
// new (lambda) LambdaPtr(std_::make_unique<JustLambda>(*source_lambda->get()));
// }
// static void construct_copy_lambda_method(void *lambda, const void *source) {
// auto source_lambda = static_cast<const JustLambda*>(source);
// new (lambda) LambdaPtr(std_::make_unique<JustLambda>(static_cast<const JustLambda &>(*source_lambda)));
// }
// lambda_wrap_helper_copy_impl() : Parent(&lambda_wrap_helper_copy_impl::construct_copy_other_method) {
// }
//
//};
template <typename Lambda, typename Return, typename ...Args>
struct lambda_wrap_helper_copy_impl<Lambda, std_::false_type, Return, Args...> : public lambda_wrap_helper_move_impl<Lambda, std_::false_type, Return, Args...> {
@ -204,6 +222,12 @@ struct lambda_wrap_helper_copy_impl<Lambda, std_::false_type, Return, Args...> :
new (lambda) JustLambda(static_cast<const JustLambda &>(*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<const JustLambda*>(source);
new (lambda) JustLambda(static_cast<const JustLambda &>(*source_lambda));
}
@ -356,7 +380,7 @@ public:
auto temp = other;
this->helper_->destruct(this->storage_);
this->helper_ = &internal::lambda_wrap_helper_copy<Lambda, Return, Args...>::instance;
internal::lambda_wrap_helper_copy<Lambda, Return, Args...>::construct_move_lambda_method(this->storage_, &other);
internal::lambda_wrap_helper_copy<Lambda, Return, Args...>::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 <typename FunctionType>
struct LambdaFunctionHelper;
struct LambdaUniqueHelper;
template <typename Lambda, typename R, typename ...Args>
struct LambdaFunctionHelper<R(Lambda::*)(Args...) const> {
using FunctionType = Function<R, Args...>;
struct LambdaUniqueHelper<R(Lambda::*)(Args...) const> {
using UniqueType = base::lambda_unique<R(Args...)>;
};
template <typename FunctionType>
using LambdaGetFunction = typename LambdaFunctionHelper<FunctionType>::FunctionType;
template <typename FunctionType>
using LambdaGetUnique = typename LambdaFunctionHelper<FunctionType>::UniqueType;
template <typename R, typename ...Args>
class LambdaFunctionImplementation : public FunctionImplementation<R, Args...> {
public:
LambdaFunctionImplementation(base::lambda_unique<R(Args...)> &&lambda) : _lambda(std_::move(lambda)) {
}
R call(Args... args) override { return _lambda(std_::forward<Args>(args)...); }
private:
base::lambda_unique<R(Args...)> _lambda;
};
template <typename R, typename ...Args>
inline Function<R, Args...> func_lambda_wrap_helper(base::lambda_unique<R(Args...)> &&lambda) {
return Function<R, Args...>(new LambdaFunctionImplementation<R, Args...>(std_::move(lambda)));
}
template <typename Lambda, typename = std_::enable_if_t<std_::is_rvalue_reference<Lambda&&>::value>>
inline LambdaGetFunction<decltype(&Lambda::operator())> func(Lambda &&lambda) {
return func_lambda_wrap_helper(LambdaGetUnique<decltype(&Lambda::operator())>(std_::move(lambda)));
}
// While we still use rpcDone() and rpcFail()
#include "mtproto/rpc_sender.h"
using LambdaGetUnique = typename LambdaUniqueHelper<FunctionType>::UniqueType;
template <typename Base, typename FunctionType>
class RPCHandlerImplementation : public Base {

View File

@ -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<StartCallbackData>;
using FinishCallbacksList = QVector<FinishCallbackData>;
NeverFreedPointer<StartCallbacksList> StartCallbacks;
NeverFreedPointer<FinishCallbacksList> 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<internal::ObservedEvent>(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 {

View File

@ -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 <typename Flags, typename Handler>
struct ObserversList {
struct Entry {
Flags flags;
Handler handler;
};
std_::vector_of_moveable<Entry> entries;
QVector<int> 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 <typename Flags, typename Handler>
class ObservedEventRegistrator : public internal::BaseObservedEventRegistrator {
public:
ObservedEventRegistrator(StartObservedEventCallback startCallback,
FinishObservedEventCallback finishCallback) : internal::BaseObservedEventRegistrator(static_cast<void*>(this),
ObservedEventRegistrator<Flags, Handler>::start,
ObservedEventRegistrator<Flags, Handler>::finish,
ObservedEventRegistrator<Flags, Handler>::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>(handler));
return (static_cast<uint32>(event()) << 24) | static_cast<uint32>(connectionIndex + 1);
}
template <typename... Args>
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>(args)...);
}
}
}
private:
using Self = ObservedEventRegistrator<Flags, Handler>;
static void start(void *vthat) {
Self *that = static_cast<Self*>(vthat);
t_assert(!that->started());
if (that->_startCallback) that->_startCallback();
that->_list = new internal::ObserversList<Flags, Handler>();
}
static void finish(void *vthat) {
Self *that = static_cast<Self*>(vthat);
if (that->_finishCallback) that->_finishCallback();
delete that->_list;
that->_list = nullptr;
}
static void unregister(void *vthat, int connectionIndex) {
Self *that = static_cast<Self*>(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<Flags, Handler> *_list = nullptr;
};
// If no filtering of notifications by Flags is intended use this class.
template <typename Handler>
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>(handler));
}
template <typename... Args>
void notify(Args&&... args) {
return _implementation.notify(internal::UniversalFlag, std_::forward<Args>(args)...);
}
private:
ObservedEventRegistrator<int, Handler> _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<ConnectionId> _connections;
};
namespace internal {
template <typename ObserverType, int>
struct ObserverRegisteredGeneric {
static inline void call(ObserverType *observer, ConnectionId connection) {
observer->observerRegistered(connection);
}
};
template <typename ObserverType>
struct ObserverRegisteredGeneric<ObserverType, true> {
static inline void call(ObserverType *observer, ConnectionId connection) {
observerRegisteredDefault(observer, connection);
}
};
} // namespace internal
template <typename ObserverType>
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<ObserverType, std_::is_base_of<Observer, ObserverType>::value>;
ObserverRegistered::call(observer, connection);
}
} // namespace Notify
namespace base {
namespace internal {
@ -271,10 +47,10 @@ using SubscriptionHandler = typename SubscriptionHandlerHelper<EventType>::type;
class BaseObservableData {
};
template <typename EventType>
template <typename EventType, typename Handler>
class CommonObservableData;
template <typename EventType>
template <typename EventType, typename Handler>
class ObservableData;
} // namespace internal
@ -317,43 +93,41 @@ private:
Node *_node = nullptr;
RemoveMethod _removeMethod;
template <typename EventType>
template <typename EventType, typename Handler>
friend class internal::CommonObservableData;
template <typename EventType>
template <typename EventType, typename Handler>
friend class internal::ObservableData;
};
template <typename EventType>
template <typename EventType, typename Handler>
class Observable;
namespace internal {
template <typename EventType>
template <typename EventType, typename Handler>
class CommonObservable {
public:
using Handler = typename CommonObservableData<EventType>::Handler;
Subscription add_subscription(Handler &&handler) {
if (!_data) {
_data = MakeShared<ObservableData<EventType>>(this);
_data = MakeShared<ObservableData<EventType, Handler>>(this);
}
return _data->append(std_::forward<Handler>(handler));
}
private:
QSharedPointer<ObservableData<EventType>> _data;
QSharedPointer<ObservableData<EventType, Handler>> _data;
friend class CommonObservableData<EventType>;
friend class Observable<EventType>;
friend class CommonObservableData<EventType, Handler>;
friend class Observable<EventType, Handler>;
};
} // namespace internal
template <typename EventType>
class Observable : public internal::CommonObservable<EventType> {
template <typename EventType, typename Handler = internal::SubscriptionHandler<EventType>>
class Observable : public internal::CommonObservable<EventType, Handler> {
public:
void notify(EventType &&event, bool sync = false) {
if (this->_data) {
@ -368,12 +142,10 @@ public:
namespace internal {
template <typename EventType>
template <typename EventType, typename Handler>
class CommonObservableData : public BaseObservableData {
public:
using Handler = SubscriptionHandler<EventType>;
CommonObservableData(CommonObservable<EventType> *observable) : _observable(observable) {
CommonObservableData(CommonObservable<EventType, Handler> *observable) : _observable(observable) {
}
Subscription append(Handler &&handler) {
@ -444,20 +216,20 @@ private:
}
}
CommonObservable<EventType> *_observable = nullptr;
CommonObservable<EventType, Handler> *_observable = nullptr;
Node *_begin = nullptr;
Node *_current = nullptr;
Node *_end = nullptr;
ObservableCallHandlers _callHandlers;
friend class ObservableData<EventType>;
friend class ObservableData<EventType, Handler>;
};
template <typename EventType>
class ObservableData : public CommonObservableData<EventType> {
template <typename EventType, typename Handler>
class ObservableData : public CommonObservableData<EventType, Handler> {
public:
using CommonObservableData<EventType>::CommonObservableData;
using CommonObservableData<EventType, Handler>::CommonObservableData;
void notify(EventType &&event, bool sync) {
if (_handling) {
@ -501,10 +273,10 @@ private:
};
template <>
class ObservableData<void> : public CommonObservableData<void> {
template <class Handler>
class ObservableData<void, Handler> : public CommonObservableData<void, Handler> {
public:
using CommonObservableData<void>::CommonObservableData;
using CommonObservableData<void, Handler>::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<void> : public internal::CommonObservable<void> {
template <typename Handler>
class Observable<void, Handler> : public internal::CommonObservable<void, Handler> {
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 <typename EventType, typename Lambda>
int subscribe(base::Observable<EventType> &observable, Lambda &&handler) {
template <typename EventType, typename Handler, typename Lambda>
int subscribe(base::Observable<EventType, Handler> &observable, Lambda &&handler) {
_subscriptions.push_back(observable.add_subscription(std_::forward<Lambda>(handler)));
return _subscriptions.size() - 1;
}
template <typename EventType, typename Lambda>
int subscribe(base::Observable<EventType> *observable, Lambda &&handler) {
template <typename EventType, typename Handler, typename Lambda>
int subscribe(base::Observable<EventType, Handler> *observable, Lambda &&handler) {
return subscribe(*observable, std_::forward<Lambda>(handler));
}

View File

@ -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();
}

View File

@ -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";

View File

@ -46,13 +46,15 @@ DialogsInner::DialogsInner(QWidget *parent, MainWidget *main) : SplittedWidget(p
if (Global::DialogsModeEnabled()) {
importantDialogs = std_::make_unique<Dialogs::IndexedList>(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();
}

View File

@ -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:

View File

@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
class LayerWidget;
namespace base {
template <typename Type>
template <typename Type, typename>
class Observable;
} // namespace base
namespace InlineBots {

View File

@ -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<History*>(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<HistoryMessageReply>()) {
reply->replyToMsgId = config.replyTo;
if (!reply->updateData(this) && App::api()) {
App::api()->requestMessageData(history()->peer->asChannel(), reply->replyToMsgId, std_::make_unique<HistoryDependentItemCallback>(fullId()));
App::api()->requestMessageData(history()->peer->asChannel(), reply->replyToMsgId, historyDependentItemCallback(fullId()));
}
}
if (auto via = Get<HistoryMessageVia>()) {
@ -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<HistoryDependentItemCallback>(fullId()));
App::api()->requestMessageData(history()->peer->asChannel(), dependent->msgId, historyDependentItemCallback(fullId()));
}
}
}

View File

@ -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<void, ChannelData*, MsgId> {
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<HistoryMessageDate> {

View File

@ -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

View File

@ -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;

View File

@ -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<ReplyEditMessageDataCallback>());
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<ReplyEditMessageDataCallback>());
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;

View File

@ -908,11 +908,6 @@ private:
void destroyPinnedBar();
void unpinDone(const MTPUpdates &updates);
class ReplyEditMessageDataCallback : public SharedCallback<void, ChannelData*, MsgId> {
public:
void call(ChannelData *channel, MsgId msgId) const override;
};
bool sendExistingDocument(DocumentData *doc, const QString &caption);
void sendExistingPhoto(PhotoData *photo, const QString &caption);

View File

@ -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<Gif*>(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);

View File

@ -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<MediaPreviewWidget*>(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();
}
}

View File

@ -129,7 +129,7 @@ private:
};
class MediaPreviewWidget : public TWidget {
class MediaPreviewWidget : public TWidget, private base::Subscriber {
Q_OBJECT
public:

View File

@ -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<uint64, int32> 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<uint64, int> 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<uint64, int32>::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;

View File

@ -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);

View File

@ -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);

View File

@ -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()));

View File

@ -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;

View File

@ -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();

View File

@ -52,7 +52,7 @@ enum ReaderSteps {
class ReaderPrivate;
class Reader {
public:
using Callback = Function<void, Notification>;
using Callback = base::lambda_unique<void(Notification)>;
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<Reader*, MutableAtomicInt> ReaderPointers;
using ReaderPointers = QMap<Reader*, QAtomicInt>;
ReaderPointers _readerPointers;
mutable QReadWriteLock _readerPointersMutex;
mutable QMutex _readerPointersMutex;
ReaderPointers::const_iterator constUnsafeFindReaderPointer(ReaderPrivate *reader) const;
ReaderPointers::iterator unsafeFindReaderPointer(ReaderPrivate *reader);

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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();

View File

@ -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() {

View File

@ -41,8 +41,8 @@ Controller::Controller(QWidget *parent) : TWidget(parent)
, _toPlayLeft(this, st::mediaviewPlayProgressLabel)
, _fadeAnimation(std_::make_unique<Ui::FadeAnimation>(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());

View File

@ -55,6 +55,7 @@ void Playback::updateState(const AudioPlaybackState &playbackState) {
_position = position;
_duration = duration;
}
_slider->update();
}
} // namespace Clip

View File

@ -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

View File

@ -43,9 +43,6 @@ protected:
void leaveEvent(QEvent *e) override;
private:
void updateCallback() {
update();
}
void setOver(bool over);
void changeVolume(float64 newVolume);

View File

@ -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<Media::Clip::Reader>(_doc->location(), _doc->data(), func(this, &MediaView::clipCallback), mode);
_gif = std_::make_unique<Media::Clip::Reader>(_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<Media::Clip::Reader>(_doc->location(), _doc->data(), func(this, &MediaView::clipCallback), Media::Clip::Reader::Mode::Video, positionMs);
_gif = std_::make_unique<Media::Clip::Reader>(_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;

View File

@ -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);
}

View File

@ -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<ImageLoadedHandler> creator(nullptr, nullptr);
base::Observable<void> ImageLoadedObservable;
} // namespace
namespace internal {
Notify::ConnectionId plainRegisterImageLoadedObserver(ImageLoadedHandler &&handler) {
return creator.registerObserver(std_::forward<ImageLoadedHandler>(handler));
base::Observable<void> &ImageLoaded() {
return ImageLoadedObservable;
}
void notifyImageLoaded() {
creator.notify();
}
} // namespace internal
}
} // namespace FileDownload

View File

@ -396,19 +396,7 @@ void reinitWebLoadManager();
void stopWebLoadManager();
namespace FileDownload {
namespace internal {
using ImageLoadedHandler = Function<void>;
Notify::ConnectionId plainRegisterImageLoadedObserver(ImageLoadedHandler &&handler);
void notifyImageLoaded();
} // namespace internal
template <typename ObserverType>
void registerImageLoadedObserver(ObserverType *observer, void (ObserverType::*handler)()) {
auto connection = internal::plainRegisterImageLoadedObserver(func(observer, handler));
Notify::observerRegistered(observer, connection);
}
base::Observable<void> &ImageLoaded();
} // namespace FileDownload

View File

@ -31,8 +31,6 @@ void emitPeerUpdated();
namespace Notify {
namespace {
using internal::PeerUpdateHandler;
using SmallUpdatesList = QVector<PeerUpdate>;
NeverFreedPointer<SmallUpdatesList> SmallUpdates;
using AllUpdatesList = QMap<PeerData*, PeerUpdate>;
@ -46,19 +44,11 @@ void FinishCallback() {
SmallUpdates.clear();
AllUpdates.clear();
}
ObservedEventRegistrator<PeerUpdate::Flags, PeerUpdateHandler> creator(StartCallback, FinishCallback);
base::Observable<PeerUpdate, PeerUpdatedHandler> PeerUpdatedObservable;
} // namespace
namespace internal {
ConnectionId plainRegisterPeerObserver(PeerUpdate::Flags events, PeerUpdateHandler &&handler) {
constexpr auto tmp = sizeof(PeerUpdate);
return creator.registerObserver(events, std_::forward<PeerUpdateHandler>(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<PeerUpdate, PeerUpdatedHandler> &PeerUpdated() {
return PeerUpdatedObservable;
}
} // namespace Notify

View File

@ -89,17 +89,22 @@ inline void peerUpdatedDelayed(PeerData *peer, PeerUpdate::Flags events) {
}
void peerUpdatedSendDelayed();
namespace internal {
class PeerUpdatedHandler {
public:
template <typename Lambda>
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<void, const PeerUpdate&>;
ConnectionId plainRegisterPeerObserver(PeerUpdate::Flags events, PeerUpdateHandler &&handler);
private:
PeerUpdate::Flags _events;
base::lambda_unique<void(const PeerUpdate&)> _handler;
} // namespace internal
template <typename ObserverType>
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<PeerUpdate, PeerUpdatedHandler> &PeerUpdated();
} // namespace Notify

View File

@ -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);

View File

@ -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:

View File

@ -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();

View File

@ -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:

View File

@ -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();

View File

@ -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:

View File

@ -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

View File

@ -28,7 +28,7 @@ public:
void showAnimated();
using HideFinishCallback = Function<void, CoverDropArea*>;
using HideFinishCallback = base::lambda_unique<void(CoverDropArea*)>;
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;

View File

@ -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();
}

View File

@ -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:

View File

@ -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()) {

View File

@ -51,8 +51,6 @@ private:
void refreshChannelLink();
void refreshVisibility();
bool aboutClickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button);
// labelWidget may be nullptr.
void setLabeledText(ChildWidget<FlatLabel> *labelWidget, const QString &label,
ChildWidget<FlatLabel> *textWidget, const TextWithEntities &textWithEntities, const QString &copyText);

View File

@ -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

View File

@ -46,8 +46,6 @@ private:
void refreshLink();
void refreshVisibility();
bool clickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button);
ChildWidget<FlatLabel> _link = { nullptr };
};

View File

@ -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();
}

View File

@ -78,7 +78,6 @@ private slots:
private:
// Observed notifications.
void notifyPeerUpdated(const Notify::PeerUpdate &update);
void repaintCallback();
void preloadUserPhotos();

View File

@ -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();

View File

@ -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) {

View File

@ -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();
}

View File

@ -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();

View File

@ -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) {

View File

@ -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:

View File

@ -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<QImage>(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();

View File

@ -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();
}

View File

@ -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<LabeledWrap> &row, const QString &label, const TextWithEntities &textWithEntities, const TextWithEntities &shortTextWithEntities, const QString &copyText) {
if (textWithEntities.text.isEmpty()) {
row->slideUp();

View File

@ -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();

View File

@ -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();
}

View File

@ -65,6 +65,7 @@ private:
UserData *_self = nullptr;
int _contentLeft = 0;
bool _showFinished = false;
int _visibleTop = 0;
int _visibleBottom = 0;

View File

@ -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) {

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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 <QtCore/QTimer>
#include <QtGui/QColor>
@ -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 <typename AnimType>
class SimpleAnimation {
public:
using Callback = Function<void>;
using ValueType = typename AnimType::ValueType;
using Callback = base::lambda_unique<void()>;
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 <typename Lambda>
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<AnimType>::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<Data>(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> _data;
};
@ -486,18 +460,8 @@ using FloatAnimation = SimpleAnimation<anim::fvalue>;
using IntAnimation = SimpleAnimation<anim::ivalue>;
using ColorAnimation = SimpleAnimation<anim::cvalue>;
// 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<Animation*, NullType> AnimatingObjects;
using AnimatingObjects = OrderedSet<Animation*>;
AnimatingObjects _objects, _starting, _stopping;
QTimer _timer;
bool _iterating;

View File

@ -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() {

View File

@ -47,9 +47,6 @@ protected:
private:
void toggleAnimated();
void repaintCallback() {
update();
}
void step_arrowOver(float64 ms, bool timer);
QPixmap _cache;

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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();
}

View File

@ -31,10 +31,10 @@ public:
bool paint(Painter &p);
void refreshCache();
using FinishedCallback = Function<void>;
using FinishedCallback = base::lambda_unique<void()>;
void setFinishedCallback(FinishedCallback &&callback);
using UpdatedCallback = Function<void, float64>;
using UpdatedCallback = base::lambda_unique<void(float64)>;
void setUpdatedCallback(UpdatedCallback &&callback);
void show();

View File

@ -255,7 +255,7 @@ QString filedialogAllFilesFilter() {
namespace FileDialog {
namespace {
using internal::QueryUpdateHandler;
base::Observable<QueryUpdate> QueryDoneObservable;
struct Query {
enum class Type {
@ -285,16 +285,10 @@ void StartCallback() {
Queries.makeIfNull();
}
void FinishCallback() {
Queries.clear();
}
Notify::SimpleObservedEventRegistrator<QueryUpdateHandler> 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<QueryUpdateHandler>(handler));
base::Observable<QueryUpdate> &QueryDone() {
return QueryDoneObservable;
}
} // namespace internal
} // namespace FileDialog

View File

@ -63,17 +63,6 @@ QueryId queryReadFolder(const QString &caption);
// NB! This function enters an event loop.
bool processQuery();
namespace internal {
using QueryUpdateHandler = Function<void, const QueryUpdate&>;
Notify::ConnectionId plainRegisterObserver(QueryUpdateHandler &&handler);
} // namespace internal
template <typename ObserverType>
void registerObserver(ObserverType *observer, void (ObserverType::*handler)(const QueryUpdate &)) {
auto connection = internal::plainRegisterObserver(func(observer, handler));
Notify::observerRegistered(observer, connection);
}
base::Observable<QueryUpdate> &QueryDone();
} // namespace FileDialog

Some files were not shown because too many files have changed in this diff Show More