diff --git a/Telegram/SourceFiles/basic_types.h b/Telegram/SourceFiles/basic_types.h index 46057e3f0..c2038dee4 100644 --- a/Telegram/SourceFiles/basic_types.h +++ b/Telegram/SourceFiles/basic_types.h @@ -772,12 +772,12 @@ private: T *_p; }; -template +template inline UniquePointer MakeUnique(Args&&... args) { return UniquePointer(new T(std_::forward(args)...)); } -template +template inline QSharedPointer MakeShared(Args&&... args) { return QSharedPointer(new T(std_::forward(args)...)); } @@ -832,6 +832,13 @@ private: }; +template +using NeverFreedPointerCreator = T*(*)(); +template +inline NeverFreedPointerCreator MakeNeverFreedCreator(Args&&... args) { + return []() -> T* { return new T(std_::forward(args)...); }; +} + // This pointer is used for static non-POD variables that are allocated // on first use by constructor and are never automatically freed. template diff --git a/Telegram/SourceFiles/dropdown.cpp b/Telegram/SourceFiles/dropdown.cpp index 2da683b68..de1c3d9da 100644 --- a/Telegram/SourceFiles/dropdown.cpp +++ b/Telegram/SourceFiles/dropdown.cpp @@ -2172,7 +2172,9 @@ void StickerPanInner::refreshPanels(QVector &panels) { } void StickerPanInner::updateSelected() { - if (_pressedSel >= 0 && !_previewShown) return; + if (_pressedSel >= 0 && !_previewShown) { + return; + } int32 selIndex = -1; QPoint p(mapFromGlobal(_lastMousePos)); @@ -2229,8 +2231,10 @@ void StickerPanInner::updateSelected() { } if (_pressedSel >= 0 && _selected >= 0 && _pressedSel != _selected) { _pressedSel = _selected; - if (row >= 0 && col >= 0 && _inlineRows.at(row).items.at(col)->getDocument()) { - Ui::showStickerPreview(_inlineRows.at(row).items.at(col)->getDocument()); + if (row >= 0 && col >= 0) { + if (DocumentData *previewDocument = _inlineRows.at(row).items.at(col)->getPreviewDocument()) { + Ui::showStickerPreview(previewDocument); + } } } } @@ -2329,9 +2333,11 @@ void StickerPanInner::onPreview() { if (_pressedSel < 0) return; if (_showingInlineItems) { int32 row = _pressedSel / MatrixRowShift, col = _pressedSel % MatrixRowShift; - if (row < _inlineRows.size() && col < _inlineRows.at(row).items.size() && _inlineRows.at(row).items.at(col)->getDocument() && _inlineRows.at(row).items.at(col)->getDocument()->loaded()) { - Ui::showStickerPreview(_inlineRows.at(row).items.at(col)->getDocument()); - _previewShown = true; + if (row < _inlineRows.size() && col < _inlineRows.at(row).items.size()) { + if (DocumentData *previewDocument = _inlineRows.at(row).items.at(col)->getPreviewDocument()) { + Ui::showStickerPreview(previewDocument); + _previewShown = true; + } } } else if (_pressedSel < MatrixRowShift * _sets.size()) { int tab = (_pressedSel / MatrixRowShift), sel = _pressedSel % MatrixRowShift; diff --git a/Telegram/SourceFiles/gui/text.cpp b/Telegram/SourceFiles/gui/text.cpp index 482ad7a2d..c1b14ec0f 100644 --- a/Telegram/SourceFiles/gui/text.cpp +++ b/Telegram/SourceFiles/gui/text.cpp @@ -61,8 +61,8 @@ ClickHandlerHost::~ClickHandlerHost() { ClickHandler::hostDestroyed(this); } -ClickHandlerPtr *ClickHandler::_active = nullptr; -ClickHandlerPtr *ClickHandler::_pressed = nullptr; +NeverFreedPointer ClickHandler::_active; +NeverFreedPointer ClickHandler::_pressed; ClickHandlerHost *ClickHandler::_activeHost = nullptr; ClickHandlerHost *ClickHandler::_pressedHost = nullptr; @@ -86,9 +86,7 @@ bool ClickHandler::setActive(const ClickHandlerPtr &p, ClickHandlerHost *host) { } } if (p) { - if (!_active) { - _active = new ClickHandlerPtr(); // won't be deleted - } + _active.createIfNull(MakeNeverFreedCreator()); *_active = p; if ((_activeHost = host)) { bool emitClickHandlerActiveChanged = (!_pressed || !*_pressed || *_pressed == *_active); diff --git a/Telegram/SourceFiles/gui/text.h b/Telegram/SourceFiles/gui/text.h index 684774740..08301e1b6 100644 --- a/Telegram/SourceFiles/gui/text.h +++ b/Telegram/SourceFiles/gui/text.h @@ -366,9 +366,7 @@ public: if (!_active || !*_active) { return; } - if (!_pressed) { - _pressed = new ClickHandlerPtr(); // won't be deleted - } + _pressed.createIfNull(MakeNeverFreedCreator()); *_pressed = *_active; if ((_pressedHost = _activeHost)) { _pressedHost->clickHandlerPressedChanged(*_pressed, true); @@ -428,8 +426,8 @@ public: private: - static ClickHandlerPtr *_active; - static ClickHandlerPtr *_pressed; + static NeverFreedPointer _active; + static NeverFreedPointer _pressed; static ClickHandlerHost *_activeHost; static ClickHandlerHost *_pressedHost; diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index a00ac63b0..ef6fcdba1 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -2740,36 +2740,57 @@ void HistoryBlock::removeItem(HistoryItem *item) { } } -void ReplyMarkupClickHandler::onClickImpl() const { - const HistoryItem *item = nullptr; - const HistoryMessageReplyMarkup::Button *button = nullptr; - if (getItemAndButton(&item, &button)) { - App::activateBotCommand(item->history()->peer, *button, _msgId.msg); +class ReplyMarkupClickHandler : public LeftButtonClickHandler { +public: + ReplyMarkupClickHandler(const HistoryItem *item, int row, int col) : _item(item), _row(row), _col(col) { } -} -// We need to make sure the item still exists, so we get it by id. -// After that we check if the reply markup is still there and that -// there are enough button rows and buttons in the row. -// Note: it is possible that we will point to the different button -// than the one was used when constructing the handler, but not a big deal. -bool ReplyMarkupClickHandler::getItemAndButton( - const HistoryItem **outItem, - const HistoryMessageReplyMarkup::Button **outButton) const { - if (HistoryItem *item = App::histItemById(_msgId)) { - if (auto *markup = item->Get()) { + QString tooltip() const override { + return _fullDisplayed ? QString() : text(); + } + + void setFullDisplayed(bool full) { + _fullDisplayed = full; + } + +protected: + void onClickImpl() const override { + if (auto button = getButton()) { + MsgId replyTo = (_item->id > 0) ? _item->id : 0; + App::activateBotCommand(_item->history()->peer, *button, replyTo); + } + } + +private: + const HistoryItem *_item = nullptr; + int _row, _col; + bool _fullDisplayed = true; + + // Finds the corresponding button in the items markup struct. + // If the button is not found it returns nullptr. + // Note: it is possible that we will point to the different button + // than the one was used when constructing the handler, but not a big deal. + const HistoryMessageReplyMarkup::Button *getButton() const { + if (auto *markup = _item->Get()) { if (_row < markup->rows.size()) { const HistoryMessageReplyMarkup::ButtonRow &row(markup->rows.at(_row)); if (_col < row.size()) { - if (outItem) *outItem = item; - if (outButton) *outButton = &row.at(_col); - return true; + return &row.at(_col); } } } + return nullptr; } - return false; -} + + // Returns the full text of the corresponding button. + QString text() const { + if (auto button = getButton()) { + return button->text; + } + return QString(); + } + +}; ReplyKeyboard::ReplyKeyboard(const HistoryItem *item, StylePtr &&s) : _item(item) @@ -2785,7 +2806,7 @@ ReplyKeyboard::ReplyKeyboard(const HistoryItem *item, StylePtr &&s) Button &button(newRow[j]); QString str = row.at(j).text; button.type = row.at(j).type; - button.link.reset(new ReplyMarkupClickHandler(item->fullId(), i, j)); + button.link.reset(new ReplyMarkupClickHandler(item, i, j)); button.text.setText(_st->textFont(), textOneLine(str), _textPlainOptions); button.characters = str.isEmpty() ? 1 : str.size(); } diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index c90fcc9f3..9cf6db042 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -1121,45 +1121,7 @@ private: }; -class ReplyMarkupClickHandler : public LeftButtonClickHandler { -public: - ReplyMarkupClickHandler(const FullMsgId &msgId, int row, int col) : _msgId(msgId), _row(row), _col(col) { - } - - QString tooltip() const override { - return _fullDisplayed ? QString() : text(); - } - - void setFullDisplayed(bool full) { - _fullDisplayed = full; - } - -protected: - void onClickImpl() const override; - -private: - FullMsgId _msgId; - int _row, _col; - bool _fullDisplayed = true; - - // Finds the corresponding item and button in the items markup struct. - // If the item or the button is not found it returns false. - // Any of the two output arguments can be nullptr if its value is not needed. - bool getItemAndButton( - const HistoryItem **outItem, - const HistoryMessageReplyMarkup::Button **outButtonPointer) const; - - // Returns the full text of the corresponding button. - QString text() const { - const HistoryMessageReplyMarkup::Button *button = nullptr; - if (getItemAndButton(nullptr, &button)) { - return button->text; - } - return QString(); - } - -}; - +class ReplyMarkupClickHandler; class ReplyKeyboard { private: struct Button; diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp index 25047919a..d2693cb7f 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp @@ -49,6 +49,24 @@ PhotoData *ItemBase::getPhoto() const { return _photo; } +DocumentData *ItemBase::getPreviewDocument() const { + auto previewDocument = [this]() -> DocumentData* { + if (_doc) { + return _doc; + } + if (_result) { + return _result->_document; + } + return nullptr; + }; + if (DocumentData *result = previewDocument()) { + if (result->sticker() || result->loaded()) { + return result; + } + } + return nullptr; +} + void ItemBase::preload() const { if (_result) { if (_result->_photo) { diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h index 6ee18f3bf..b0b2b5a85 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h @@ -73,6 +73,10 @@ public: DocumentData *getDocument() const; PhotoData *getPhoto() const; + // Get document (possibly from InlineBots::Result) for + // showing sticker or GIF preview. + DocumentData *getPreviewDocument() const; + virtual void preload() const; void update(); diff --git a/Telegram/SourceFiles/mtproto/generate.py b/Telegram/SourceFiles/mtproto/generate.py index 85b571407..e93d8e5d3 100644 --- a/Telegram/SourceFiles/mtproto/generate.py +++ b/Telegram/SourceFiles/mtproto/generate.py @@ -217,7 +217,7 @@ with open('scheme.tl') as f: if funcsNow: if (isTemplate != ''): - funcsText += '\ntemplate '; + funcsText += '\ntemplate '; funcsText += '\nclass MTP' + name + ' { // RPC method \'' + nametype.group(1) + '\'\n'; # class funcsText += 'public:\n'; diff --git a/Telegram/SourceFiles/mtproto/scheme_auto.h b/Telegram/SourceFiles/mtproto/scheme_auto.h index 9adda8e04..a22e9a8dc 100644 --- a/Telegram/SourceFiles/mtproto/scheme_auto.h +++ b/Telegram/SourceFiles/mtproto/scheme_auto.h @@ -14423,7 +14423,7 @@ public: } }; -template +template class MTPinvokeAfterMsg { // RPC method 'invokeAfterMsg' public: MTPlong vmsg_id; @@ -14465,7 +14465,7 @@ public: } }; -template +template class MTPinvokeAfterMsgs { // RPC method 'invokeAfterMsgs' public: MTPVector vmsg_ids; @@ -14507,7 +14507,7 @@ public: } }; -template +template class MTPinitConnection { // RPC method 'initConnection' public: MTPint vapi_id; @@ -14561,7 +14561,7 @@ public: } }; -template +template class MTPinvokeWithLayer { // RPC method 'invokeWithLayer' public: MTPint vlayer; @@ -14603,7 +14603,7 @@ public: } }; -template +template class MTPinvokeWithoutUpdates { // RPC method 'invokeWithoutUpdates' public: TQueryType vquery;