Compare commits

..

38 Commits

Author SHA1 Message Date
John Preston
744eccc51e Version 2.4.3: Fix build for OS X 10.10-10.11. 2020-10-07 18:18:58 +03:00
Ilya Fedin
ce49714533 Use FindALSA instead of pkg-config 2020-10-07 17:10:27 +03:00
John Preston
ae2c858dc9 Version 2.4.3: Update lib_ui submodule. 2020-10-07 15:10:31 +03:00
John Preston
f0b5dc42f9 Version 2.4.3.
- Fix sending voice messages in scheduled messages section.
- Fix deleting profile / group / channel photos.
- Several crash fixes.
2020-10-07 15:08:52 +03:00
John Preston
9c213bf1c0 Warn when launching .sh on Windows.
Fixes #8753.
2020-10-07 14:41:21 +03:00
John Preston
0c1175f9cd Fix broadcast field placeholder update. 2020-10-07 14:41:21 +03:00
23rd
0c1312419a Fixed crash when user schedules message with elapsed date.
Fixed #8764.
2020-10-07 14:30:29 +03:00
23rd
7e9695b213 Added missed *.mov extension to dialog files filter for album items. 2020-10-07 13:09:15 +03:00
Ilya Fedin
093fcc3821 Subscribe to StatusNotifierHostRegistered signal 2020-10-07 13:06:06 +03:00
Ilya Fedin
6f89598a7b Clean old attempts to register url scheme on scheme registration 2020-10-07 12:55:34 +03:00
John Preston
6ccd53689d Fix crash in shared media search message delete.
Fixes #8237.
2020-10-06 14:20:49 +03:00
John Preston
cd506dfff5 Fix reply_to_top_id in local sent stickers.
Fixes #8758.
2020-10-06 14:01:19 +03:00
John Preston
5a3733b5b6 Fix selecting stickers in Replies section. 2020-10-06 13:46:19 +03:00
John Preston
22a85016e3 Show rank in anonymous outgoing messages. 2020-10-06 10:23:58 +03:00
John Preston
26c7a95a9f Use network-manager-observe in snap version. 2020-10-06 10:15:22 +03:00
John Preston
9acf617c9f Show full cached song as downloaded. 2020-10-06 10:10:22 +03:00
John Preston
72af170484 Force call panel to be a separate window.
I hope this fixes #8715.
2020-10-05 18:30:08 +03:00
John Preston
4db2505f5d Fix deleting profile photos.
Fixes #8720.
2020-10-05 18:26:29 +03:00
23rd
4d40336be0 Fixed voice recording cancel. 2020-10-05 17:08:52 +03:00
John Preston
616531b0d0 Fix author signature in discussion posts. 2020-10-05 16:21:34 +03:00
John Preston
473803edb8 Fix comments button getState / remove. 2020-10-05 16:21:34 +03:00
Ilya Fedin
a33ca97298 Find taskbar window on the same monitor 2020-10-05 13:50:03 +03:00
John Preston
a711c89409 Fix crash on wrong server response.
Fixes #8724.
2020-10-05 12:58:12 +03:00
John Preston
24ec0e0866 Fix recording stop in voice messages. 2020-10-05 12:58:12 +03:00
John Preston
e6df927e30 Correctly use alcGetIntegerv. 2020-10-05 12:58:12 +03:00
Ilya Fedin
638ea3111f Fallback to D-Bus methods if XCB-based LastUserInputTime failed 2020-10-05 10:10:40 +03:00
John Preston
983d9e6eee Version 2.4.2.
- Allow block, report and delete all message from user
in "user joined" service message context menu.
- Fix admin badge display in groups.
- Fix loading and opening of comments in channels.
2020-10-02 19:32:20 +03:00
John Preston
4b6d74dd9b Fix opening Replies section on unread bar. 2020-10-02 19:29:29 +03:00
23rd
8d70a62ee8 Fixed crash in OverlayWidget when user opens attached stickers.
Fixed #8710.
2020-10-02 19:29:29 +03:00
Ilya Fedin
a0af748fc5 Update SNI state even if tray is deactivated 2020-10-02 19:19:16 +03:00
John Preston
f10ef26226 Fix message right badge refresh.
Fixes #8669.
2020-10-02 17:46:27 +03:00
John Preston
4ebc62afd2 Fix build on Linux. 2020-10-02 17:29:28 +03:00
John Preston
18cb26fed6 Change flags / attributes when changing window frame. 2020-10-02 16:17:53 +03:00
John Preston
d965385356 Fix loading comments. 2020-10-02 16:10:50 +03:00
Ilya Fedin
5cc4066b65 Don't change window flags in Window::MainWindow::recountGeometryConstraints 2020-10-02 16:10:38 +03:00
John Preston
6b084301be Allow delete all from service message. 2020-10-02 16:02:09 +03:00
23rd
498e82b804 Added ability to scroll to replying message on reply header click. 2020-10-02 15:57:17 +03:00
John Preston
8c224f7aca Allow block & report from service message. 2020-10-02 15:52:26 +03:00
40 changed files with 545 additions and 288 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -293,6 +293,8 @@ public:
}
virtual void setReplyToTop(MsgId replyToTop) {
}
virtual void setPostAuthor(const QString &author) {
}
virtual void setRealId(MsgId newId);
virtual void incrementReplyToTopCounter() {
}

View File

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

View File

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

View File

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

View File

@@ -294,8 +294,6 @@ signals:
public slots:
void onScroll();
void onBroadcastSilentChange();
void activate();
void onTextChange();

View File

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

View File

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

View File

@@ -305,7 +305,7 @@ private:
using CursorState = HistoryView::CursorState;
void refreshViewer();
void updateAroundPositionFromRows();
void updateAroundPositionFromNearest(int nearestIndex);
void refreshRows();
ScrollTopState countScrollState() const;
void saveScrollState();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -42,7 +42,6 @@ QString GetIconName();
inline void IgnoreApplicationActivationRightNow() {
}
void SetTrayIconSupported(bool supported);
void InstallMainDesktopFile();
} // namespace Platform

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -29,7 +29,7 @@ apps:
- desktop-legacy
- home
- network
- network-manager
- network-manager-observe
- opengl
- pulseaudio
- removable-media