Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
744eccc51e | ||
|
|
ce49714533 | ||
|
|
ae2c858dc9 | ||
|
|
f0b5dc42f9 | ||
|
|
9c213bf1c0 | ||
|
|
0c1175f9cd | ||
|
|
0c1312419a | ||
|
|
7e9695b213 | ||
|
|
093fcc3821 | ||
|
|
6f89598a7b | ||
|
|
6ccd53689d | ||
|
|
cd506dfff5 | ||
|
|
5a3733b5b6 | ||
|
|
22a85016e3 | ||
|
|
26c7a95a9f | ||
|
|
9acf617c9f | ||
|
|
72af170484 | ||
|
|
4db2505f5d | ||
|
|
4d40336be0 | ||
|
|
616531b0d0 | ||
|
|
473803edb8 | ||
|
|
a33ca97298 | ||
|
|
a711c89409 | ||
|
|
24ec0e0866 | ||
|
|
e6df927e30 | ||
|
|
638ea3111f | ||
|
|
983d9e6eee | ||
|
|
4b6d74dd9b | ||
|
|
8d70a62ee8 | ||
|
|
a0af748fc5 | ||
|
|
f10ef26226 | ||
|
|
4ebc62afd2 | ||
|
|
18cb26fed6 | ||
|
|
d965385356 | ||
|
|
5cc4066b65 | ||
|
|
6b084301be | ||
|
|
498e82b804 | ||
|
|
8c224f7aca |
@@ -9,7 +9,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="2.4.1.0" />
|
||||
Version="2.4.3.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram FZ-LLC</PublisherDisplayName>
|
||||
|
||||
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,4,1,0
|
||||
PRODUCTVERSION 2,4,1,0
|
||||
FILEVERSION 2,4,3,0
|
||||
PRODUCTVERSION 2,4,3,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -62,10 +62,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "2.4.1.0"
|
||||
VALUE "FileVersion", "2.4.3.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2020"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "2.4.1.0"
|
||||
VALUE "ProductVersion", "2.4.3.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,4,1,0
|
||||
PRODUCTVERSION 2,4,1,0
|
||||
FILEVERSION 2,4,3,0
|
||||
PRODUCTVERSION 2,4,3,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -53,10 +53,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop Updater"
|
||||
VALUE "FileVersion", "2.4.1.0"
|
||||
VALUE "FileVersion", "2.4.3.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2020"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "2.4.1.0"
|
||||
VALUE "ProductVersion", "2.4.3.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -310,7 +310,7 @@ QString AllFilesFilter() {
|
||||
}
|
||||
|
||||
QString AlbumFilesFilter() {
|
||||
return qsl("Image and Video Files (*.png *.jpg *.mp4 *.jpeg)");
|
||||
return qsl("Image and Video Files (*.png *.jpg *.jpeg *.mp4 *.mov)");
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
@@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs;
|
||||
constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs;
|
||||
constexpr auto AppName = "Telegram Desktop"_cs;
|
||||
constexpr auto AppFile = "Telegram"_cs;
|
||||
constexpr auto AppVersion = 2004001;
|
||||
constexpr auto AppVersionStr = "2.4.1";
|
||||
constexpr auto AppVersion = 2004003;
|
||||
constexpr auto AppVersionStr = "2.4.3";
|
||||
constexpr auto AppBetaVersion = false;
|
||||
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
|
||||
|
||||
@@ -1676,7 +1676,7 @@ mde mdt mdw mdz mht mhtml mjs mmc mof msc msg msh msh1 msh2 msh1xml msh2xml \
|
||||
mshxml msi msp mst ops osd paf pcd phar php php3 php4 php5 php7 phps php-s \
|
||||
pht phtml pif pl plg pm pod prf prg ps1 ps2 ps1xml ps2xml psc1 psc2 psd1 \
|
||||
psm1 pssc pst py py3 pyc pyd pyi pyo pyw pywz pyz rb reg rgs scf scr sct \
|
||||
search-ms settingcontent-ms shb shs slk sys t tmp u3p url vb vbe vbp vbs \
|
||||
search-ms settingcontent-ms sh shb shs slk sys t tmp u3p url vb vbe vbp vbs \
|
||||
vbscript vdx vsmacros vsd vsdm vsdx vss vssm vssx vst vstm vstx vsw vsx vtx \
|
||||
website ws wsc wsf wsh xbap xll xnk xs");
|
||||
#endif // !Q_OS_MAC && !Q_OS_UNIX
|
||||
|
||||
@@ -479,9 +479,15 @@ void MessagesSliceBuilder::requestMessagesCount() {
|
||||
MessagesSlice MessagesSliceBuilder::snapshot() const {
|
||||
auto result = MessagesSlice();
|
||||
result.ids.reserve(_ids.size());
|
||||
auto nearestToAround = std::optional<FullMsgId>();
|
||||
for (const auto &position : _ids) {
|
||||
result.ids.push_back(position.fullId);
|
||||
if (!nearestToAround && position >= _key) {
|
||||
nearestToAround = position.fullId;
|
||||
}
|
||||
}
|
||||
result.nearestToAround = nearestToAround.value_or(
|
||||
_ids.empty() ? FullMsgId() : _ids.back().fullId);
|
||||
result.skippedBefore = _skippedBefore;
|
||||
result.skippedAfter = _skippedAfter;
|
||||
result.fullCount = _fullCount;
|
||||
|
||||
@@ -93,10 +93,10 @@ constexpr auto UnreadMessagePosition = MessagePosition(
|
||||
|
||||
struct MessagesSlice {
|
||||
std::vector<FullMsgId> ids;
|
||||
FullMsgId nearestToAround;
|
||||
std::optional<int> skippedBefore;
|
||||
std::optional<int> skippedAfter;
|
||||
std::optional<int> fullCount;
|
||||
|
||||
};
|
||||
|
||||
struct MessagesQuery {
|
||||
@@ -112,7 +112,6 @@ struct MessagesQuery {
|
||||
MessagePosition aroundId;
|
||||
int limitBefore = 0;
|
||||
int limitAfter = 0;
|
||||
|
||||
};
|
||||
|
||||
struct MessagesResult {
|
||||
|
||||
@@ -227,6 +227,7 @@ void RepliesList::injectRootDivider(
|
||||
bool RepliesList::buildFromData(not_null<Viewer*> viewer) {
|
||||
if (_list.empty() && _skippedBefore == 0 && _skippedAfter == 0) {
|
||||
viewer->slice.ids.clear();
|
||||
viewer->slice.nearestToAround = FullMsgId();
|
||||
viewer->slice.fullCount
|
||||
= viewer->slice.skippedBefore
|
||||
= viewer->slice.skippedAfter
|
||||
@@ -268,10 +269,20 @@ bool RepliesList::buildFromData(not_null<Viewer*> viewer) {
|
||||
|
||||
const auto channelId = _history->channelId();
|
||||
slice->ids.clear();
|
||||
auto nearestToAround = std::optional<MsgId>();
|
||||
slice->ids.reserve(useAfter + useBefore);
|
||||
for (auto j = i - useAfter, e = i + useBefore; j != e; ++j) {
|
||||
if (!nearestToAround && *j < around) {
|
||||
nearestToAround = (j == i - useAfter)
|
||||
? *j
|
||||
: *(j - 1);
|
||||
}
|
||||
slice->ids.emplace_back(channelId, *j);
|
||||
}
|
||||
slice->nearestToAround = FullMsgId(
|
||||
channelId,
|
||||
nearestToAround.value_or(
|
||||
slice->ids.empty() ? 0 : slice->ids.back().msg));
|
||||
slice->fullCount = _fullCount.current();
|
||||
|
||||
injectRootMessageAndReverse(slice);
|
||||
@@ -530,6 +541,8 @@ bool RepliesList::processMessagesIsEmpty(const MTPmessages_Messages &result) {
|
||||
} else {
|
||||
_list.push_back(item->id);
|
||||
}
|
||||
} else {
|
||||
++skipped;
|
||||
}
|
||||
} else {
|
||||
++skipped;
|
||||
@@ -580,7 +593,8 @@ bool RepliesList::processMessagesIsEmpty(const MTPmessages_Messages &result) {
|
||||
}
|
||||
}
|
||||
|
||||
return (list.size() > skipped);
|
||||
Ensures(list.size() >= skipped);
|
||||
return (list.size() == skipped);
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
|
||||
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "data/data_scheduled_messages.h"
|
||||
|
||||
#include "base/unixtime.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_session.h"
|
||||
#include "api/api_hash.h"
|
||||
@@ -26,6 +27,11 @@ constexpr auto kRequestTimeLimit = 60 * crl::time(1000);
|
||||
return (received > 0) && (received + kRequestTimeLimit > crl::now());
|
||||
}
|
||||
|
||||
[[nodiscard]] bool HasScheduledDate(not_null<HistoryItem*> item) {
|
||||
return (item->date() != ScheduledMessages::kScheduledUntilOnlineTimestamp)
|
||||
&& (item->date() > base::unixtime::now());
|
||||
}
|
||||
|
||||
MTPMessage PrepareMessage(const MTPMessage &message, MsgId id) {
|
||||
return message.match([&](const MTPDmessageEmpty &) {
|
||||
return MTP_messageEmpty(MTP_int(id));
|
||||
@@ -147,7 +153,11 @@ void ScheduledMessages::sendNowSimpleMessage(
|
||||
not_null<HistoryItem*> local) {
|
||||
Expects(local->isSending());
|
||||
Expects(local->isScheduled());
|
||||
Expects(local->date() == kScheduledUntilOnlineTimestamp);
|
||||
if (HasScheduledDate(local)) {
|
||||
LOG(("Error: trying to put to history a new local message, "
|
||||
"that has scheduled date."));
|
||||
return;
|
||||
}
|
||||
|
||||
// When the user sends a text message scheduled until online
|
||||
// while the recipient is already online, the server sends
|
||||
@@ -243,16 +253,18 @@ void ScheduledMessages::checkEntitiesAndUpdate(const MTPDmessage &data) {
|
||||
}
|
||||
|
||||
const auto existing = j->second;
|
||||
Assert(existing->date() == kScheduledUntilOnlineTimestamp);
|
||||
existing->updateSentContent({
|
||||
qs(data.vmessage()),
|
||||
Api::EntitiesFromMTP(_session, data.ventities().value_or_empty())
|
||||
}, data.vmedia());
|
||||
existing->updateReplyMarkup(data.vreply_markup());
|
||||
existing->updateForwardedInfo(data.vfwd_from());
|
||||
_session->data().requestItemTextRefresh(existing);
|
||||
if (!HasScheduledDate(existing)) {
|
||||
// Destroy a local message, that should be in history.
|
||||
existing->updateSentContent({
|
||||
qs(data.vmessage()),
|
||||
Api::EntitiesFromMTP(_session, data.ventities().value_or_empty())
|
||||
}, data.vmedia());
|
||||
existing->updateReplyMarkup(data.vreply_markup());
|
||||
existing->updateForwardedInfo(data.vfwd_from());
|
||||
_session->data().requestItemTextRefresh(existing);
|
||||
|
||||
existing->destroy();
|
||||
existing->destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void ScheduledMessages::apply(
|
||||
|
||||
@@ -1775,6 +1775,7 @@ bool Session::checkEntitiesAndViewsUpdate(const MTPDmessage &data) {
|
||||
data.vreply_to_msg_id().v));
|
||||
});
|
||||
}
|
||||
existing->setPostAuthor(data.vpost_author().value_or_empty());
|
||||
existing->indexAsNewItem();
|
||||
existing->contributeToSlowmode(data.vdate().v);
|
||||
requestItemTextRefresh(existing);
|
||||
|
||||
@@ -191,8 +191,7 @@ TimeId HistoryItem::date() const {
|
||||
}
|
||||
|
||||
TimeId HistoryItem::NewMessageDate(TimeId scheduled) {
|
||||
const auto now = base::unixtime::now();
|
||||
return scheduled ? std::max(scheduled, now + 60) : now;
|
||||
return scheduled ? scheduled : base::unixtime::now();
|
||||
}
|
||||
|
||||
void HistoryItem::finishEdition(int oldKeyboardTop) {
|
||||
@@ -637,7 +636,7 @@ bool HistoryItem::suggestBanReport() const {
|
||||
if (!channel || !fromUser || !channel->canRestrictUser(fromUser)) {
|
||||
return false;
|
||||
}
|
||||
return !isPost() && !out() && toHistoryMessage();
|
||||
return !isPost() && !out();
|
||||
}
|
||||
|
||||
bool HistoryItem::suggestDeleteAllReport() const {
|
||||
@@ -645,7 +644,7 @@ bool HistoryItem::suggestDeleteAllReport() const {
|
||||
if (!channel || !channel->canDeleteMessages()) {
|
||||
return false;
|
||||
}
|
||||
return !isPost() && !out() && from()->isUser() && toHistoryMessage();
|
||||
return !isPost() && !out() && from()->isUser();
|
||||
}
|
||||
|
||||
bool HistoryItem::hasDirectLink() const {
|
||||
|
||||
@@ -293,6 +293,8 @@ public:
|
||||
}
|
||||
virtual void setReplyToTop(MsgId replyToTop) {
|
||||
}
|
||||
virtual void setPostAuthor(const QString &author) {
|
||||
}
|
||||
virtual void setRealId(MsgId newId);
|
||||
virtual void incrementReplyToTopCounter() {
|
||||
}
|
||||
|
||||
@@ -374,18 +374,22 @@ MTPDmessage::Flags NewMessageFlags(not_null<PeerData*> peer) {
|
||||
return result;
|
||||
}
|
||||
|
||||
MsgId LookupReplyToTop(not_null<History*> history, MsgId replyToId) {
|
||||
const auto &owner = history->owner();
|
||||
if (const auto item = owner.message(history->channelId(), replyToId)) {
|
||||
return item->replyToTop();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MTPMessageReplyHeader NewMessageReplyHeader(const Api::SendAction &action) {
|
||||
if (const auto id = action.replyTo) {
|
||||
const auto history = action.history;
|
||||
const auto &owner = history->owner();
|
||||
if (const auto item = owner.message(history->channelId(), id)) {
|
||||
if (item->replyToId()) {
|
||||
return MTP_messageReplyHeader(
|
||||
MTP_flags(MTPDmessageReplyHeader::Flag::f_reply_to_top_id),
|
||||
MTP_int(id),
|
||||
MTPPeer(),
|
||||
MTP_int(item->replyToTop()));
|
||||
}
|
||||
if (const auto replyToTop = LookupReplyToTop(action.history, id)) {
|
||||
return MTP_messageReplyHeader(
|
||||
MTP_flags(MTPDmessageReplyHeader::Flag::f_reply_to_top_id),
|
||||
MTP_int(id),
|
||||
MTPPeer(),
|
||||
MTP_int(replyToTop));
|
||||
}
|
||||
return MTP_messageReplyHeader(
|
||||
MTP_flags(0),
|
||||
@@ -741,7 +745,9 @@ void HistoryMessage::createComponentsHelper(
|
||||
|
||||
if (flags & MTPDmessage::Flag::f_via_bot_id) config.viaBotId = viaBotId;
|
||||
if (flags & MTPDmessage::Flag::f_reply_to) {
|
||||
config.replyToTop = config.replyTo = replyTo;
|
||||
config.replyTo = replyTo;
|
||||
const auto replyToTop = LookupReplyToTop(history(), replyTo);
|
||||
config.replyToTop = replyToTop ? replyToTop : replyTo;
|
||||
}
|
||||
if (flags & MTPDmessage::Flag::f_reply_markup) config.mtpMarkup = &markup;
|
||||
if (flags & MTPDmessage::Flag::f_post_author) config.author = postAuthor;
|
||||
@@ -988,6 +994,14 @@ void HistoryMessage::createComponents(const CreateConfig &config) {
|
||||
}
|
||||
if (!config.author.isEmpty()) {
|
||||
mask |= HistoryMessageSigned::Bit();
|
||||
} else if (_history->peer->isMegagroup() // Discussion posts signatures.
|
||||
&& config.savedFromPeer
|
||||
&& !config.authorOriginal.isEmpty()) {
|
||||
const auto savedFrom = _history->owner().peerLoaded(
|
||||
config.savedFromPeer);
|
||||
if (savedFrom && savedFrom->isChannel()) {
|
||||
mask |= HistoryMessageSigned::Bit();
|
||||
}
|
||||
}
|
||||
if (config.editDate != TimeId(0)) {
|
||||
mask |= HistoryMessageEdited::Bit();
|
||||
@@ -1048,8 +1062,11 @@ void HistoryMessage::createComponents(const CreateConfig &config) {
|
||||
edited->date = config.editDate;
|
||||
}
|
||||
if (const auto msgsigned = Get<HistoryMessageSigned>()) {
|
||||
msgsigned->author = config.author;
|
||||
msgsigned->isAnonymousRank = author()->isMegagroup();
|
||||
msgsigned->author = config.author.isEmpty()
|
||||
? config.authorOriginal
|
||||
: config.author;
|
||||
msgsigned->isAnonymousRank = !isDiscussionPost()
|
||||
&& author()->isMegagroup();
|
||||
}
|
||||
setupForwardedComponent(config);
|
||||
if (const auto markup = Get<HistoryMessageReplyMarkup>()) {
|
||||
@@ -1299,6 +1316,11 @@ void HistoryMessage::applyEdition(const MTPDmessage &message) {
|
||||
setViewsCount(message.vviews().value_or(-1));
|
||||
setForwardsCount(message.vforwards().value_or(-1));
|
||||
setText(_media ? textWithEntities : EnsureNonEmpty(textWithEntities));
|
||||
if (const auto replies = message.vreplies()) {
|
||||
setReplies(*replies);
|
||||
} else {
|
||||
clearReplies();
|
||||
}
|
||||
|
||||
finishEdition(keyboardTop);
|
||||
}
|
||||
@@ -1585,6 +1607,28 @@ void HistoryMessage::setViewsCount(int count) {
|
||||
void HistoryMessage::setForwardsCount(int count) {
|
||||
}
|
||||
|
||||
void HistoryMessage::setPostAuthor(const QString &author) {
|
||||
auto msgsigned = Get<HistoryMessageSigned>();
|
||||
if (author.isEmpty()) {
|
||||
if (!msgsigned) {
|
||||
return;
|
||||
}
|
||||
RemoveComponents(HistoryMessageSigned::Bit());
|
||||
history()->owner().requestItemResize(this);
|
||||
return;
|
||||
}
|
||||
if (!msgsigned) {
|
||||
AddComponents(HistoryMessageSigned::Bit());
|
||||
msgsigned = Get<HistoryMessageSigned>();
|
||||
} else if (msgsigned->author == author) {
|
||||
return;
|
||||
}
|
||||
msgsigned->author = author;
|
||||
msgsigned->isAnonymousRank = !isDiscussionPost()
|
||||
&& this->author()->isMegagroup();
|
||||
history()->owner().requestItemResize(this);
|
||||
}
|
||||
|
||||
void HistoryMessage::setReplies(const MTPMessageReplies &data) {
|
||||
data.match([&](const MTPDmessageReplies &data) {
|
||||
auto views = Get<HistoryMessageViews>();
|
||||
|
||||
@@ -21,16 +21,20 @@ struct HistoryMessageEdited;
|
||||
struct HistoryMessageReply;
|
||||
struct HistoryMessageViews;
|
||||
|
||||
Fn<void(ChannelData*, MsgId)> HistoryDependentItemCallback(
|
||||
[[nodiscard]] Fn<void(ChannelData*, MsgId)> HistoryDependentItemCallback(
|
||||
not_null<HistoryItem*> item);
|
||||
MTPDmessage::Flags NewMessageFlags(not_null<PeerData*> peer);
|
||||
MTPDmessage_ClientFlags NewMessageClientFlags();
|
||||
MTPMessageReplyHeader NewMessageReplyHeader(const Api::SendAction &action);
|
||||
QString GetErrorTextForSending(
|
||||
[[nodiscard]] MTPDmessage::Flags NewMessageFlags(not_null<PeerData*> peer);
|
||||
[[nodiscard]] MTPDmessage_ClientFlags NewMessageClientFlags();
|
||||
[[nodiscard]] MsgId LookupReplyToTop(
|
||||
not_null<History*> history,
|
||||
MsgId replyToId);
|
||||
[[nodiscard]] MTPMessageReplyHeader NewMessageReplyHeader(
|
||||
const Api::SendAction &action);
|
||||
[[nodiscard]] QString GetErrorTextForSending(
|
||||
not_null<PeerData*> peer,
|
||||
const HistoryItemsList &items,
|
||||
bool ignoreSlowmodeCountdown = false);
|
||||
QString GetErrorTextForSending(
|
||||
[[nodiscard]] QString GetErrorTextForSending(
|
||||
not_null<PeerData*> peer,
|
||||
const HistoryItemsList &items,
|
||||
const TextWithTags &comment,
|
||||
@@ -129,6 +133,7 @@ public:
|
||||
void clearReplies() override;
|
||||
void changeRepliesCount(int delta, PeerId replier) override;
|
||||
void setReplyToTop(MsgId replyToTop) override;
|
||||
void setPostAuthor(const QString &author) override;
|
||||
void setRealId(MsgId newId) override;
|
||||
void incrementReplyToTopCounter() override;
|
||||
|
||||
|
||||
@@ -1942,6 +1942,7 @@ void HistoryWidget::updateNotifyControls() {
|
||||
if (!session().data().notifySilentPostsUnknown(_peer)) {
|
||||
if (_silent) {
|
||||
_silent->setChecked(session().data().notifySilentPosts(_peer));
|
||||
updateFieldPlaceholder();
|
||||
} else if (hasSilentToggle()) {
|
||||
refreshSilentToggle();
|
||||
updateControlsVisibility();
|
||||
@@ -3132,10 +3133,6 @@ void HistoryWidget::toggleMuteUnmute() {
|
||||
session().data().updateNotifySettings(_peer, muteForSeconds);
|
||||
}
|
||||
|
||||
void HistoryWidget::onBroadcastSilentChange() {
|
||||
updateFieldPlaceholder();
|
||||
}
|
||||
|
||||
History *HistoryWidget::history() const {
|
||||
return _history;
|
||||
}
|
||||
|
||||
@@ -294,8 +294,6 @@ signals:
|
||||
public slots:
|
||||
void onScroll();
|
||||
|
||||
void onBroadcastSilentChange();
|
||||
|
||||
void activate();
|
||||
void onTextChange();
|
||||
|
||||
|
||||
@@ -130,6 +130,8 @@ private:
|
||||
const not_null<Data::Session*> _data;
|
||||
const not_null<Ui::IconButton*> _cancel;
|
||||
|
||||
QRect _clickableRect;
|
||||
|
||||
rpl::event_stream<bool> _visibleChanged;
|
||||
rpl::event_stream<FullMsgId> _scrollToItemRequests;
|
||||
|
||||
@@ -231,22 +233,16 @@ void FieldHeader::init() {
|
||||
events(
|
||||
) | rpl::filter([=](not_null<QEvent*> event) {
|
||||
return ranges::contains(kMouseEvents, event->type())
|
||||
&& isEditingMessage();
|
||||
&& (isEditingMessage() || replyingToMessage());
|
||||
}) | rpl::start_with_next([=](not_null<QEvent*> event) {
|
||||
const auto type = event->type();
|
||||
const auto e = static_cast<QMouseEvent*>(event.get());
|
||||
const auto pos = e ? e->pos() : mapFromGlobal(QCursor::pos());
|
||||
const auto inPreviewRect = QRect(
|
||||
st::historyReplySkip,
|
||||
0,
|
||||
width() - st::historyReplySkip - _cancel->width(),
|
||||
height()).contains(pos);
|
||||
const auto inPreviewRect = _clickableRect.contains(pos);
|
||||
|
||||
if (type == QEvent::MouseMove) {
|
||||
const auto inEdit = inPreviewRect;
|
||||
|
||||
if (inEdit != *inClickable) {
|
||||
*inClickable = inEdit;
|
||||
if (inPreviewRect != *inClickable) {
|
||||
*inClickable = inPreviewRect;
|
||||
setCursor(*inClickable
|
||||
? style::cur_pointer
|
||||
: style::cur_default);
|
||||
@@ -260,7 +256,10 @@ void FieldHeader::init() {
|
||||
*leftIconPressed = true;
|
||||
update();
|
||||
} else if (isLeftButton && inPreviewRect) {
|
||||
_scrollToItemRequests.fire(_editMsgId.current());
|
||||
auto id = isEditingMessage()
|
||||
? _editMsgId.current()
|
||||
: replyingToMessage();
|
||||
_scrollToItemRequests.fire(std::move(id));
|
||||
}
|
||||
} else if (type == QEvent::MouseButtonRelease) {
|
||||
if (isLeftButton && *leftIconPressed) {
|
||||
@@ -451,6 +450,11 @@ WebPageId FieldHeader::webPageId() const {
|
||||
|
||||
void FieldHeader::updateControlsGeometry(QSize size) {
|
||||
_cancel->moveToRight(0, 0);
|
||||
_clickableRect = QRect(
|
||||
st::historyReplySkip,
|
||||
0,
|
||||
width() - st::historyReplySkip - _cancel->width(),
|
||||
height());
|
||||
}
|
||||
|
||||
void FieldHeader::editMessage(FullMsgId id) {
|
||||
|
||||
@@ -336,12 +336,16 @@ void ListWidget::refreshRows() {
|
||||
|
||||
_items.clear();
|
||||
_items.reserve(_slice.ids.size());
|
||||
auto nearestIndex = -1;
|
||||
for (const auto &fullId : _slice.ids) {
|
||||
if (const auto item = session().data().message(fullId)) {
|
||||
if (_slice.nearestToAround == fullId) {
|
||||
nearestIndex = int(_items.size());
|
||||
}
|
||||
_items.push_back(enforceViewForItem(item));
|
||||
}
|
||||
}
|
||||
updateAroundPositionFromRows();
|
||||
updateAroundPositionFromNearest(nearestIndex);
|
||||
|
||||
updateItemsGeometry();
|
||||
checkUnreadBarCreation();
|
||||
@@ -573,8 +577,7 @@ not_null<Element*> ListWidget::enforceViewForItem(
|
||||
return i->second.get();
|
||||
}
|
||||
|
||||
void ListWidget::updateAroundPositionFromRows() {
|
||||
const auto nearestIndex = findNearestItem(_aroundPosition);
|
||||
void ListWidget::updateAroundPositionFromNearest(int nearestIndex) {
|
||||
if (nearestIndex < 0) {
|
||||
_aroundIndex = -1;
|
||||
return;
|
||||
@@ -2091,7 +2094,8 @@ void ListWidget::mouseActionStart(
|
||||
if (isPressInSelectedText(dragState)) {
|
||||
_mouseAction = MouseAction::PrepareDrag; // start text drag
|
||||
} else if (!_pressWasInactive) {
|
||||
if (requiredToStartDragging(pressElement)) {
|
||||
if (requiredToStartDragging(pressElement)
|
||||
&& _pressState.pointState != PointState::Outside) {
|
||||
_mouseAction = MouseAction::PrepareDrag;
|
||||
} else {
|
||||
if (dragState.afterSymbol) ++_mouseTextSymbol;
|
||||
|
||||
@@ -305,7 +305,7 @@ private:
|
||||
using CursorState = HistoryView::CursorState;
|
||||
|
||||
void refreshViewer();
|
||||
void updateAroundPositionFromRows();
|
||||
void updateAroundPositionFromNearest(int nearestIndex);
|
||||
void refreshRows();
|
||||
ScrollTopState countScrollState() const;
|
||||
void saveScrollState();
|
||||
|
||||
@@ -286,7 +286,6 @@ void Message::applyGroupAdminChanges(
|
||||
const base::flat_set<UserId> &changes) {
|
||||
if (!data()->out()
|
||||
&& changes.contains(peerToUser(data()->author()->id))) {
|
||||
refreshRightBadge();
|
||||
history()->owner().requestViewResize(this);
|
||||
}
|
||||
}
|
||||
@@ -300,6 +299,7 @@ QSize Message::performCountOptimalSize() {
|
||||
|
||||
updateMediaInBubbleState();
|
||||
refreshEditedBadge();
|
||||
refreshRightBadge();
|
||||
|
||||
auto mediaOnBottom = (logEntryOriginal() != nullptr)
|
||||
|| (media && media->isDisplayed() && media->isBubbleBottom());
|
||||
@@ -542,14 +542,14 @@ void Message::draw(
|
||||
auto displayTail = skipTail ? RectPart::None : (outbg && !Core::App().settings().chatWide()) ? RectPart::Right : RectPart::Left;
|
||||
PaintBubble(p, g, width(), selected, outbg, displayTail);
|
||||
|
||||
const auto gBubble = g;
|
||||
paintCommentsButton(p, g, selected);
|
||||
auto inner = g;
|
||||
paintCommentsButton(p, inner, selected);
|
||||
|
||||
// Entry page is always a bubble bottom.
|
||||
auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || (entry/* && entry->isBubbleBottom()*/);
|
||||
auto mediaOnTop = (mediaDisplayed && media->isBubbleTop()) || (entry && entry->isBubbleTop());
|
||||
|
||||
auto trect = g.marginsRemoved(st::msgPadding);
|
||||
auto trect = inner.marginsRemoved(st::msgPadding);
|
||||
if (mediaOnBottom) {
|
||||
trect.setHeight(trect.height() + st::msgPadding.bottom());
|
||||
}
|
||||
@@ -567,7 +567,7 @@ void Message::draw(
|
||||
paintText(p, trect, selection);
|
||||
if (mediaDisplayed) {
|
||||
auto mediaHeight = media->height();
|
||||
auto mediaLeft = g.left();
|
||||
auto mediaLeft = inner.left();
|
||||
auto mediaTop = (trect.y() + trect.height() - mediaHeight);
|
||||
|
||||
p.translate(mediaLeft, mediaTop);
|
||||
@@ -575,7 +575,7 @@ void Message::draw(
|
||||
p.translate(-mediaLeft, -mediaTop);
|
||||
}
|
||||
if (entry) {
|
||||
auto entryLeft = g.left();
|
||||
auto entryLeft = inner.left();
|
||||
auto entryTop = trect.y() + trect.height();
|
||||
p.translate(entryLeft, entryTop);
|
||||
auto entrySelection = skipTextSelection(selection);
|
||||
@@ -591,29 +591,29 @@ void Message::draw(
|
||||
? !media->customInfoLayout()
|
||||
: true);
|
||||
if (needDrawInfo) {
|
||||
drawInfo(p, g.left() + g.width(), g.top() + g.height(), 2 * g.left() + g.width(), selected, InfoDisplayType::Default);
|
||||
if (g != gBubble) {
|
||||
drawInfo(p, inner.left() + inner.width(), inner.top() + inner.height(), 2 * inner.left() + inner.width(), selected, InfoDisplayType::Default);
|
||||
if (g != inner) {
|
||||
const auto o = p.opacity();
|
||||
p.setOpacity(0.3);
|
||||
const auto color = selected
|
||||
? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected)
|
||||
: (outbg ? st::msgOutDateFg : st::msgInDateFg);
|
||||
p.fillRect(g.left(), g.top() + g.height() - st::lineWidth, g.width(), st::lineWidth, color);
|
||||
p.fillRect(inner.left(), inner.top() + inner.height() - st::lineWidth, inner.width(), st::lineWidth, color);
|
||||
p.setOpacity(o);
|
||||
}
|
||||
}
|
||||
if (const auto size = rightActionSize()) {
|
||||
const auto fastShareSkip = std::clamp(
|
||||
(gBubble.height() - size->height()) / 2,
|
||||
(g.height() - size->height()) / 2,
|
||||
0,
|
||||
st::historyFastShareBottom);
|
||||
const auto fastShareLeft = g.left() + g.width() + st::historyFastShareLeft;
|
||||
const auto fastShareTop = g.top() + gBubble.height() - fastShareSkip - size->height();
|
||||
const auto fastShareTop = g.top() + g.height() - fastShareSkip - size->height();
|
||||
drawRightAction(p, fastShareLeft, fastShareTop, width());
|
||||
}
|
||||
|
||||
if (media) {
|
||||
media->paintBubbleFireworks(p, gBubble, ms);
|
||||
media->paintBubbleFireworks(p, g, ms);
|
||||
}
|
||||
} else if (media && media->isDisplayed()) {
|
||||
p.translate(g.topLeft());
|
||||
@@ -782,74 +782,77 @@ void Message::paintFromName(
|
||||
QRect &trect,
|
||||
bool selected) const {
|
||||
const auto item = message();
|
||||
if (displayFromName()) {
|
||||
const auto badgeWidth = _rightBadge.isEmpty() ? 0 : _rightBadge.maxWidth();
|
||||
const auto replyWidth = [&] {
|
||||
if (isUnderCursor() && displayFastReply()) {
|
||||
return st::msgFont->width(FastReplyText());
|
||||
}
|
||||
return 0;
|
||||
}();
|
||||
const auto rightWidth = replyWidth ? replyWidth : badgeWidth;
|
||||
auto availableLeft = trect.left();
|
||||
auto availableWidth = trect.width();
|
||||
if (rightWidth) {
|
||||
availableWidth -= st::msgPadding.right() + rightWidth;
|
||||
if (!displayFromName()) {
|
||||
return;
|
||||
}
|
||||
const auto badgeWidth = _rightBadge.isEmpty() ? 0 : _rightBadge.maxWidth();
|
||||
const auto replyWidth = [&] {
|
||||
if (isUnderCursor() && displayFastReply()) {
|
||||
return st::msgFont->width(FastReplyText());
|
||||
}
|
||||
return 0;
|
||||
}();
|
||||
const auto rightWidth = replyWidth ? replyWidth : badgeWidth;
|
||||
auto availableLeft = trect.left();
|
||||
auto availableWidth = trect.width();
|
||||
if (rightWidth) {
|
||||
availableWidth -= st::msgPadding.right() + rightWidth;
|
||||
}
|
||||
|
||||
p.setFont(st::msgNameFont);
|
||||
const auto nameText = [&]() -> const Ui::Text::String * {
|
||||
const auto from = item->displayFrom();
|
||||
if (hasOutLayout()) {
|
||||
p.setPen(selected ? st::msgOutServiceFgSelected : st::msgOutServiceFg);
|
||||
return &from->nameText();
|
||||
} else if (item->isPost()) {
|
||||
p.setPen(selected ? st::msgInServiceFgSelected : st::msgInServiceFg);
|
||||
return &from->nameText();
|
||||
} else if (from) {
|
||||
p.setPen(FromNameFg(from->id, selected));
|
||||
return &from->nameText();
|
||||
} else if (const auto info = item->hiddenForwardedInfo()) {
|
||||
p.setPen(FromNameFg(info->colorPeerId, selected));
|
||||
return &info->nameText;
|
||||
} else {
|
||||
Unexpected("Corrupt forwarded information in message.");
|
||||
}
|
||||
}();
|
||||
nameText->drawElided(p, availableLeft, trect.top(), availableWidth);
|
||||
const auto skipWidth = nameText->maxWidth() + st::msgServiceFont->spacew;
|
||||
p.setFont(st::msgNameFont);
|
||||
const auto outbg = hasOutLayout();
|
||||
const auto nameText = [&]() -> const Ui::Text::String * {
|
||||
const auto from = item->displayFrom();
|
||||
if (outbg) {
|
||||
p.setPen(selected ? st::msgOutServiceFgSelected : st::msgOutServiceFg);
|
||||
return &from->nameText();
|
||||
} else if (item->isPost()) {
|
||||
p.setPen(selected ? st::msgInServiceFgSelected : st::msgInServiceFg);
|
||||
return &from->nameText();
|
||||
} else if (from) {
|
||||
p.setPen(FromNameFg(from->id, selected));
|
||||
return &from->nameText();
|
||||
} else if (const auto info = item->hiddenForwardedInfo()) {
|
||||
p.setPen(FromNameFg(info->colorPeerId, selected));
|
||||
return &info->nameText;
|
||||
} else {
|
||||
Unexpected("Corrupt forwarded information in message.");
|
||||
}
|
||||
}();
|
||||
nameText->drawElided(p, availableLeft, trect.top(), availableWidth);
|
||||
const auto skipWidth = nameText->maxWidth() + st::msgServiceFont->spacew;
|
||||
availableLeft += skipWidth;
|
||||
availableWidth -= skipWidth;
|
||||
|
||||
auto via = item->Get<HistoryMessageVia>();
|
||||
if (via && !displayForwardedFrom() && availableWidth > 0) {
|
||||
p.setPen(selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg));
|
||||
p.drawText(availableLeft, trect.top() + st::msgServiceFont->ascent, via->text);
|
||||
auto skipWidth = via->width + st::msgServiceFont->spacew;
|
||||
availableLeft += skipWidth;
|
||||
availableWidth -= skipWidth;
|
||||
|
||||
auto via = item->Get<HistoryMessageVia>();
|
||||
if (via && !displayForwardedFrom() && availableWidth > 0) {
|
||||
const auto outbg = hasOutLayout();
|
||||
p.setPen(selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg));
|
||||
p.drawText(availableLeft, trect.top() + st::msgServiceFont->ascent, via->text);
|
||||
auto skipWidth = via->width + st::msgServiceFont->spacew;
|
||||
availableLeft += skipWidth;
|
||||
availableWidth -= skipWidth;
|
||||
}
|
||||
if (rightWidth) {
|
||||
p.setPen(selected ? st::msgInDateFgSelected : st::msgInDateFg);
|
||||
p.setFont(ClickHandler::showAsActive(_fastReplyLink)
|
||||
? st::msgFont->underline()
|
||||
: st::msgFont);
|
||||
if (replyWidth) {
|
||||
p.drawText(
|
||||
trect.left() + trect.width() - rightWidth,
|
||||
trect.top() + st::msgFont->ascent,
|
||||
FastReplyText());
|
||||
} else {
|
||||
_rightBadge.draw(
|
||||
p,
|
||||
trect.left() + trect.width() - rightWidth,
|
||||
trect.top(),
|
||||
rightWidth);
|
||||
}
|
||||
}
|
||||
trect.setY(trect.y() + st::msgNameFont->height);
|
||||
}
|
||||
if (rightWidth) {
|
||||
p.setPen(outbg
|
||||
? (selected ? st::msgOutDateFgSelected : st::msgOutDateFg)
|
||||
: (selected ? st::msgInDateFgSelected : st::msgInDateFg));
|
||||
p.setFont(ClickHandler::showAsActive(_fastReplyLink)
|
||||
? st::msgFont->underline()
|
||||
: st::msgFont);
|
||||
if (replyWidth) {
|
||||
p.drawText(
|
||||
trect.left() + trect.width() - rightWidth,
|
||||
trect.top() + st::msgFont->ascent,
|
||||
FastReplyText());
|
||||
} else {
|
||||
_rightBadge.draw(
|
||||
p,
|
||||
trect.left() + trect.width() - rightWidth,
|
||||
trect.top(),
|
||||
rightWidth);
|
||||
}
|
||||
}
|
||||
trect.setY(trect.y() + st::msgNameFont->height);
|
||||
}
|
||||
|
||||
void Message::paintForwardedInfo(Painter &p, QRect &trect, bool selected) const {
|
||||
@@ -1148,12 +1151,12 @@ TextState Message::textState(
|
||||
auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || (entry/* && entry->isBubbleBottom()*/);
|
||||
auto mediaOnTop = (mediaDisplayed && media->isBubbleTop()) || (entry && entry->isBubbleTop());
|
||||
|
||||
const auto gBubble = g;
|
||||
if (getStateCommentsButton(point, g, &result)) {
|
||||
auto bubble = g;
|
||||
if (getStateCommentsButton(point, bubble, &result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
auto trect = g.marginsRemoved(st::msgPadding);
|
||||
auto trect = bubble.marginsRemoved(st::msgPadding);
|
||||
if (mediaOnBottom) {
|
||||
trect.setHeight(trect.height() + st::msgPadding.bottom());
|
||||
}
|
||||
@@ -1176,7 +1179,7 @@ TextState Message::textState(
|
||||
if (entry) {
|
||||
auto entryHeight = entry->height();
|
||||
trect.setHeight(trect.height() - entryHeight);
|
||||
auto entryLeft = g.left();
|
||||
auto entryLeft = bubble.left();
|
||||
auto entryTop = trect.y() + trect.height();
|
||||
if (point.y() >= entryTop && point.y() < entryTop + entryHeight) {
|
||||
result = entry->textState(
|
||||
@@ -1191,8 +1194,8 @@ TextState Message::textState(
|
||||
return;
|
||||
}
|
||||
const auto inDate = pointInTime(
|
||||
g.left() + g.width(),
|
||||
g.top() + g.height(),
|
||||
bubble.left() + bubble.width(),
|
||||
bubble.top() + bubble.height(),
|
||||
point,
|
||||
InfoDisplayType::Default);
|
||||
if (inDate) {
|
||||
@@ -1224,11 +1227,11 @@ TextState Message::textState(
|
||||
checkForPointInTime();
|
||||
if (const auto size = rightActionSize()) {
|
||||
const auto fastShareSkip = snap(
|
||||
(gBubble.height() - size->height()) / 2,
|
||||
(g.height() - size->height()) / 2,
|
||||
0,
|
||||
st::historyFastShareBottom);
|
||||
const auto fastShareLeft = g.left() + g.width() + st::historyFastShareLeft;
|
||||
const auto fastShareTop = g.top() + gBubble.height() - fastShareSkip - size->height();
|
||||
const auto fastShareTop = g.top() + g.height() - fastShareSkip - size->height();
|
||||
if (QRect(
|
||||
fastShareLeft,
|
||||
fastShareTop,
|
||||
|
||||
@@ -1519,7 +1519,7 @@ void RepliesWidget::updateControlsGeometry() {
|
||||
|
||||
const auto bottom = height();
|
||||
const auto controlsHeight = _composeControls->heightCurrent();
|
||||
const auto scrollY = _topBar->height() + _rootView->height();
|
||||
const auto scrollY = _topBar->height() + _rootViewHeight;
|
||||
const auto scrollHeight = bottom - scrollY - controlsHeight;
|
||||
const auto scrollSize = QSize(contentWidth, scrollHeight);
|
||||
if (_scroll->size() != scrollSize) {
|
||||
@@ -1585,13 +1585,28 @@ void RepliesWidget::updatePinnedVisibility() {
|
||||
return _root;
|
||||
}();
|
||||
const auto view = _inner->viewByPosition(item->position());
|
||||
setPinnedVisibility(!view
|
||||
|| (view->y() + view->height() <= _scroll->scrollTop()));
|
||||
const auto visible = !view
|
||||
|| (view->y() + view->height() <= _scroll->scrollTop());
|
||||
setPinnedVisibility(visible);
|
||||
}
|
||||
|
||||
void RepliesWidget::setPinnedVisibility(bool shown) {
|
||||
if (!animating()) {
|
||||
_rootView->toggle(shown, anim::type::normal);
|
||||
if (!_rootViewInited) {
|
||||
const auto height = shown ? st::historyReplyHeight : 0;
|
||||
if (const auto delta = height - _rootViewHeight) {
|
||||
_rootViewHeight = height;
|
||||
if (_scroll->scrollTop() == _scroll->scrollTopMax()) {
|
||||
setGeometryWithTopMoved(geometry(), delta);
|
||||
} else {
|
||||
updateControlsGeometry();
|
||||
}
|
||||
}
|
||||
_rootView->toggle(shown, anim::type::instant);
|
||||
_rootViewInited = true;
|
||||
} else {
|
||||
_rootView->toggle(shown, anim::type::normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -255,6 +255,7 @@ private:
|
||||
object_ptr<Ui::SlideWrap<Ui::RpWidget>> _rootView;
|
||||
int _rootViewHeight = 0;
|
||||
object_ptr<Ui::PlainShadow> _rootShadow;
|
||||
bool _rootViewInited = false;
|
||||
|
||||
std::unique_ptr<Ui::ScrollArea> _scroll;
|
||||
|
||||
|
||||
@@ -384,9 +384,7 @@ void Document::draw(Painter &p, const QRect &r, TextSelection selection, crl::ti
|
||||
_animation->radial.draw(p, rinner, st::msgFileRadialLine, fg);
|
||||
}
|
||||
|
||||
if (!loaded) {
|
||||
drawCornerDownload(p, selected);
|
||||
}
|
||||
drawCornerDownload(p, selected);
|
||||
}
|
||||
auto namewidth = width() - nameleft - nameright;
|
||||
auto statuswidth = namewidth;
|
||||
@@ -530,7 +528,9 @@ bool Document::downloadInCorner() const {
|
||||
}
|
||||
|
||||
void Document::drawCornerDownload(Painter &p, bool selected) const {
|
||||
if (!downloadInCorner()) {
|
||||
if (dataLoaded()
|
||||
|| _data->loadedInMediaCache()
|
||||
|| !downloadInCorner()) {
|
||||
return;
|
||||
}
|
||||
auto outbg = _parent->hasOutLayout();
|
||||
@@ -570,7 +570,9 @@ TextState Document::cornerDownloadTextState(
|
||||
QPoint point,
|
||||
StateRequest request) const {
|
||||
auto result = TextState(_parent);
|
||||
if (!downloadInCorner()) {
|
||||
if (dataLoaded()
|
||||
|| _data->loadedInMediaCache()
|
||||
|| !downloadInCorner()) {
|
||||
return result;
|
||||
}
|
||||
auto topMinus = isBubbleTop() ? 0 : st::msgFileTopMinus;
|
||||
@@ -627,10 +629,8 @@ TextState Document::textState(QPoint point, StateRequest request) const {
|
||||
nametop = st::msgFileNameTop - topMinus;
|
||||
bottom = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom() - topMinus;
|
||||
|
||||
if (!loaded) {
|
||||
if (const auto state = cornerDownloadTextState(point, request); state.link) {
|
||||
return state;
|
||||
}
|
||||
if (const auto state = cornerDownloadTextState(point, request); state.link) {
|
||||
return state;
|
||||
}
|
||||
QRect inner(style::rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top() - topMinus, st::msgFileSize, st::msgFileSize, width()));
|
||||
if ((_data->loading() || _data->uploading()) && inner.contains(point) && !downloadInCorner()) {
|
||||
|
||||
@@ -649,36 +649,41 @@ void ListWidget::restart() {
|
||||
}
|
||||
|
||||
void ListWidget::itemRemoved(not_null<const HistoryItem*> item) {
|
||||
if (isMyItem(item)) {
|
||||
auto id = GetUniversalId(item);
|
||||
|
||||
auto sectionIt = findSectionByItem(id);
|
||||
if (sectionIt != _sections.end()) {
|
||||
if (sectionIt->removeItem(id)) {
|
||||
auto top = sectionIt->top();
|
||||
if (sectionIt->empty()) {
|
||||
_sections.erase(sectionIt);
|
||||
}
|
||||
refreshHeight();
|
||||
}
|
||||
}
|
||||
|
||||
if (isItemLayout(item, _overLayout)) {
|
||||
_overLayout = nullptr;
|
||||
}
|
||||
|
||||
if (const auto i = _layouts.find(id); i != _layouts.end()) {
|
||||
_heavyLayouts.remove(i->second.item.get());
|
||||
_layouts.erase(i);
|
||||
}
|
||||
_dragSelected.remove(id);
|
||||
|
||||
if (const auto i = _selected.find(id); i != _selected.cend()) {
|
||||
removeItemSelection(i);
|
||||
}
|
||||
|
||||
mouseActionUpdate(_mousePosition);
|
||||
if (!isMyItem(item)) {
|
||||
return;
|
||||
}
|
||||
auto id = GetUniversalId(item);
|
||||
|
||||
auto needHeightRefresh = false;
|
||||
auto sectionIt = findSectionByItem(id);
|
||||
if (sectionIt != _sections.end()) {
|
||||
if (sectionIt->removeItem(id)) {
|
||||
auto top = sectionIt->top();
|
||||
if (sectionIt->empty()) {
|
||||
_sections.erase(sectionIt);
|
||||
}
|
||||
needHeightRefresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isItemLayout(item, _overLayout)) {
|
||||
_overLayout = nullptr;
|
||||
}
|
||||
|
||||
if (const auto i = _layouts.find(id); i != _layouts.end()) {
|
||||
_heavyLayouts.remove(i->second.item.get());
|
||||
_layouts.erase(i);
|
||||
}
|
||||
_dragSelected.remove(id);
|
||||
|
||||
if (const auto i = _selected.find(id); i != _selected.cend()) {
|
||||
removeItemSelection(i);
|
||||
}
|
||||
|
||||
if (needHeightRefresh) {
|
||||
refreshHeight();
|
||||
}
|
||||
mouseActionUpdate(_mousePosition);
|
||||
}
|
||||
|
||||
FullMsgId ListWidget::computeFullId(
|
||||
|
||||
@@ -100,7 +100,15 @@ void Instance::start() {
|
||||
|
||||
void Instance::stop(Fn<void(Result&&)> callback) {
|
||||
InvokeQueued(_inner.get(), [=] {
|
||||
_inner->stop(callback);
|
||||
if (!callback) {
|
||||
_inner->stop();
|
||||
return;
|
||||
}
|
||||
_inner->stop([=](Result &&result) {
|
||||
crl::on_main([=, result = std::move(result)]() mutable {
|
||||
callback(std::move(result));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -524,7 +532,7 @@ void Instance::Inner::timeout() {
|
||||
return;
|
||||
}
|
||||
ALint samples;
|
||||
alcGetIntegerv(d->device, ALC_CAPTURE_SAMPLES, sizeof(samples), &samples);
|
||||
alcGetIntegerv(d->device, ALC_CAPTURE_SAMPLES, 1, &samples);
|
||||
if (ErrorHappened(d->device)) {
|
||||
fail();
|
||||
return;
|
||||
|
||||
@@ -1489,32 +1489,33 @@ void OverlayWidget::onForward() {
|
||||
}
|
||||
|
||||
void OverlayWidget::onDelete() {
|
||||
const auto session = _session;
|
||||
if (!session) {
|
||||
if (!_session) {
|
||||
return;
|
||||
}
|
||||
|
||||
close();
|
||||
const auto deletingPeerPhoto = [this] {
|
||||
const auto session = _session;
|
||||
const auto photo = _photo;
|
||||
const auto msgid = _msgid;
|
||||
const auto deletingPeerPhoto = [&] {
|
||||
if (!_msgid) {
|
||||
return true;
|
||||
}
|
||||
if (_photo && _history) {
|
||||
} else if (_photo && _history) {
|
||||
if (_history->peer->userpicPhotoId() == _photo->id) {
|
||||
return _firstOpenedPeerPhoto;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}();
|
||||
close();
|
||||
|
||||
Core::App().domain().activate(&_session->account());
|
||||
const auto &active = _session->windows();
|
||||
Core::App().domain().activate(&session->account());
|
||||
const auto &active = session->windows();
|
||||
if (active.empty()) {
|
||||
return;
|
||||
}
|
||||
if (deletingPeerPhoto()) {
|
||||
active.front()->content()->deletePhotoLayer(_photo);
|
||||
} else if (const auto item = session->data().message(_msgid)) {
|
||||
if (deletingPeerPhoto) {
|
||||
active.front()->content()->deletePhotoLayer(photo);
|
||||
} else if (const auto item = session->data().message(msgid)) {
|
||||
const auto suggestModerateActions = true;
|
||||
Ui::show(Box<DeleteMessagesBox>(item, suggestModerateActions));
|
||||
}
|
||||
@@ -1544,15 +1545,15 @@ void OverlayWidget::onCopy() {
|
||||
|
||||
void OverlayWidget::onAttachedStickers() {
|
||||
const auto session = _session;
|
||||
if (!session) {
|
||||
if (!session || !_photo) {
|
||||
return;
|
||||
}
|
||||
const auto &active = _session->windows();
|
||||
if (active.empty()) {
|
||||
return;
|
||||
}
|
||||
close();
|
||||
active.front()->requestAttachedStickerSets(_photo);
|
||||
close();
|
||||
}
|
||||
|
||||
auto OverlayWidget::sharedMediaType() const
|
||||
|
||||
@@ -39,6 +39,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <QtDBus/QDBusReply>
|
||||
#include <QtDBus/QDBusError>
|
||||
#include <QtDBus/QDBusMetaType>
|
||||
|
||||
extern "C" {
|
||||
#undef signals
|
||||
#include <gio/gio.h>
|
||||
#define signals public
|
||||
} // extern "C"
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
#include <glib.h>
|
||||
@@ -51,10 +57,13 @@ constexpr auto kForcePanelIcon = "TDESKTOP_FORCE_PANEL_ICON"_cs;
|
||||
constexpr auto kPanelTrayIconName = "telegram-panel"_cs;
|
||||
constexpr auto kMutePanelTrayIconName = "telegram-mute-panel"_cs;
|
||||
constexpr auto kAttentionPanelTrayIconName = "telegram-attention-panel"_cs;
|
||||
constexpr auto kSNIWatcherService = "org.kde.StatusNotifierWatcher"_cs;
|
||||
constexpr auto kPropertiesInterface = "org.freedesktop.DBus.Properties"_cs;
|
||||
constexpr auto kTrayIconFilename = "tdesktop-trayicon-XXXXXX.png"_cs;
|
||||
|
||||
constexpr auto kSNIWatcherService = "org.kde.StatusNotifierWatcher"_cs;
|
||||
constexpr auto kSNIWatcherObjectPath = "/StatusNotifierWatcher"_cs;
|
||||
constexpr auto kSNIWatcherInterface = kSNIWatcherService;
|
||||
|
||||
constexpr auto kAppMenuService = "com.canonical.AppMenu.Registrar"_cs;
|
||||
constexpr auto kAppMenuObjectPath = "/com/canonical/AppMenu/Registrar"_cs;
|
||||
constexpr auto kAppMenuInterface = kAppMenuService;
|
||||
@@ -65,9 +74,6 @@ base::flat_map<int, QImage> TrayIconImageBack;
|
||||
QIcon TrayIcon;
|
||||
QString TrayIconThemeName, TrayIconName;
|
||||
|
||||
bool SNIAvailable = false;
|
||||
bool AppMenuSupported = false;
|
||||
|
||||
QString GetPanelIconName(int counter, bool muted) {
|
||||
return (counter > 0)
|
||||
? (muted
|
||||
@@ -222,7 +228,13 @@ QIcon TrayIconGen(int counter, bool muted) {
|
||||
iconImage.height() - layer.height() - 1,
|
||||
layer);
|
||||
} else {
|
||||
App::wnd()->placeSmallCounter(iconImage, 16, counter, bg, QPoint(), fg);
|
||||
App::wnd()->placeSmallCounter(
|
||||
iconImage,
|
||||
16,
|
||||
counter,
|
||||
bg,
|
||||
QPoint(),
|
||||
fg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,7 +324,7 @@ bool IsSNIAvailable() {
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
auto message = QDBusMessage::createMethodCall(
|
||||
kSNIWatcherService.utf16(),
|
||||
qsl("/StatusNotifierWatcher"),
|
||||
kSNIWatcherObjectPath.utf16(),
|
||||
kPropertiesInterface.utf16(),
|
||||
qsl("Get"));
|
||||
|
||||
@@ -416,15 +428,26 @@ MainWindow::MainWindow(not_null<Window::Controller*> controller)
|
||||
}
|
||||
|
||||
void MainWindow::initHook() {
|
||||
SNIAvailable = IsSNIAvailable();
|
||||
|
||||
const auto trayAvailable = SNIAvailable
|
||||
|| QSystemTrayIcon::isSystemTrayAvailable();
|
||||
|
||||
LOG(("System tray available: %1").arg(Logs::b(trayAvailable)));
|
||||
Platform::SetTrayIconSupported(trayAvailable);
|
||||
_sniAvailable = IsSNIAvailable();
|
||||
LOG(("System tray available: %1").arg(Logs::b(trayAvailable())));
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
_sniDBusProxy = g_dbus_proxy_new_for_bus_sync(
|
||||
G_BUS_TYPE_SESSION,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
nullptr,
|
||||
kSNIWatcherService.utf8(),
|
||||
kSNIWatcherObjectPath.utf8(),
|
||||
kSNIWatcherInterface.utf8(),
|
||||
nullptr,
|
||||
nullptr);
|
||||
|
||||
g_signal_connect(
|
||||
_sniDBusProxy,
|
||||
"g-signal",
|
||||
G_CALLBACK(sniSignalEmitted),
|
||||
this);
|
||||
|
||||
auto sniWatcher = new QDBusServiceWatcher(
|
||||
kSNIWatcherService.utf16(),
|
||||
QDBusConnection::sessionBus(),
|
||||
@@ -442,7 +465,7 @@ void MainWindow::initHook() {
|
||||
handleSNIOwnerChanged(service, oldOwner, newOwner);
|
||||
});
|
||||
|
||||
AppMenuSupported = IsAppMenuSupported();
|
||||
_appMenuSupported = IsAppMenuSupported();
|
||||
|
||||
auto appMenuWatcher = new QDBusServiceWatcher(
|
||||
kAppMenuService.utf16(),
|
||||
@@ -461,7 +484,7 @@ void MainWindow::initHook() {
|
||||
handleAppMenuOwnerChanged(service, oldOwner, newOwner);
|
||||
});
|
||||
|
||||
if (AppMenuSupported) {
|
||||
if (_appMenuSupported) {
|
||||
LOG(("Using D-Bus global menu."));
|
||||
} else {
|
||||
LOG(("Not using D-Bus global menu."));
|
||||
@@ -484,7 +507,7 @@ void MainWindow::initHook() {
|
||||
|
||||
bool MainWindow::hasTrayIcon() const {
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
return trayIcon || (SNIAvailable && _sniTrayIcon);
|
||||
return trayIcon || (_sniAvailable && _sniTrayIcon);
|
||||
#else
|
||||
return trayIcon;
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
@@ -564,15 +587,50 @@ void MainWindow::attachToSNITrayIcon() {
|
||||
updateTrayMenu();
|
||||
}
|
||||
|
||||
void MainWindow::handleSNIOwnerChanged(
|
||||
const QString &service,
|
||||
const QString &oldOwner,
|
||||
const QString &newOwner) {
|
||||
void MainWindow::sniSignalEmitted(
|
||||
GDBusProxy *proxy,
|
||||
gchar *sender_name,
|
||||
gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
MainWindow *window) {
|
||||
if(signal_name == qstr("StatusNotifierHostRegistered")) {
|
||||
window->handleSNIHostRegistered();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::handleSNIHostRegistered() {
|
||||
if (_sniAvailable) {
|
||||
return;
|
||||
}
|
||||
|
||||
_sniAvailable = true;
|
||||
|
||||
if (Global::WorkMode().value() == dbiwmWindowOnly) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldOwner.isEmpty() && !newOwner.isEmpty()) {
|
||||
LOG(("Switching to SNI tray icon..."));
|
||||
|
||||
if (trayIcon) {
|
||||
trayIcon->setContextMenu(0);
|
||||
trayIcon->deleteLater();
|
||||
}
|
||||
trayIcon = nullptr;
|
||||
|
||||
psSetupTrayIcon();
|
||||
}
|
||||
|
||||
void MainWindow::handleSNIOwnerChanged(
|
||||
const QString &service,
|
||||
const QString &oldOwner,
|
||||
const QString &newOwner) {
|
||||
_sniAvailable = IsSNIAvailable();
|
||||
|
||||
if (Global::WorkMode().value() == dbiwmWindowOnly) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldOwner.isEmpty() && !newOwner.isEmpty() && _sniAvailable) {
|
||||
LOG(("Switching to SNI tray icon..."));
|
||||
} else if (!oldOwner.isEmpty() && newOwner.isEmpty()) {
|
||||
LOG(("Switching to Qt tray icon..."));
|
||||
@@ -586,14 +644,7 @@ void MainWindow::handleSNIOwnerChanged(
|
||||
}
|
||||
trayIcon = nullptr;
|
||||
|
||||
SNIAvailable = !newOwner.isEmpty();
|
||||
|
||||
const auto trayAvailable = SNIAvailable
|
||||
|| QSystemTrayIcon::isSystemTrayAvailable();
|
||||
|
||||
Platform::SetTrayIconSupported(trayAvailable);
|
||||
|
||||
if (trayAvailable) {
|
||||
if (trayAvailable()) {
|
||||
psSetupTrayIcon();
|
||||
} else {
|
||||
LOG(("System tray is not available."));
|
||||
@@ -605,14 +656,14 @@ void MainWindow::handleAppMenuOwnerChanged(
|
||||
const QString &oldOwner,
|
||||
const QString &newOwner) {
|
||||
if (oldOwner.isEmpty() && !newOwner.isEmpty()) {
|
||||
AppMenuSupported = true;
|
||||
_appMenuSupported = true;
|
||||
LOG(("Using D-Bus global menu."));
|
||||
} else if (!oldOwner.isEmpty() && newOwner.isEmpty()) {
|
||||
AppMenuSupported = false;
|
||||
_appMenuSupported = false;
|
||||
LOG(("Not using D-Bus global menu."));
|
||||
}
|
||||
|
||||
if (AppMenuSupported && !_mainMenuPath.path().isEmpty()) {
|
||||
if (_appMenuSupported && !_mainMenuPath.path().isEmpty()) {
|
||||
RegisterAppMenu(winId(), _mainMenuPath);
|
||||
} else {
|
||||
UnregisterAppMenu(winId());
|
||||
@@ -624,7 +675,7 @@ void MainWindow::psSetupTrayIcon() {
|
||||
const auto counter = Core::App().unreadBadge();
|
||||
const auto muted = Core::App().unreadBadgeMuted();
|
||||
|
||||
if (SNIAvailable) {
|
||||
if (_sniAvailable) {
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
LOG(("Using SNI tray icon."));
|
||||
if (!_sniTrayIcon) {
|
||||
@@ -654,7 +705,7 @@ void MainWindow::psSetupTrayIcon() {
|
||||
}
|
||||
|
||||
void MainWindow::workmodeUpdated(DBIWorkMode mode) {
|
||||
if (!Platform::TrayIconSupported()) {
|
||||
if (!trayAvailable()) {
|
||||
return;
|
||||
} else if (mode == dbiwmWindowOnly) {
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
@@ -953,7 +1004,7 @@ void MainWindow::createGlobalMenu() {
|
||||
_mainMenuPath.path(),
|
||||
psMainMenu);
|
||||
|
||||
if (AppMenuSupported) {
|
||||
if (_appMenuSupported) {
|
||||
RegisterAppMenu(winId(), _mainMenuPath);
|
||||
}
|
||||
|
||||
@@ -1074,7 +1125,7 @@ void MainWindow::updateGlobalMenuHook() {
|
||||
}
|
||||
|
||||
void MainWindow::handleVisibleChangedHook(bool visible) {
|
||||
if (AppMenuSupported && !_mainMenuPath.path().isEmpty()) {
|
||||
if (_appMenuSupported && !_mainMenuPath.path().isEmpty()) {
|
||||
if (visible) {
|
||||
RegisterAppMenu(winId(), _mainMenuPath);
|
||||
} else {
|
||||
@@ -1089,12 +1140,14 @@ MainWindow::~MainWindow() {
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
delete _sniTrayIcon;
|
||||
|
||||
if (AppMenuSupported) {
|
||||
if (_appMenuSupported) {
|
||||
UnregisterAppMenu(winId());
|
||||
}
|
||||
|
||||
delete _mainMenuExporter;
|
||||
delete psMainMenu;
|
||||
|
||||
g_object_unref(_sniDBusProxy);
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
delete _trayIconMenuXEmbed;
|
||||
|
||||
@@ -16,7 +16,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <QtCore/QTemporaryFile>
|
||||
#include <QtDBus/QDBusObjectPath>
|
||||
#include <dbusmenuexporter.h>
|
||||
#endif
|
||||
|
||||
typedef char gchar;
|
||||
typedef struct _GVariant GVariant;
|
||||
typedef struct _GDBusProxy GDBusProxy;
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
namespace Platform {
|
||||
|
||||
@@ -33,6 +37,14 @@ public:
|
||||
|
||||
void psShowTrayMenu();
|
||||
|
||||
bool trayAvailable() {
|
||||
return _sniAvailable || QSystemTrayIcon::isSystemTrayAvailable();
|
||||
}
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
void handleSNIHostRegistered();
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
static void LibsLoaded();
|
||||
|
||||
~MainWindow();
|
||||
@@ -64,6 +76,7 @@ protected:
|
||||
style::color color) = 0;
|
||||
|
||||
private:
|
||||
bool _sniAvailable = false;
|
||||
Ui::PopupMenu *_trayIconMenuXEmbed = nullptr;
|
||||
|
||||
void updateIconCounters();
|
||||
@@ -71,8 +84,10 @@ private:
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
StatusNotifierItem *_sniTrayIcon = nullptr;
|
||||
GDBusProxy *_sniDBusProxy = nullptr;
|
||||
std::unique_ptr<QTemporaryFile> _trayIconFile = nullptr;
|
||||
|
||||
bool _appMenuSupported = false;
|
||||
DBusMenuExporter *_mainMenuExporter = nullptr;
|
||||
QDBusObjectPath _mainMenuPath;
|
||||
|
||||
@@ -124,6 +139,13 @@ private:
|
||||
void psLinuxStrikeOut();
|
||||
void psLinuxMonospace();
|
||||
void psLinuxClearFormat();
|
||||
|
||||
static void sniSignalEmitted(
|
||||
GDBusProxy *proxy,
|
||||
gchar *sender_name,
|
||||
gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
MainWindow *window);
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
};
|
||||
|
||||
@@ -85,8 +85,6 @@ constexpr auto kXCBFrameExtentsAtomName = "_GTK_FRAME_EXTENTS"_cs;
|
||||
|
||||
QStringList PlatformThemes;
|
||||
|
||||
bool IsTrayIconSupported = true;
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
void PortalAutostart(bool autostart, bool silent = false) {
|
||||
if (cExeName().isEmpty()) {
|
||||
@@ -1013,7 +1011,10 @@ QImage GetImageFromClipboard() {
|
||||
|
||||
std::optional<crl::time> LastUserInputTime() {
|
||||
if (!IsWayland()) {
|
||||
return XCBLastUserInputTime();
|
||||
const auto xcbResult = XCBLastUserInputTime();
|
||||
if (xcbResult.has_value()) {
|
||||
return xcbResult;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
@@ -1063,11 +1064,9 @@ bool AutostartSupported() {
|
||||
}
|
||||
|
||||
bool TrayIconSupported() {
|
||||
return IsTrayIconSupported;
|
||||
}
|
||||
|
||||
void SetTrayIconSupported(bool supported) {
|
||||
IsTrayIconSupported = supported;
|
||||
return App::wnd()
|
||||
? App::wnd()->trayAvailable()
|
||||
: false;
|
||||
}
|
||||
|
||||
bool StartSystemMove(QWindow *window) {
|
||||
@@ -1420,13 +1419,13 @@ void RegisterCustomScheme(bool force) {
|
||||
|
||||
GError *error = nullptr;
|
||||
|
||||
const auto actualCommandlineBuilder = qsl("%1 --")
|
||||
const auto neededCommandlineBuilder = qsl("%1 --")
|
||||
.arg((IsStaticBinary() || InAppImage())
|
||||
? cExeDir() + cExeName()
|
||||
: cExeName());
|
||||
|
||||
const auto actualCommandline = qsl("%1 %u")
|
||||
.arg(actualCommandlineBuilder);
|
||||
const auto neededCommandline = qsl("%1 %u")
|
||||
.arg(neededCommandlineBuilder);
|
||||
|
||||
auto currentAppInfo = g_app_info_get_default_for_type(
|
||||
kHandlerTypeName.utf8(),
|
||||
@@ -1438,13 +1437,36 @@ void RegisterCustomScheme(bool force) {
|
||||
|
||||
g_object_unref(currentAppInfo);
|
||||
|
||||
if (currentCommandline == actualCommandline) {
|
||||
if (currentCommandline == neededCommandline) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto registeredAppInfoList = g_app_info_get_recommended_for_type(
|
||||
kHandlerTypeName.utf8());
|
||||
|
||||
for (auto l = registeredAppInfoList; l != nullptr; l = l->next) {
|
||||
const auto currentRegisteredAppInfo = reinterpret_cast<GAppInfo*>(
|
||||
l->data);
|
||||
|
||||
const auto currentAppInfoId = QString(
|
||||
g_app_info_get_id(currentRegisteredAppInfo));
|
||||
|
||||
const auto currentCommandline = QString(
|
||||
g_app_info_get_commandline(currentRegisteredAppInfo));
|
||||
|
||||
if (currentCommandline == neededCommandline
|
||||
&& currentAppInfoId.startsWith(qsl("userapp-"))) {
|
||||
g_app_info_delete(currentRegisteredAppInfo);
|
||||
}
|
||||
}
|
||||
|
||||
if (registeredAppInfoList) {
|
||||
g_list_free_full(registeredAppInfoList, g_object_unref);
|
||||
}
|
||||
|
||||
auto newAppInfo = g_app_info_create_from_commandline(
|
||||
actualCommandlineBuilder.toUtf8(),
|
||||
neededCommandlineBuilder.toUtf8(),
|
||||
AppName.utf8(),
|
||||
G_APP_INFO_CREATE_SUPPORTS_URIS,
|
||||
&error);
|
||||
|
||||
@@ -42,7 +42,6 @@ QString GetIconName();
|
||||
inline void IgnoreApplicationActivationRightNow() {
|
||||
}
|
||||
|
||||
void SetTrayIconSupported(bool supported);
|
||||
void InstallMainDesktopFile();
|
||||
|
||||
} // namespace Platform
|
||||
|
||||
@@ -35,8 +35,29 @@ bool IsCompositionEnabled() {
|
||||
return success && result;
|
||||
}
|
||||
|
||||
bool IsTaskbarAutoHidden(PUINT pEdge = nullptr) {
|
||||
HWND hTaskbar = FindWindowW(L"Shell_TrayWnd", nullptr);
|
||||
HWND FindTaskbarWindow(LPRECT rcMon = nullptr) {
|
||||
HWND hTaskbar = nullptr;
|
||||
RECT rcTaskbar, rcMatch;
|
||||
|
||||
while ((hTaskbar = FindWindowEx(
|
||||
nullptr,
|
||||
hTaskbar,
|
||||
L"Shell_TrayWnd",
|
||||
nullptr)) != nullptr) {
|
||||
if (!rcMon) {
|
||||
break; // OK, return first found
|
||||
}
|
||||
if (GetWindowRect(hTaskbar, &rcTaskbar)
|
||||
&& IntersectRect(&rcMatch, &rcTaskbar, rcMon)) {
|
||||
break; // OK, taskbar match monitor
|
||||
}
|
||||
}
|
||||
|
||||
return hTaskbar;
|
||||
}
|
||||
|
||||
bool IsTaskbarAutoHidden(LPRECT rcMon = nullptr, PUINT pEdge = nullptr) {
|
||||
HWND hTaskbar = FindTaskbarWindow(rcMon);
|
||||
if (!hTaskbar) {
|
||||
if (pEdge) {
|
||||
*pEdge = (UINT)-1;
|
||||
@@ -134,7 +155,7 @@ bool EventFilter::customWindowFrameEvent(
|
||||
if (GetMonitorInfo(hMonitor, &mi)) {
|
||||
*r = mi.rcWork;
|
||||
UINT uEdge = (UINT)-1;
|
||||
if (IsTaskbarAutoHidden(&uEdge)) {
|
||||
if (IsTaskbarAutoHidden(&mi.rcMonitor, &uEdge)) {
|
||||
switch (uEdge) {
|
||||
case ABE_LEFT: r->left += 1; break;
|
||||
case ABE_RIGHT: r->right -= 1; break;
|
||||
|
||||
@@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/platform/ui_platform_utility.h"
|
||||
#include "history/history.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "window/window_title_qt.h" // kShowAfterWindowFlagChangeDelay
|
||||
#include "window/window_session_controller.h"
|
||||
#include "window/window_lock_widgets.h"
|
||||
#include "window/window_outdated_bar.h"
|
||||
@@ -363,6 +364,21 @@ void MainWindow::refreshTitleWidget() {
|
||||
_title->init();
|
||||
_titleShadow.destroy();
|
||||
}
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
// setWindowFlag calls setParent(parentWidget(), newFlags), which
|
||||
// always calls hide() explicitly, we have to show() the window back.
|
||||
const auto hidden = isHidden();
|
||||
const auto withShadow = hasShadow();
|
||||
setWindowFlag(Qt::NoDropShadowWindowHint, withShadow);
|
||||
setAttribute(Qt::WA_OpaquePaintEvent, !withShadow);
|
||||
if (!hidden) {
|
||||
base::call_delayed(
|
||||
kShowAfterWindowFlagChangeDelay,
|
||||
this,
|
||||
[=] { show(); });
|
||||
}
|
||||
#endif // Q_OS_LINUX
|
||||
}
|
||||
|
||||
void MainWindow::updateMinimumSize() {
|
||||
@@ -377,12 +393,6 @@ void MainWindow::updateShadowSize() {
|
||||
}
|
||||
|
||||
void MainWindow::recountGeometryConstraints() {
|
||||
#ifdef Q_OS_LINUX
|
||||
const auto hasShadow = this->hasShadow();
|
||||
setWindowFlag(Qt::NoDropShadowWindowHint, hasShadow);
|
||||
setAttribute(Qt::WA_OpaquePaintEvent, !hasShadow);
|
||||
#endif // Q_OS_LINUX
|
||||
|
||||
updateShadowSize();
|
||||
updateMinimumSize();
|
||||
updateControlsGeometry();
|
||||
|
||||
@@ -24,13 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Window {
|
||||
namespace {
|
||||
|
||||
// If we toggle frameless window hint in maximized window, and
|
||||
// show it back too quickly, the mouse position inside the window
|
||||
// won't be correct (from Qt-s point of view) until we Alt-Tab from
|
||||
// that window. If we show the window back with this delay it works.
|
||||
constexpr auto kShowAfterFramelessToggleDelay = crl::time(1000);
|
||||
|
||||
style::margins ShadowExtents() {
|
||||
[[nodiscard]] style::margins ShadowExtents() {
|
||||
return st::callShadow.extend;
|
||||
}
|
||||
|
||||
@@ -103,7 +97,7 @@ void TitleWidgetQt::toggleFramelessWindow(bool enabled) {
|
||||
top->setWindowFlag(Qt::FramelessWindowHint, enabled);
|
||||
if (!hidden) {
|
||||
base::call_delayed(
|
||||
kShowAfterFramelessToggleDelay,
|
||||
kShowAfterWindowFlagChangeDelay,
|
||||
top,
|
||||
[=] { top->show(); });
|
||||
}
|
||||
|
||||
@@ -22,6 +22,12 @@ class PlainShadow;
|
||||
|
||||
namespace Window {
|
||||
|
||||
// If we toggle frameless window hint in maximized window, and
|
||||
// show it back too quickly, the mouse position inside the window
|
||||
// won't be correct (from Qt-s point of view) until we Alt-Tab from
|
||||
// that window. If we show the window back with this delay it works.
|
||||
inline constexpr auto kShowAfterWindowFlagChangeDelay = crl::time(1000);
|
||||
|
||||
class TitleWidgetQt : public TitleWidget {
|
||||
public:
|
||||
TitleWidgetQt(QWidget *parent);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
AppVersion 2004001
|
||||
AppVersion 2004003
|
||||
AppVersionStrMajor 2.4
|
||||
AppVersionStrSmall 2.4.1
|
||||
AppVersionStr 2.4.1
|
||||
AppVersionStrSmall 2.4.3
|
||||
AppVersionStr 2.4.3
|
||||
BetaChannel 0
|
||||
AlphaVersion 0
|
||||
AppVersionOriginal 2.4.1
|
||||
AppVersionOriginal 2.4.3
|
||||
|
||||
@@ -827,7 +827,7 @@ if (NOT TGVOIP_FOUND)
|
||||
|
||||
if (LINUX)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(ALSA REQUIRED alsa)
|
||||
find_package(ALSA REQUIRED)
|
||||
pkg_check_modules(PULSE REQUIRED libpulse)
|
||||
|
||||
target_include_directories(lib_tgvoip_bundled
|
||||
|
||||
Submodule Telegram/lib_ui updated: 430d96dcd5...ae340a0b76
@@ -1,3 +1,15 @@
|
||||
2.4.3 (07.10.20)
|
||||
|
||||
- Fix sending voice messages in scheduled messages section.
|
||||
- Fix deleting profile / group / channel photos.
|
||||
- Several crash fixes.
|
||||
|
||||
2.4.2 (02.10.20)
|
||||
|
||||
- Allow block, report and delete all message from user from "user joined" service message context menu.
|
||||
- Fix admin badge display in groups.
|
||||
- Fix loading and opening of comments in channels.
|
||||
|
||||
2.4.1 (01.10.20)
|
||||
|
||||
- Move by PageUp and PageDown in channel comments.
|
||||
|
||||
@@ -29,7 +29,7 @@ apps:
|
||||
- desktop-legacy
|
||||
- home
|
||||
- network
|
||||
- network-manager
|
||||
- network-manager-observe
|
||||
- opengl
|
||||
- pulseaudio
|
||||
- removable-media
|
||||
|
||||
Reference in New Issue
Block a user