Compare commits

..

34 Commits

Author SHA1 Message Date
John Preston
9717a8b5fa Version 2.4.4.
- Fix application quit on call end with main window hidden in tray.
- Update OpenAL library on Windows.
- Several crash fixes.
2020-10-23 19:40:48 +03:00
John Preston
aff4f69b64 Don't quit on call end with window hidden in tray.
Fixes #8585.
2020-10-23 19:37:58 +03:00
John Preston
9de4c42555 Keep sending typings up to 30s after offline. 2020-10-23 18:25:55 +03:00
John Preston
1de144a48d Show transfer ownership button for non-anonymous admins. 2020-10-23 17:37:27 +03:00
John Preston
0690d14f1b Don't send typings to bots and offline users. 2020-10-23 17:28:11 +03:00
John Preston
53ac4c00ad Track deleted messages carefully.
Fixes #8855.
2020-10-23 16:35:43 +03:00
John Preston
f064692e57 Close media viewer when photo message is deleted. 2020-10-23 15:28:20 +03:00
John Preston
3d54a263b8 Stop playing documents when items are deleted. 2020-10-23 15:22:38 +03:00
23rd
47bb8ec687 Added Github Action that updates user-agent for DNS. 2020-10-23 15:13:20 +03:00
23rd
3a2b772a5d Added spellchecker to Replies / Scheduled messages sections.
Fixed #8793.
2020-10-23 13:32:44 +03:00
23rd
bc8f8bc68c Added auto-closing to some boxes which depend on certain message. 2020-10-23 13:32:44 +03:00
23rd
bc7975ece7 Fixed crash when user reschedules already sent message.
Fixed #8867.
2020-10-23 13:32:43 +03:00
23rd
52cca98144 Fixed replies button display in section of scheduled messages. 2020-10-23 13:32:43 +03:00
23rd
5540b0bb8b Fixed glitch for scheduled messages with elapsed date in channels. 2020-10-23 13:32:32 +03:00
23rd
7de9bcad03 Added ability to open contacts with shortcut.
Fixed #8775.
2020-10-23 13:31:24 +03:00
23rd
367b028094 Moved contacts box preparing to single place. 2020-10-23 13:31:24 +03:00
John Preston
8b27aa5331 Update cmake_helpers submodule. 2020-10-23 13:11:42 +03:00
John Preston
9697567b8d Add some more open file warnings. 2020-10-23 13:10:43 +03:00
Ilya Fedin
1fdfa94497 Remove explicit Opus clone step from macos action
Since no longer needed
2020-10-23 12:51:52 +03:00
John Preston
1373bd0af1 Use OpenAL 1.20.1 with bugfix backport on Windows. 2020-10-23 12:47:41 +03:00
Ilya Fedin
4f2b0531f8 Replace GDBusProxy with GDBusConnection in NotificationData 2020-10-23 11:29:35 +03:00
Ilya Fedin
ca67ac913f Check for KDE portal backend when using portals on KDE 2020-10-23 11:28:18 +03:00
Ilya Fedin
4033a091b5 Hide mark as read button in notifications when app is pass-code locked 2020-10-23 11:25:18 +03:00
Ilya Fedin
0179a2ca10 Rename InstallMainDesktopFile to InstallLauncher 2020-10-23 11:25:18 +03:00
Ilya Fedin
f58874572d Check actual socket path length rather than InSnap/InFlatpak 2020-10-23 11:25:18 +03:00
Ilya Fedin
143b9682a4 Get rid of lxqt-qtplugin
It is stil impossible to build it statically and it seems that reading icon theme from gtk is pretty enough
2020-10-23 11:24:37 +03:00
John Preston
00c962e557 Bump cmake_helpers submodule. 2020-10-23 11:24:02 +03:00
John Preston
1cabfaa6a4 Fix cancel / crash in sending album to scheduled messages.
Fixes #8788
2020-10-23 11:22:38 +03:00
Ilya Fedin
b788ae0ae4 Add stale bot configuration 2020-10-23 11:18:14 +03:00
Ilya Fedin
3f6399f13d Log getting GTK settings 2020-10-21 10:57:40 +03:00
Ilya Fedin
b6fc418d32 01org/libva -> intel/libva 2020-10-20 09:37:56 +03:00
Ilya Fedin
245d644cd7 Add always on top hint for media view window
To avoid overlapping by panels in KDE
2020-10-20 09:37:31 +03:00
Ilya Fedin
2aa0b674cd Use new XCB methods from lib_base 2020-10-16 16:12:38 +03:00
Ilya Fedin
654784ce9f Use external_xcb and external_glib 2020-10-16 16:12:38 +03:00
61 changed files with 616 additions and 405 deletions

21
.github/stale.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels: []
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: |
Hey there!
This issue will be automatically closed in 7 days if there would be no activity. We therefore assume that the user has lost interest or resolved the problem on their own.
Don't worry though; if this is an error, let us know with a comment and we'll be happy to reopen the issue.
Thanks!
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
# Process only issues
only: issues

View File

@@ -182,7 +182,7 @@ jobs:
run: |
cd $LibrariesPath
git clone $GIT/01org/libva.git
git clone $GIT/intel/libva.git
cd libva
./autogen.sh --enable-static
make -j$(nproc)

View File

@@ -169,17 +169,14 @@ jobs:
with:
path: ${{ env.LibrariesPath }}/opus-cache
key: ${{ runner.OS }}-opus-${{ env.CACHE_KEY }}
- name: Opus clone.
run: |
cd $LibrariesPath
git clone -b v1.3 --depth=1 $GIT/xiph/opus
- name: Opus build.
- name: Opus.
if: steps.cache-opus.outputs.cache-hit != 'true'
run: |
cd $LibrariesPath
git clone $GIT/xiph/opus
cd opus
git checkout v1.3
./autogen.sh
CFLAGS="$MIN_MAC $UNGUARDED" CPPFLAGS="$MIN_MAC $UNGUARDED" LDFLAGS="$MIN_MAC" ./configure --prefix=$PREFIX
make -j$(nproc)

View File

@@ -0,0 +1,90 @@
name: User-agent updater.
on:
repository_dispatch:
types: ["Restart user_agent_updater workflow."]
schedule:
# At 00:00 on day-of-month 1.
- cron: '0 0 1 * *'
jobs:
User-agent:
runs-on: ubuntu-latest
env:
code_file: "Telegram/SourceFiles/mtproto/details/mtproto_domain_resolver.cpp"
skip: "0"
steps:
- name: Clone.
if: env.skip == '0'
uses: actions/checkout@v2
- name: Write a new version of Google Chrome to the user-agent for DNS.
if: env.skip == '0'
shell: python
run: |
import subprocess, os, re;
regExpVersion = "[0-9]+.[0-9]+.[0-9]+.[0-9]+";
chrome = "Chrome/";
def newVersion():
output = subprocess.check_output(["google-chrome", "--version"]);
version = re.search(regExpVersion, output);
if not version:
print("Can't find a Chrome version.");
exit();
return version.group(0);
newChromeVersion = newVersion();
print(newChromeVersion);
def writeUserAgent():
p = os.environ['code_file'];
w = open(p, "r");
content = w.read();
w.close();
regExpChrome = chrome + regExpVersion;
version = re.search(regExpChrome, content);
if not version:
print("Can't find an user-agent in the code.");
exit();
content = re.sub(regExpChrome, chrome + newChromeVersion, content);
w = open(p, "w");
w.write(content);
print("::set-env name=ChromeVersion::" + newChromeVersion);
writeUserAgent();
- name: Push to the current branch.
if: env.skip == '0' && env.ChromeVersion != ''
run: |
token=${{ secrets.TOKEN_FOR_MASTER_UPDATER }}
if [ -z "${token}" ]; then
echo "Token is unset. Nothing to do."
exit 0
fi
url=https://x-access-token:$token@github.com/$GITHUB_REPOSITORY
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git diff > git_diff.txt
if [[ ! -s git_diff.txt ]]; then
echo "Nothing to commit."
exit 0
fi
git add $code_file
git commit -m "Update User-Agent for DNS to Chrome $ChromeVersion."
git remote set-url origin $url
git push origin HEAD:$GITHUB_REF
echo "Done!"

6
.gitmodules vendored
View File

@@ -82,12 +82,6 @@
[submodule "Telegram/ThirdParty/qt5ct"]
path = Telegram/ThirdParty/qt5ct
url = https://github.com/desktop-app/qt5ct.git
[submodule "Telegram/ThirdParty/lxqt-qtplugin"]
path = Telegram/ThirdParty/lxqt-qtplugin
url = https://github.com/lxqt/lxqt-qtplugin.git
[submodule "Telegram/ThirdParty/libqtxdg"]
path = Telegram/ThirdParty/libqtxdg
url = https://github.com/lxqt/libqtxdg.git
[submodule "Telegram/ThirdParty/fcitx5-qt"]
path = Telegram/ThirdParty/fcitx5-qt
url = https://github.com/fcitx/fcitx5-qt.git

View File

@@ -106,17 +106,12 @@ if (LINUX)
desktop-app::external_materialdecoration
desktop-app::external_nimf_qt5
desktop-app::external_qt5ct_support
desktop-app::external_xcb_screensaver
desktop-app::external_xcb
desktop-app::external_glib
)
if (NOT DESKTOP_APP_DISABLE_DBUS_INTEGRATION)
# conflicts with Qt static link
if (DESKTOP_APP_USE_PACKAGED_LAZY_PLATFORMTHEMES)
target_link_libraries(Telegram
PRIVATE
desktop-app::external_lxqt_qtplugin
)
endif()
target_link_libraries(Telegram
PRIVATE
desktop-app::external_statusnotifieritem
@@ -137,35 +132,6 @@ if (LINUX)
)
endif()
if (DESKTOP_APP_USE_PACKAGED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(XCB_SCREENSAVER REQUIRED IMPORTED_TARGET xcb-screensaver)
pkg_check_modules(XCB REQUIRED IMPORTED_TARGET xcb)
target_link_libraries(Telegram
PRIVATE
PkgConfig::XCB_SCREENSAVER
PkgConfig::XCB
)
else()
target_link_static_libraries(Telegram PRIVATE xcb-screensaver)
target_link_libraries(Telegram PRIVATE xcb)
endif()
find_package(PkgConfig REQUIRED)
pkg_check_modules(GLIB2 REQUIRED IMPORTED_TARGET glib-2.0)
pkg_check_modules(GOBJECT REQUIRED IMPORTED_TARGET gobject-2.0)
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
target_link_libraries(Telegram
PRIVATE
PkgConfig::GLIB2
PkgConfig::GOBJECT
PkgConfig::GIO
)
target_compile_definitions(Telegram PRIVATE G_LOG_DOMAIN="Telegram")
if (NOT TDESKTOP_DISABLE_GTK_INTEGRATION)
find_package(PkgConfig REQUIRED)
@@ -1290,6 +1256,7 @@ target_compile_definitions(Telegram
PRIVATE
TDESKTOP_API_ID=${TDESKTOP_API_ID}
TDESKTOP_API_HASH=${TDESKTOP_API_HASH}
G_LOG_DOMAIN="Telegram"
)
if (APPLE OR NOT CMAKE_EXECUTABLE_SUFFIX STREQUAL "" OR NOT "${output_name}" STREQUAL "Telegram")

View File

@@ -2271,6 +2271,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_language_not_ready_link" = "translations platform";
"lng_launch_exe_warning" = "This file has a {extension} extension.\nAre you sure you want to run it?";
"lng_launch_svg_warning" = "Opening this file can potentially expose your IP address to its sender. Continue?";
"lng_launch_exe_sure" = "Run";
"lng_launch_exe_dont_ask" = "Don't ask me again";

View File

@@ -9,7 +9,7 @@
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
ProcessorArchitecture="ARCHITECTURE"
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
Version="2.4.3.0" />
Version="2.4.4.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,3,0
PRODUCTVERSION 2,4,3,0
FILEVERSION 2,4,4,0
PRODUCTVERSION 2,4,4,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.3.0"
VALUE "FileVersion", "2.4.4.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2020"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "2.4.3.0"
VALUE "ProductVersion", "2.4.4.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,4,3,0
PRODUCTVERSION 2,4,3,0
FILEVERSION 2,4,4,0
PRODUCTVERSION 2,4,4,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.3.0"
VALUE "FileVersion", "2.4.4.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2020"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "2.4.3.0"
VALUE "ProductVersion", "2.4.4.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -10,6 +10,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h"
#include "history/history.h"
#include "data/data_peer.h"
#include "data/data_user.h"
#include "base/unixtime.h"
#include "data/data_peer_values.h"
#include "apiwrap.h"
namespace Api {
@@ -17,6 +20,7 @@ namespace {
constexpr auto kCancelTypingActionTimeout = crl::time(5000);
constexpr auto kSetMyActionForMs = 10 * crl::time(1000);
constexpr auto kSendTypingsToOfflineFor = TimeId(30);
} // namespace
@@ -98,6 +102,9 @@ bool SendProgressManager::updated(const Key &key, bool doing) {
}
void SendProgressManager::send(const Key &key, int progress) {
if (skipRequest(key)) {
return;
}
using Type = SendProgressType;
const auto action = [&]() -> MTPsendMessageAction {
const auto p = MTP_int(progress);
@@ -135,6 +142,19 @@ void SendProgressManager::send(const Key &key, int progress) {
}
}
bool SendProgressManager::skipRequest(const Key &key) const {
const auto user = key.history->peer->asUser();
if (!user) {
return false;
} else if (user->isSelf()) {
return true;
} else if (user->isBot() && !user->isSupport()) {
return true;
}
const auto recently = base::unixtime::now() - kSendTypingsToOfflineFor;
return !Data::OnlineTextActive(user->onlineTill, recently);
}
void SendProgressManager::done(
const MTPBool &result,
mtpRequestId requestId) {

View File

@@ -90,6 +90,8 @@ private:
void send(const Key &key, int progress);
void done(const MTPBool &result, mtpRequestId requestId);
[[nodiscard]] bool skipRequest(const Key &key) const;
const not_null<Main::Session*> _session;
base::flat_map<Key, mtpRequestId> _requests;
base::flat_map<Key, crl::time> _updated;

View File

@@ -63,6 +63,22 @@ enum class DataIsLoadedResult {
Ok = 3,
};
void ProcessScheduledMessageWithElapsedTime(
not_null<Main::Session*> session,
bool needToAdd,
const MTPDmessage &data) {
if (needToAdd && !data.is_from_scheduled()) {
// If we still need to add a new message,
// we should first check if this message is in
// the list of scheduled messages.
// This is necessary to correctly update the file reference.
// Note that when a message is scheduled until online
// while the recipient is already online, the server sends
// an ordinary new message with skipped "from_scheduled" flag.
session->data().scheduledMessages().checkEntitiesAndUpdate(data);
}
}
bool IsForceLogoutNotification(const MTPDupdateServiceNotification &data) {
return qs(data.vtype()).startsWith(qstr("AUTH_KEY_DROP_"));
}
@@ -958,17 +974,7 @@ void Updates::applyUpdateNoPtsCheck(const MTPUpdate &update) {
LOG(("Skipping message, because it is already in blocks!"));
needToAdd = false;
}
if (needToAdd && !data.is_from_scheduled()) {
// If we still need to add a new message,
// we should first check if this message is in
// the list of scheduled messages.
// This is necessary to correctly update the file reference.
// Note that when a message is scheduled until online
// while the recipient is already online, the server sends
// an ordinary new message with skipped "from_scheduled" flag.
_session->data().scheduledMessages().checkEntitiesAndUpdate(
data);
}
ProcessScheduledMessageWithElapsedTime(_session, needToAdd, data);
}
if (needToAdd) {
_session->data().addNewMessage(
@@ -1057,10 +1063,12 @@ void Updates::applyUpdateNoPtsCheck(const MTPUpdate &update) {
auto &d = update.c_updateNewChannelMessage();
auto needToAdd = true;
if (d.vmessage().type() == mtpc_message) { // index forwarded messages to links _overview
if (_session->data().checkEntitiesAndViewsUpdate(d.vmessage().c_message())) { // already in blocks
const auto &data = d.vmessage().c_message();
if (_session->data().checkEntitiesAndViewsUpdate(data)) { // already in blocks
LOG(("Skipping message, because it is already in blocks!"));
needToAdd = false;
}
ProcessScheduledMessageWithElapsedTime(_session, needToAdd, data);
}
if (needToAdd) {
_session->data().addNewMessage(

View File

@@ -363,6 +363,12 @@ EditCaptionBox::EditCaptionBox(
) | rpl::start_with_next([&](bool checked) {
_asFile = checked;
}, _wayWrap->lifetime());
_controller->session().data().itemRemoved(
_msgId
) | rpl::start_with_next([=] {
closeBox();
}, lifetime());
}
EditCaptionBox::~EditCaptionBox() = default;

View File

@@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_histories.h"
#include "apiwrap.h"
#include "mainwidget.h"
#include "mainwindow.h"
#include "lang/lang_keys.h"
#include "history/history.h"
#include "dialogs/dialogs_main_list.h"
@@ -104,6 +105,20 @@ void AddBotToGroup(not_null<UserData*> bot, not_null<PeerData*> chat) {
// return mapFromGlobal(QCursor::pos()) - _st.rippleAreaPosition;
//}
object_ptr<Ui::BoxContent> PrepareContactsBox(
not_null<Window::SessionController*> sessionController) {
const auto controller = sessionController;
auto delegate = [=](not_null<PeerListBox*> box) {
box->addButton(tr::lng_close(), [=] { box->closeBox(); });
box->addLeftButton(
tr::lng_profile_add_contact(),
[=] { controller->widget()->onShowAddContact(); });
};
return Box<PeerListBox>(
std::make_unique<ContactsBoxController>(controller),
std::move(delegate));
}
void PeerListRowWithLink::setActionLink(const QString &action) {
_action = action;
refreshActionLink();

View File

@@ -31,9 +31,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class History;
namespace Window {
class SessionController;
class SessionNavigation;
} // namespace Window
[[nodiscard]] object_ptr<Ui::BoxContent> PrepareContactsBox(
not_null<Window::SessionController*> sessionController);
class PeerListRowWithLink : public PeerListRow {
public:
using PeerListRow::PeerListRow;

View File

@@ -308,7 +308,7 @@ void EditAdminBox::prepare() {
}, lifetime());
if (canTransferOwnership()) {
const auto allFlags = FullAdminRights(isGroup);
const auto allFlags = AdminRightsForOwnershipTransfer(isGroup);
setupTransferButton(
isGroup
)->toggleOn(rpl::duplicate(

View File

@@ -298,10 +298,12 @@ ChatRestrictions FixDependentRestrictions(ChatRestrictions restrictions) {
return restrictions;
}
ChatAdminRights FullAdminRights(bool isGroup) {
ChatAdminRights AdminRightsForOwnershipTransfer(bool isGroup) {
auto result = ChatAdminRights();
for (const auto &[flag, label] : AdminRightLabels(isGroup, true)) {
result |= flag;
if (!(flag & ChatAdminRight::f_anonymous)) {
result |= flag;
}
}
return result;
}

View File

@@ -71,4 +71,4 @@ EditFlagsControl<MTPDchatAdminRights::Flags> CreateEditAdminRights(
ChatAdminRights DisabledByDefaultRestrictions(not_null<PeerData*> peer);
ChatRestrictions FixDependentRestrictions(ChatRestrictions restrictions);
ChatAdminRights FullAdminRights(bool isGroup);
ChatAdminRights AdminRightsForOwnershipTransfer(bool isGroup);

View File

@@ -109,7 +109,8 @@ QByteArray Settings::serialize() const {
<< qint32(_notifyFromAll ? 1 : 0)
<< qint32(_nativeWindowFrame.current() ? 1 : 0)
<< qint32(_systemDarkModeEnabled.current() ? 1 : 0)
<< _callVideoInputDeviceId;
<< _callVideoInputDeviceId
<< qint32(_ipRevealWarning ? 1 : 0);
}
return result;
}
@@ -176,6 +177,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
qint32 notifyFromAll = _notifyFromAll ? 1 : 0;
qint32 nativeWindowFrame = _nativeWindowFrame.current() ? 1 : 0;
qint32 systemDarkModeEnabled = _systemDarkModeEnabled.current() ? 1 : 0;
qint32 ipRevealWarning = _ipRevealWarning ? 1 : 0;
stream >> themesAccentColors;
if (!stream.atEnd()) {
@@ -259,6 +261,9 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
if (!stream.atEnd()) {
stream >> callVideoInputDeviceId;
}
if (!stream.atEnd()) {
stream >> ipRevealWarning;
}
if (stream.status() != QDataStream::Ok) {
LOG(("App Error: "
"Bad data for Core::Settings::constructFromSerialized()"));
@@ -318,6 +323,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
_includeMutedCounter = (includeMutedCounter == 1);
_countUnreadMessages = (countUnreadMessages == 1);
_exeLaunchWarning = (exeLaunchWarning == 1);
_ipRevealWarning = (ipRevealWarning == 1);
_notifyAboutPinned = (notifyAboutPinned == 1);
_loopAnimatedStickers = (loopAnimatedStickers == 1);
_largeEmoji = (largeEmoji == 1);
@@ -468,6 +474,7 @@ void Settings::resetOnLastLogout() {
_soundOverrides = {};
_exeLaunchWarning = true;
_ipRevealWarning = true;
_loopAnimatedStickers = true;
_largeEmoji = true;
_replaceEmoji = true;

View File

@@ -255,6 +255,12 @@ public:
void setExeLaunchWarning(bool warning) {
_exeLaunchWarning = warning;
}
[[nodiscard]] bool ipRevealWarning() const {
return _ipRevealWarning;
}
void setIpRevealWarning(bool warning) {
_ipRevealWarning = warning;
}
[[nodiscard]] bool loopAnimatedStickers() const {
return _loopAnimatedStickers;
}
@@ -513,6 +519,7 @@ private:
Ui::InputSubmitSettings _sendSubmitWay;
base::flat_map<QString, QString> _soundOverrides;
bool _exeLaunchWarning = true;
bool _ipRevealWarning = true;
bool _loopAnimatedStickers = true;
rpl::variable<bool> _largeEmoji = true;
rpl::variable<bool> _replaceEmoji = true;

View File

@@ -90,6 +90,7 @@ Sandbox::Sandbox(
}
})
, _launcher(launcher) {
setQuitOnLastWindowClosed(false);
}
int Sandbox::start() {

View File

@@ -88,6 +88,7 @@ const auto CommandByName = base::flat_map<QString, Command>{
{ qsl("last_folder") , Command::ShowFolderLast },
{ qsl("show_archive") , Command::ShowArchive },
{ qsl("show_contacts") , Command::ShowContacts },
{ qsl("read_chat") , Command::ReadChat },
@@ -132,6 +133,7 @@ const auto CommandNames = base::flat_map<Command, QString>{
{ Command::ShowFolderLast , qsl("last_folder") },
{ Command::ShowArchive , qsl("show_archive") },
{ Command::ShowContacts , qsl("show_contacts") },
{ Command::ReadChat , qsl("read_chat") },
};
@@ -383,6 +385,7 @@ void Manager::fillDefaults() {
set(qsl("ctrl+0"), Command::ChatSelf);
set(qsl("ctrl+9"), Command::ShowArchive);
set(qsl("ctrl+shift+n"), Command::ShowContacts);
set(qsl("ctrl+r"), Command::ReadChat);
}

View File

@@ -48,6 +48,7 @@ enum class Command {
FolderPrevious,
ShowArchive,
ShowContacts,
JustSendMessage,
SendSilentMessage,

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 = 2004003;
constexpr auto AppVersionStr = "2.4.3";
constexpr auto AppVersion = 2004004;
constexpr auto AppVersionStr = "2.4.4";
constexpr auto AppBetaVersion = false;
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;

View File

@@ -74,15 +74,15 @@ void LaunchWithWarning(
not_null<Main::Session*> session,
const QString &name,
HistoryItem *item) {
const auto isExecutable = Data::IsExecutableName(name);
const auto isIpReveal = Data::IsIpRevealingName(name);
auto &app = Core::App();
const auto warn = [&] {
if (!Data::IsExecutableName(name)) {
return false;
} else if (!Core::App().settings().exeLaunchWarning()) {
return false;
} else if (item && item->history()->peer->isVerified()) {
if (item && item->history()->peer->isVerified()) {
return false;
}
return true;
return (isExecutable && app.settings().exeLaunchWarning())
|| (isIpReveal && app.settings().ipRevealWarning());
}();
const auto extension = '.' + Data::FileExtension(name);
if (Platform::IsWindows() && extension == u"."_q) {
@@ -99,20 +99,27 @@ void LaunchWithWarning(
File::Launch(name);
return;
}
const auto callback = [=](bool checked) {
const auto callback = [=, &app](bool checked) {
if (checked) {
Core::App().settings().setExeLaunchWarning(false);
Core::App().saveSettingsDelayed();
if (isExecutable) {
app.settings().setExeLaunchWarning(false);
} else if (isIpReveal) {
app.settings().setIpRevealWarning(false);
}
app.saveSettingsDelayed();
}
File::Launch(name);
};
Ui::show(Box<ConfirmDontWarnBox>(
tr::lng_launch_exe_warning(
auto text = isExecutable
? tr::lng_launch_exe_warning(
lt_extension,
rpl::single(Ui::Text::Bold(extension)),
Ui::Text::WithEntities),
Ui::Text::WithEntities)
: tr::lng_launch_svg_warning(Ui::Text::WithEntities);
Ui::show(Box<ConfirmDontWarnBox>(
std::move(text),
tr::lng_launch_exe_dont_ask(tr::now),
tr::lng_launch_exe_sure(),
(isExecutable ? tr::lng_launch_exe_sure : tr::lng_continue)(),
callback));
}
@@ -1668,17 +1675,17 @@ mpkg pkg scpt scptd xhtm webarchive");
slp zsh");
#else // Q_OS_MAC || Q_OS_UNIX
qsl("\
ad ade adp app application appref-ms asp asx bas bat bin cdxml cer cfg chi \
chm cmd cnt com cpl crt csh der diagcab dll drv eml exe fon fxp gadget grp \
hlp hpj hta htt inf ini ins inx isp isu its jar jnlp job js jse ksh lnk \
local lua mad maf mag mam manifest maq mar mas mat mau mav maw mcf mda mdb \
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 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");
ad ade adp app application appref-ms asp asx bas bat bin cab cdxml cer cfg \
chi chm cmd cnt com cpl crt csh der diagcab dll drv eml exe fon fxp gadget \
grp hlp hpj hta htt inf ini ins inx isp isu its jar jnlp job js jse key ksh \
lnk local lua mad maf mag mam manifest maq mar mas mat mau mav maw mcf mda \
mdb 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 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
const auto list = joined.split(' ');
return base::flat_set<QString>(list.begin(), list.end());
@@ -1689,6 +1696,18 @@ website ws wsc wsf wsh xbap xll xnk xs");
FileExtension(filepath).toLower());
}
bool IsIpRevealingName(const QString &filepath) {
static const auto kExtensions = [] {
const auto joined = u"htm html svg"_q;
const auto list = joined.split(' ');
return base::flat_set<QString>(list.begin(), list.end());
}();
return ranges::binary_search(
kExtensions,
FileExtension(filepath).toLower());
}
base::binary_guard ReadImageAsync(
not_null<Data::DocumentMedia*> media,
FnMut<QImage(QImage)> postprocess,

View File

@@ -443,9 +443,10 @@ QString DocumentFileNameForSave(
namespace Data {
QString FileExtension(const QString &filepath);
bool IsValidMediaFile(const QString &filepath);
bool IsExecutableName(const QString &filepath);
[[nodiscard]] QString FileExtension(const QString &filepath);
[[nodiscard]] bool IsValidMediaFile(const QString &filepath);
[[nodiscard]] bool IsExecutableName(const QString &filepath);
[[nodiscard]] bool IsIpRevealingName(const QString &filepath);
base::binary_guard ReadImageAsync(
not_null<Data::DocumentMedia*> media,
FnMut<QImage(QImage)> postprocess,

View File

@@ -42,7 +42,10 @@ struct RepliesList::Viewer {
MsgId around = 0;
int limitBefore = 0;
int limitAfter = 0;
int injectedForRoot = 0;
base::has_weak_ptr guard;
bool stale = true;
bool scheduled = false;
};
RepliesList::RepliesList(not_null<History*> history, MsgId rootId)
@@ -67,7 +70,9 @@ rpl::producer<MessagesSlice> RepliesList::source(
_history->session().changes().historyFlagsValue(
_history,
Data::HistoryUpdate::Flag::LocalMessages)
) | rpl::map([=](MessagesSlice &&server, const auto &) {
) | rpl::filter([=](const MessagesSlice &data, const auto &) {
return (data.fullCount.value_or(0) >= 0);
}) | rpl::map([=](MessagesSlice &&server, const auto &) {
appendLocalMessages(server);
return std::move(server);
});
@@ -82,10 +87,22 @@ rpl::producer<MessagesSlice> RepliesList::sourceFromServer(
auto lifetime = rpl::lifetime();
const auto viewer = lifetime.make_state<Viewer>();
const auto push = [=] {
viewer->scheduled = false;
if (buildFromData(viewer)) {
viewer->stale = false;
consumer.put_next_copy(viewer->slice);
}
};
const auto pushDelayed = [=] {
if (!viewer->stale) {
viewer->stale = true;
consumer.put_next_copy(MessagesSlice{ .fullCount = -1 });
}
if (!viewer->scheduled) {
viewer->scheduled = true;
crl::on_main(&viewer->guard, push);
}
};
viewer->around = around;
viewer->limitBefore = limitBefore;
viewer->limitAfter = limitAfter;
@@ -96,14 +113,10 @@ rpl::producer<MessagesSlice> RepliesList::sourceFromServer(
| MessageUpdate::Flag::Destroyed
) | rpl::filter([=](const MessageUpdate &update) {
return applyUpdate(viewer, update);
}) | rpl::start_with_next([=] {
crl::on_main(&viewer->guard, push);
}, lifetime);
}) | rpl::start_with_next(pushDelayed, lifetime);
_partLoaded.events(
) | rpl::start_with_next([=] {
crl::on_main(&viewer->guard, push);
}, lifetime);
) | rpl::start_with_next(pushDelayed, lifetime);
push();
return lifetime;
@@ -173,32 +186,37 @@ rpl::producer<int> RepliesList::fullCount() const {
return _fullCount.value() | rpl::filter_optional();
}
void RepliesList::injectRootMessageAndReverse(
not_null<MessagesSlice*> slice) {
injectRootMessage(slice);
ranges::reverse(slice->ids);
void RepliesList::injectRootMessageAndReverse(not_null<Viewer*> viewer) {
injectRootMessage(viewer);
ranges::reverse(viewer->slice.ids);
}
void RepliesList::injectRootMessage(not_null<MessagesSlice*> slice) {
void RepliesList::injectRootMessage(not_null<Viewer*> viewer) {
const auto slice = &viewer->slice;
viewer->injectedForRoot = 0;
if (slice->skippedBefore != 0) {
return;
}
if (const auto root = lookupRoot()) {
injectRootDivider(root, slice);
const auto root = lookupRoot();
if (!root) {
return;
}
injectRootDivider(root, slice);
if (const auto group = _history->owner().groups().find(root)) {
for (const auto item : ranges::view::reverse(group->items)) {
slice->ids.push_back(item->fullId());
}
if (slice->fullCount) {
*slice->fullCount += group->items.size();
}
} else {
slice->ids.push_back(root->fullId());
if (slice->fullCount) {
++*slice->fullCount;
}
if (const auto group = _history->owner().groups().find(root)) {
for (const auto item : ranges::view::reverse(group->items)) {
slice->ids.push_back(item->fullId());
}
viewer->injectedForRoot = group->items.size();
if (slice->fullCount) {
*slice->fullCount += group->items.size();
}
} else {
slice->ids.push_back(root->fullId());
viewer->injectedForRoot = 1;
}
if (slice->fullCount) {
*slice->fullCount += viewer->injectedForRoot;
}
}
@@ -232,7 +250,8 @@ bool RepliesList::buildFromData(not_null<Viewer*> viewer) {
= viewer->slice.skippedBefore
= viewer->slice.skippedAfter
= 0;
injectRootMessageAndReverse(&viewer->slice);
viewer->injectedForRoot = 0;
injectRootMessageAndReverse(viewer);
return true;
}
const auto around = [&] {
@@ -285,7 +304,7 @@ bool RepliesList::buildFromData(not_null<Viewer*> viewer) {
slice->ids.empty() ? 0 : slice->ids.back().msg));
slice->fullCount = _fullCount.current();
injectRootMessageAndReverse(slice);
injectRootMessageAndReverse(viewer);
if (_skippedBefore != 0 && useBefore < viewer->limitBefore + 1) {
loadBefore();
@@ -301,10 +320,20 @@ bool RepliesList::applyUpdate(
not_null<Viewer*> viewer,
const MessageUpdate &update) {
if (update.item->history() != _history
|| update.item->replyToTop() != _rootId
|| !IsServerMsgId(update.item->id)) {
return false;
}
if (update.flags & MessageUpdate::Flag::Destroyed) {
const auto id = update.item->fullId();
for (auto i = 0; i != viewer->injectedForRoot; ++i) {
if (viewer->slice.ids[i] == id) {
return true;
}
}
}
if (update.item->replyToTop() != _rootId) {
return false;
}
const auto id = update.item->id;
const auto i = ranges::lower_bound(_list, id, std::greater<>());
if (update.flags & MessageUpdate::Flag::Destroyed) {

View File

@@ -47,8 +47,8 @@ private:
[[nodiscard]] bool applyUpdate(
not_null<Viewer*> viewer,
const MessageUpdate &update);
void injectRootMessageAndReverse(not_null<MessagesSlice*> slice);
void injectRootMessage(not_null<MessagesSlice*> slice);
void injectRootMessageAndReverse(not_null<Viewer*> viewer);
void injectRootMessage(not_null<Viewer*> viewer);
void injectRootDivider(
not_null<HistoryItem*> root,
not_null<MessagesSlice*> slice);

View File

@@ -228,14 +228,12 @@ void ScheduledMessages::apply(const MTPDupdateNewScheduledMessage &update) {
void ScheduledMessages::checkEntitiesAndUpdate(const MTPDmessage &data) {
// When the user sends a message with a media scheduled until online
// while the recipient is already online, the server sends
// updateNewMessage to the client and the client calls this method.
// while the recipient is already online, or scheduled message
// is already due and is sent immediately, the server sends
// updateNewMessage or updateNewChannelMessage to the client
// and the client calls this method.
const auto peer = peerFromMTP(data.vpeer_id());
if (!peerIsUser(peer)) {
return;
}
const auto history = _session->data().historyLoaded(peer);
if (!history) {
return;

View File

@@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "storage/storage_account.h"
#include "storage/storage_encrypted_file.h"
#include "media/player/media_player_instance.h" // instance()->play()
#include "media/audio/media_audio.h"
#include "boxes/abstract_box.h"
#include "passport/passport_form_controller.h"
#include "window/themes/window_theme.h"
@@ -1428,6 +1429,14 @@ rpl::producer<not_null<const HistoryItem*>> Session::itemRemoved() const {
return _itemRemoved.events();
}
rpl::producer<not_null<const HistoryItem*>> Session::itemRemoved(
FullMsgId itemId) const {
return itemRemoved(
) | rpl::filter([=](not_null<const HistoryItem*> item) {
return (itemId == item->fullId());
});
}
void Session::notifyViewRemoved(not_null<const ViewElement*> view) {
_viewRemoved.fire_copy(view);
}
@@ -3325,6 +3334,15 @@ void Session::unregisterContactItem(
}
}
void Session::documentMessageRemoved(not_null<DocumentData*> document) {
if (_documentItems.find(document) != _documentItems.end()) {
return;
}
if (document->loading()) {
document->cancel();
}
}
void Session::checkPlayingAnimations() {
auto check = base::flat_set<not_null<ViewElement*>>();
for (const auto view : _heavyViewParts) {

View File

@@ -231,6 +231,8 @@ public:
[[nodiscard]] rpl::producer<not_null<const History*>> historyUnloaded() const;
[[nodiscard]] rpl::producer<not_null<const HistoryItem*>> itemRemoved() const;
[[nodiscard]] rpl::producer<not_null<const HistoryItem*>> itemRemoved(
FullMsgId itemId) const;
void notifyViewRemoved(not_null<const ViewElement*> view);
[[nodiscard]] rpl::producer<not_null<const ViewElement*>> viewRemoved() const;
void notifyHistoryCleared(not_null<const History*> history);
@@ -545,6 +547,8 @@ public:
UserId contactId,
not_null<HistoryItem*> item);
void documentMessageRemoved(not_null<DocumentData*> document);
void checkPlayingAnimations();
HistoryItem *findWebPageItem(not_null<WebPageData*> page) const;

View File

@@ -3178,6 +3178,11 @@ void InnerWidget::setupShortcuts() {
return (history != nullptr);
});
request->check(Command::ShowContacts) && request->handle([=] {
Ui::show(PrepareContactsBox(_controller));
return true;
});
if (session().supportMode() && row.key.history()) {
request->check(
Command::SupportScrollToCurrent

View File

@@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_user.h"
#include "data/data_document.h"
#include "data/data_histories.h"
#include "lang/lang_keys.h"
#include "apiwrap.h"
@@ -416,11 +417,17 @@ void History::destroyMessage(not_null<HistoryItem*> item) {
types,
item->id));
}
} else {
session().api().cancelLocalItem(item);
}
itemRemoved(item);
}
if (item->isSending()) {
session().api().cancelLocalItem(item);
}
const auto document = [&] {
const auto media = item->media();
return media ? media->document() : nullptr;
}();
owner().unregisterMessage(item);
Core::App().notifications().clearFromItem(item);
@@ -431,6 +438,10 @@ void History::destroyMessage(not_null<HistoryItem*> item) {
Assert(i != end(_messages));
_messages.erase(i);
if (document) {
session().data().documentMessageRemoved(document);
}
}
not_null<HistoryItem*> History::addNewItem(

View File

@@ -487,7 +487,7 @@ HistoryMessage::HistoryMessage(
}
config.viaBotId = data.vvia_bot_id().value_or_empty();
config.viewsCount = data.vviews().value_or(-1);
config.mtpReplies = data.vreplies();
config.mtpReplies = isScheduled() ? nullptr : data.vreplies();
config.mtpMarkup = data.vreply_markup();
config.editDate = data.vedit_date().value_or_empty();
config.author = qs(data.vpost_author().value_or_empty());

View File

@@ -1005,6 +1005,7 @@ void ComposeControls::initField() {
_field,
&_window->session());
_raiseEmojiSuggestions = [=] { suggestions->raise(); };
InitSpellchecker(_window, _field);
}
void ComposeControls::fieldChanged() {

View File

@@ -69,7 +69,7 @@ constexpr auto kExportLocalTimeout = crl::time(1000);
//}
MsgId ItemIdAcrossData(not_null<HistoryItem*> item) {
if (!item->isScheduled()) {
if (!item->isScheduled() || item->isSending() || item->hasFailed()) {
return item->id;
}
const auto session = &item->history()->session();
@@ -420,23 +420,23 @@ bool AddSendNowMessageAction(
bool AddRescheduleMessageAction(
not_null<Ui::PopupMenu*> menu,
const ContextMenuRequest &request) {
if (!HasEditMessageAction(request)
|| !request.item->isScheduled()) {
if (!HasEditMessageAction(request) || !request.item->isScheduled()) {
return false;
}
const auto item = request.item;
const auto owner = &item->history()->owner();
const auto itemId = item->fullId();
const auto owner = &request.item->history()->owner();
const auto itemId = request.item->fullId();
menu->addAction(tr::lng_context_reschedule(tr::now), [=] {
const auto item = owner->message(itemId);
if (!item) {
return;
}
const auto callback = [=](Api::SendOptions options) {
if (!item->media() || !item->media()->webpage()) {
options.removeWebPageId = true;
if (const auto item = owner->message(itemId)) {
if (!item->media() || !item->media()->webpage()) {
options.removeWebPageId = true;
}
Api::RescheduleMessage(item, options);
}
Api::RescheduleMessage(item, options);
};
const auto peer = item->history()->peer;
@@ -453,13 +453,19 @@ bool AddRescheduleMessageAction(
? HistoryView::DefaultScheduleTime()
: item->date() + 600;
Ui::show(
const auto box = Ui::show(
HistoryView::PrepareScheduleBox(
&request.navigation->session(),
sendMenuType,
callback,
date),
Ui::LayerOption::KeepOther);
owner->itemRemoved(
itemId
) | rpl::start_with_next([=] {
box->closeBox();
}, box->lifetime());
});
return true;
}

View File

@@ -292,9 +292,10 @@ ListWidget::ListWidget(
}, lifetime());
session().data().itemRemoved(
) | rpl::start_with_next(
[this](auto item) { itemRemoved(item); },
lifetime());
) | rpl::start_with_next([=](not_null<const HistoryItem*> item) {
itemRemoved(item);
}, lifetime());
subscribe(session().data().queryItemVisibility(), [this](const Data::Session::ItemVisibilityQuery &query) {
if (const auto view = viewForItem(query.item)) {
const auto top = itemTop(view);

View File

@@ -216,6 +216,7 @@ RepliesWidget::RepliesWidget(
if (update.item == _root) {
_root = nullptr;
updatePinnedVisibility();
controller->showBackFromStack();
}
while (update.item == _replyReturn) {
calculateNextReplyReturn();
@@ -1758,7 +1759,7 @@ MessagesBarData RepliesWidget::listMessagesBar(
for (auto i = 0, count = int(elements.size()); i != count; ++i) {
const auto item = elements[i]->data();
if (IsServerMsgId(item->id) && item->id > till) {
if (item->out()) {
if (item->out() || !item->replyToId()) {
readTill(item);
} else {
return MessagesBarData{

View File

@@ -349,6 +349,11 @@ MainWidget::MainWidget(
if (!songState.id || IsStoppedOrStopping(songState.state)) {
closeBothPlayers();
}
} else if (type == AudioMsgId::Type::Song) {
const auto songState = Media::Player::instance()->getState(AudioMsgId::Type::Song);
if (!songState.id) {
closeBothPlayers();
}
}
});

View File

@@ -203,10 +203,14 @@ void Instance::setSession(not_null<Data*> data, Main::Session *session) {
) | rpl::start_with_next([=] {
setSession(data, nullptr);
}, data->sessionLifetime);
session->data().itemRemoved(
) | rpl::filter([=](not_null<const HistoryItem*> item) {
return (data->current.contextId() == item->fullId());
}) | rpl::start_with_next([=] {
stopAndClear(data);
}, data->sessionLifetime);
} else {
stop(data->type);
_tracksFinishedNotifier.notify(data->type);
*data = Data(data->type, data->overview);
stopAndClear(data);
}
}
@@ -527,6 +531,12 @@ void Instance::stop(AudioMsgId::Type type) {
}
}
void Instance::stopAndClear(not_null<Data*> data) {
stop(data->type);
_tracksFinishedNotifier.notify(data->type);
*data = Data(data->type, data->overview);
}
void Instance::playPause(AudioMsgId::Type type) {
if (const auto data = getData(type)) {
if (!data->streamed) {

View File

@@ -217,6 +217,7 @@ private:
void playlistUpdated(not_null<Data*> data);
bool moveInPlaylist(not_null<Data*> data, int delta, bool autonext);
HistoryItem *itemByIndex(not_null<Data*> data, int index);
void stopAndClear(not_null<Data*> data);
void handleStreamingUpdate(
not_null<Data*> data,

View File

@@ -345,11 +345,13 @@ OverlayWidget::OverlayWidget()
connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(onScreenResized(int)));
#if defined Q_OS_UNIX && !defined Q_OS_MAC
setWindowFlags(Qt::FramelessWindowHint | Qt::MaximizeUsingFullscreenGeometryHint);
#else // Q_OS_UNIX && !Q_OS_MAC
setWindowFlags(Qt::FramelessWindowHint);
#endif // Q_OS_UNIX && !Q_OS_MAC
if (Platform::IsLinux()) {
setWindowFlags(Qt::FramelessWindowHint
| Qt::WindowStaysOnTopHint
| Qt::MaximizeUsingFullscreenGeometryHint);
} else {
setWindowFlags(Qt::FramelessWindowHint);
}
moveToScreen();
setAttribute(Qt::WA_NoSystemBackground, true);
setAttribute(Qt::WA_TranslucentBackground, true);
@@ -2280,11 +2282,11 @@ void OverlayWidget::displayFinished() {
updateControls();
if (isHidden()) {
Ui::Platform::UpdateOverlayed(this);
#if defined Q_OS_UNIX && !defined Q_OS_MAC
showFullScreen();
#else // Q_OS_UNIX && !Q_OS_MAC
show();
#endif // Q_OS_UNIX && !Q_OS_MAC
if (Platform::IsLinux()) {
showFullScreen();
} else {
show();
}
Ui::Platform::ShowOverAll(this);
activateWindow();
QApplication::setActiveWindow(this);
@@ -3672,6 +3674,14 @@ void OverlayWidget::setSession(not_null<Main::Session*> session) {
changingMsgId(change.item, change.oldId);
}, _sessionLifetime);
session->data().itemRemoved(
) | rpl::filter([=](not_null<const HistoryItem*> item) {
return (_document != nullptr || _photo != nullptr)
&& (item->fullId() == _msgid);
}) | rpl::start_with_next([=] {
close();
}, _sessionLifetime);
session->account().sessionChanges(
) | rpl::start_with_next([=] {
clearSession();

View File

@@ -277,6 +277,7 @@ inline QString GtkSetting(const gchar *propertyName) {
gchararray value = GtkSetting<gchararray>(propertyName);
QString str = QString::fromUtf8(value);
g_free(value);
DEBUG_LOG(("Getting GTK setting, %1: '%2'").arg(propertyName).arg(str));
return str;
}
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION

View File

@@ -950,18 +950,7 @@ void MainWindow::createGlobalMenu() {
return;
}
Ui::show(
Box<PeerListBox>(std::make_unique<ContactsBoxController>(
sessionController()),
[](not_null<PeerListBox*> box) {
box->addButton(tr::lng_close(), [box] {
box->closeBox();
});
box->addLeftButton(tr::lng_profile_add_contact(), [] {
App::wnd()->onShowAddContact();
});
}));
Ui::show(PrepareContactsBox(sessionController()));
}));
psAddContact = tools->addAction(

View File

@@ -244,7 +244,7 @@ public:
void notificationReplied(uint id, const QString &text);
private:
GDBusProxy *_dbusProxy;
GDBusConnection *_dbusConnection = nullptr;
base::weak_ptr<Manager> _manager;
QString _title;
@@ -255,14 +255,19 @@ private:
QImage _image;
uint _notificationId = 0;
guint _actionInvokedSignalId = 0;
guint _notificationRepliedSignalId = 0;
guint _notificationClosedSignalId = 0;
NotificationId _id;
static void signalEmitted(
GDBusProxy *proxy,
gchar *sender_name,
gchar *signal_name,
GDBusConnection *connection,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface_name,
const gchar *signal_name,
GVariant *parameters,
NotificationData *notificationData);
gpointer user_data);
};
@@ -275,20 +280,24 @@ NotificationData::NotificationData(
const QString &msg,
NotificationId id,
bool hideReplyButton)
: _dbusProxy(g_dbus_proxy_new_for_bus_sync(
G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
nullptr,
kService.utf8(),
kObjectPath.utf8(),
kInterface.utf8(),
nullptr,
nullptr))
, _manager(manager)
: _manager(manager)
, _title(title)
, _imageKey(GetImageKey(ParseSpecificationVersion(
GetServerInformation())))
, _id(id) {
GError *error = nullptr;
_dbusConnection = g_bus_get_sync(
G_BUS_TYPE_SESSION,
nullptr,
&error);
if (error) {
LOG(("Native notification error: %1").arg(error->message));
g_error_free(error);
return;
}
const auto capabilities = GetCapabilities();
if (capabilities.contains(qsl("body-markup"))) {
@@ -307,17 +316,43 @@ NotificationData::NotificationData(
_actions.push_back(qsl("default"));
_actions.push_back(QString());
_actions.push_back(qsl("mail-mark-read"));
_actions.push_back(tr::lng_context_mark_read(tr::now));
if (!hideReplyButton) {
_actions.push_back(qsl("mail-mark-read"));
_actions.push_back(tr::lng_context_mark_read(tr::now));
}
if (capabilities.contains(qsl("inline-reply")) && !hideReplyButton) {
_actions.push_back(qsl("inline-reply"));
_actions.push_back(tr::lng_notification_reply(tr::now));
_notificationRepliedSignalId = g_dbus_connection_signal_subscribe(
_dbusConnection,
kService.utf8(),
kInterface.utf8(),
"NotificationReplied",
kObjectPath.utf8(),
nullptr,
G_DBUS_SIGNAL_FLAGS_NONE,
signalEmitted,
this,
nullptr);
} else {
// icon name according to https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html
_actions.push_back(qsl("mail-reply-sender"));
_actions.push_back(tr::lng_notification_reply(tr::now));
}
_actionInvokedSignalId = g_dbus_connection_signal_subscribe(
_dbusConnection,
kService.utf8(),
kInterface.utf8(),
"ActionInvoked",
kObjectPath.utf8(),
nullptr,
G_DBUS_SIGNAL_FLAGS_NONE,
signalEmitted,
this,
nullptr);
}
if (capabilities.contains(qsl("action-icons"))) {
@@ -351,11 +386,35 @@ NotificationData::NotificationData(
qsl("desktop-entry"),
g_variant_new_string(GetLauncherBasename().toUtf8()));
g_signal_connect(_dbusProxy, "g-signal", G_CALLBACK(signalEmitted), this);
_notificationClosedSignalId = g_dbus_connection_signal_subscribe(
_dbusConnection,
kService.utf8(),
kInterface.utf8(),
"NotificationClosed",
kObjectPath.utf8(),
nullptr,
G_DBUS_SIGNAL_FLAGS_NONE,
signalEmitted,
this,
nullptr);
}
NotificationData::~NotificationData() {
g_object_unref(_dbusProxy);
if (_dbusConnection) {
if (_actionInvokedSignalId != 0) {
g_dbus_connection_signal_unsubscribe(_dbusConnection, _actionInvokedSignalId);
}
if (_notificationRepliedSignalId != 0) {
g_dbus_connection_signal_unsubscribe(_dbusConnection, _notificationRepliedSignalId);
}
if (_notificationClosedSignalId != 0) {
g_dbus_connection_signal_unsubscribe(_dbusConnection, _notificationClosedSignalId);
}
g_object_unref(_dbusConnection);
}
for (const auto &[key, value] : _hints) {
if (value) {
@@ -391,8 +450,11 @@ bool NotificationData::show() {
? GetIconName()
: QString();
auto reply = g_dbus_proxy_call_sync(
_dbusProxy,
auto reply = g_dbus_connection_call_sync(
_dbusConnection,
kService.utf8(),
kObjectPath.utf8(),
kInterface.utf8(),
"Notify",
g_variant_new(
kNotifyArgsType.utf8(),
@@ -404,6 +466,7 @@ bool NotificationData::show() {
&actionsBuilder,
&hintsBuilder,
-1),
nullptr,
G_DBUS_CALL_FLAGS_NONE,
kDBusTimeout,
nullptr,
@@ -423,10 +486,14 @@ bool NotificationData::show() {
}
void NotificationData::close() {
g_dbus_proxy_call(
_dbusProxy,
g_dbus_connection_call(
_dbusConnection,
kService.utf8(),
kObjectPath.utf8(),
kInterface.utf8(),
"CloseNotification",
g_variant_new("(u)", _notificationId),
nullptr,
G_DBUS_CALL_FLAGS_NONE,
-1,
nullptr,
@@ -463,11 +530,20 @@ void NotificationData::setImage(const QString &imagePath) {
}
void NotificationData::signalEmitted(
GDBusProxy *proxy,
gchar *sender_name,
gchar *signal_name,
GDBusConnection *connection,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface_name,
const gchar *signal_name,
GVariant *parameters,
NotificationData *notificationData) {
gpointer user_data) {
const auto notificationData = reinterpret_cast<NotificationData*>(
user_data);
if (!notificationData) {
return;
}
if(signal_name == qstr("ActionInvoked")) {
guint32 id;
gchar *actionName;

View File

@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "platform/linux/linux_libs.h"
#include "base/platform/base_platform_info.h"
#include "base/platform/linux/base_xcb_utilities_linux.h"
#include "lang/lang_keys.h"
#include "mainwidget.h"
#include "mainwindow.h"
@@ -25,7 +26,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtCore/QProcess>
#include <QtCore/QVersionNumber>
#include <QtGui/QWindow>
#include <qpa/qplatformnativeinterface.h>
#include <private/qwaylanddisplay_p.h>
#include <private/qwaylandwindow_p.h>
@@ -123,6 +123,14 @@ void PortalAutostart(bool autostart, bool silent = false) {
}
}
bool IsXDGDesktopPortalKDEPresent() {
static const auto Result = QDBusInterface(
qsl("org.freedesktop.impl.portal.desktop.kde"),
kXDGDesktopPortalObjectPath.utf16()).isValid();
return Result;
}
uint FileChooserPortalVersion() {
static const auto Result = [&]() -> uint {
auto message = QDBusMessage::createMethodCall(
@@ -301,128 +309,26 @@ bool GetImageFromClipboardSupported() {
}
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
std::optional<xcb_atom_t> GetXCBAtom(
xcb_connection_t *connection,
const QString &name) {
const auto cookie = xcb_intern_atom(
connection,
0,
name.size(),
name.toUtf8());
auto reply = xcb_intern_atom_reply(
connection,
cookie,
nullptr);
if (!reply) {
return std::nullopt;
}
const auto atom = reply->atom;
free(reply);
return atom;
}
bool IsXCBExtensionPresent(
xcb_connection_t *connection,
xcb_extension_t *ext) {
const auto reply = xcb_get_extension_data(
connection,
ext);
if (!reply) {
return false;
}
return reply->present;
}
std::vector<xcb_atom_t> GetXCBWMSupported(xcb_connection_t *connection) {
auto netWmAtoms = std::vector<xcb_atom_t>{};
const auto native = QGuiApplication::platformNativeInterface();
if (!native) {
return netWmAtoms;
}
const auto root = static_cast<xcb_window_t>(reinterpret_cast<quintptr>(
native->nativeResourceForIntegration(QByteArray("rootwindow"))));
const auto supportedAtom = GetXCBAtom(connection, "_NET_SUPPORTED");
if (!supportedAtom.has_value()) {
return netWmAtoms;
}
auto offset = 0;
auto remaining = 0;
do {
const auto cookie = xcb_get_property(
connection,
false,
root,
*supportedAtom,
XCB_ATOM_ATOM,
offset,
1024);
auto reply = xcb_get_property_reply(
connection,
cookie,
nullptr);
if (!reply) {
break;
}
remaining = 0;
if (reply->type == XCB_ATOM_ATOM && reply->format == 32) {
const auto len = xcb_get_property_value_length(reply)
/ sizeof(xcb_atom_t);
const auto atoms = reinterpret_cast<xcb_atom_t*>(
xcb_get_property_value(reply));
const auto s = netWmAtoms.size();
netWmAtoms.resize(s + len);
memcpy(netWmAtoms.data() + s, atoms, len * sizeof(xcb_atom_t));
remaining = reply->bytes_after;
offset += len;
}
free(reply);
} while (remaining > 0);
return netWmAtoms;
}
std::optional<crl::time> XCBLastUserInputTime() {
const auto native = QGuiApplication::platformNativeInterface();
if (!native) {
return std::nullopt;
}
const auto connection = reinterpret_cast<xcb_connection_t*>(
native->nativeResourceForIntegration(QByteArray("connection")));
const auto connection = base::Platform::XCB::GetConnectionFromQt();
if (!connection) {
return std::nullopt;
}
if (!IsXCBExtensionPresent(connection, &xcb_screensaver_id)) {
if (!base::Platform::XCB::IsExtensionPresent(
connection,
&xcb_screensaver_id)) {
return std::nullopt;
}
const auto root = static_cast<xcb_window_t>(reinterpret_cast<quintptr>(
native->nativeResourceForIntegration(QByteArray("rootwindow"))));
const auto root = base::Platform::XCB::GetRootWindowFromQt();
if (!root.has_value()) {
return std::nullopt;
}
const auto cookie = xcb_screensaver_query_info(
connection,
root);
*root);
auto reply = xcb_screensaver_query_info_reply(
connection,
@@ -573,27 +479,21 @@ enum wl_shell_surface_resize WlResizeFromEdges(Qt::Edges edges) {
#endif // Qt < 5.13 && !DESKTOP_APP_QT_PATCHED
bool StartXCBMoveResize(QWindow *window, int edges) {
const auto native = QGuiApplication::platformNativeInterface();
if (!native) {
return false;
}
const auto connection = reinterpret_cast<xcb_connection_t*>(
native->nativeResourceForIntegration(QByteArray("connection")));
const auto connection = base::Platform::XCB::GetConnectionFromQt();
if (!connection) {
return false;
}
const auto screen = xcb_setup_roots_iterator(
xcb_get_setup(connection)).data;
if (!screen) {
const auto root = base::Platform::XCB::GetRootWindowFromQt();
if (!root.has_value()) {
return false;
}
const auto moveResize = GetXCBAtom(connection, "_NET_WM_MOVERESIZE");
if (!moveResize.has_value()) {
const auto moveResizeAtom = base::Platform::XCB::GetAtom(
connection,
"_NET_WM_MOVERESIZE");
if (!moveResizeAtom.has_value()) {
return false;
}
@@ -601,7 +501,7 @@ bool StartXCBMoveResize(QWindow *window, int edges) {
xcb_client_message_event_t xev;
xev.response_type = XCB_CLIENT_MESSAGE;
xev.type = *moveResize;
xev.type = *moveResizeAtom;
xev.sequence = 0;
xev.window = window->winId();
xev.format = 32;
@@ -617,7 +517,7 @@ bool StartXCBMoveResize(QWindow *window, int edges) {
xcb_send_event(
connection,
false,
screen->root,
*root,
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT
| XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
reinterpret_cast<const char*>(&xev));
@@ -679,19 +579,12 @@ bool ShowWaylandWindowMenu(QWindow *window) {
}
bool XCBFrameExtentsSupported() {
const auto native = QGuiApplication::platformNativeInterface();
if (!native) {
return false;
}
const auto connection = reinterpret_cast<xcb_connection_t*>(
native->nativeResourceForIntegration(QByteArray("connection")));
const auto connection = base::Platform::XCB::GetConnectionFromQt();
if (!connection) {
return false;
}
const auto frameExtentsAtom = GetXCBAtom(
const auto frameExtentsAtom = base::Platform::XCB::GetAtom(
connection,
kXCBFrameExtentsAtomName.utf16());
@@ -699,23 +592,18 @@ bool XCBFrameExtentsSupported() {
return false;
}
return ranges::contains(GetXCBWMSupported(connection), *frameExtentsAtom);
return ranges::contains(
base::Platform::XCB::GetWMSupported(connection),
*frameExtentsAtom);
}
bool SetXCBFrameExtents(QWindow *window, const QMargins &extents) {
const auto native = QGuiApplication::platformNativeInterface();
if (!native) {
return false;
}
const auto connection = reinterpret_cast<xcb_connection_t*>(
native->nativeResourceForIntegration(QByteArray("connection")));
const auto connection = base::Platform::XCB::GetConnectionFromQt();
if (!connection) {
return false;
}
const auto frameExtentsAtom = GetXCBAtom(
const auto frameExtentsAtom = base::Platform::XCB::GetAtom(
connection,
kXCBFrameExtentsAtomName.utf16());
@@ -744,19 +632,12 @@ bool SetXCBFrameExtents(QWindow *window, const QMargins &extents) {
}
bool UnsetXCBFrameExtents(QWindow *window) {
const auto native = QGuiApplication::platformNativeInterface();
if (!native) {
return false;
}
const auto connection = reinterpret_cast<xcb_connection_t*>(
native->nativeResourceForIntegration(QByteArray("connection")));
const auto connection = base::Platform::XCB::GetConnectionFromQt();
if (!connection) {
return false;
}
const auto frameExtentsAtom = GetXCBAtom(
const auto frameExtentsAtom = base::Platform::XCB::GetAtom(
connection,
kXCBFrameExtentsAtomName.utf16());
@@ -858,17 +739,20 @@ bool IsXDGDesktopPortalPresent() {
}
bool UseXDGDesktopPortal() {
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
static const auto Result = [&] {
const auto envVar = qEnvironmentVariableIsSet("TDESKTOP_USE_PORTAL");
const auto portalPresent = IsXDGDesktopPortalPresent();
const auto neededForKde = DesktopEnvironment::IsKDE()
&& IsXDGDesktopPortalKDEPresent();
return (
DesktopEnvironment::IsKDE()
|| envVar
) && portalPresent;
return (neededForKde || envVar) && portalPresent;
}();
return Result;
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
return false;
}
bool CanOpenDirectoryWithPortal() {
@@ -926,10 +810,15 @@ QString AppRuntimeDirectory() {
}
QString SingleInstanceLocalServerName(const QString &hash) {
if (InFlatpak() || InSnap()) {
const auto idealSocketPath = AppRuntimeDirectory()
+ hash
+ '-'
+ cGUIDStr();
if (idealSocketPath.size() > 108) {
return AppRuntimeDirectory() + hash;
} else {
return AppRuntimeDirectory() + hash + '-' + cGUIDStr();
return idealSocketPath;
}
}
@@ -1375,7 +1264,7 @@ void start() {
void finish() {
}
void InstallMainDesktopFile() {
void InstallLauncher() {
static const auto DisabledByEnv = qEnvironmentVariableIsSet(
"TDESKTOP_DISABLE_DESKTOP_FILE_GENERATION");
@@ -1543,7 +1432,7 @@ void finish() {
} // namespace Platform
void psNewVersion() {
Platform::InstallMainDesktopFile();
Platform::InstallLauncher();
Platform::RegisterCustomScheme();
}

View File

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

View File

@@ -721,10 +721,7 @@ void MainWindow::createGlobalMenu() {
if (!sessionController()) {
return;
}
Ui::show(Box<PeerListBox>(std::make_unique<ContactsBoxController>(sessionController()), [](not_null<PeerListBox*> box) {
box->addButton(tr::lng_close(), [box] { box->closeBox(); });
box->addLeftButton(tr::lng_profile_add_contact(), [] { App::wnd()->onShowAddContact(); });
}));
Ui::show(PrepareContactsBox(sessionController()));
}));
psAddContact = window->addAction(tr::lng_mac_menu_add_contact(tr::now), App::wnd(), SLOT(onShowAddContact()));
window->addSeparator();

View File

@@ -62,11 +62,4 @@ Q_IMPORT_PLUGIN(QHimePlatformInputContextPlugin)
Q_IMPORT_PLUGIN(Qt5CTPlatformThemePlugin)
Q_IMPORT_PLUGIN(Qt5CTStylePlugin)
#endif // !DESKTOP_APP_USE_PACKAGED || DESKTOP_APP_USE_PACKAGED_LAZY_PLATFORMTHEMES
// conflicts with Qt static link
#ifdef DESKTOP_APP_USE_PACKAGED_LAZY_PLATFORMTHEMES
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
Q_IMPORT_PLUGIN(LXQtPlatformThemePlugin)
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
#endif // DESKTOP_APP_USE_PACKAGED_LAZY_PLATFORMTHEMES
#endif // Q_OS_UNIX && !Q_OS_MAC

View File

@@ -861,10 +861,7 @@ void MainMenu::refreshMenu() {
App::wnd()->onShowNewChannel();
}, &st::mainMenuNewChannel, &st::mainMenuNewChannelOver);
_menu->addAction(tr::lng_menu_contacts(tr::now), [=] {
Ui::show(Box<PeerListBox>(std::make_unique<ContactsBoxController>(controller), [](not_null<PeerListBox*> box) {
box->addButton(tr::lng_close(), [box] { box->closeBox(); });
box->addLeftButton(tr::lng_profile_add_contact(), [] { App::wnd()->onShowAddContact(); });
}));
Ui::show(PrepareContactsBox(controller));
}, &st::mainMenuContacts, &st::mainMenuContactsOver);
if (_controller->session().serverConfig().phoneCallsEnabled.current()) {
_menu->addAction(tr::lng_menu_calls(tr::now), [=] {

View File

@@ -1,7 +1,7 @@
AppVersion 2004003
AppVersion 2004004
AppVersionStrMajor 2.4
AppVersionStrSmall 2.4.3
AppVersionStr 2.4.3
AppVersionStrSmall 2.4.4
AppVersionStr 2.4.4
BetaChannel 0
AlphaVersion 0
AppVersionOriginal 2.4.3
AppVersionOriginal 2.4.4

View File

@@ -1,3 +1,9 @@
2.4.4 (23.10.20)
- Fix application quit on call end with main window hidden in tray.
- Update OpenAL library on Windows.
- Several crash fixes.
2.4.3 (07.10.20)
- Fix sending voice messages in scheduled messages section.

2
cmake

Submodule cmake updated: 5d6f8ebee3...cfc6051fb6

View File

@@ -67,7 +67,7 @@ Go to ***BuildPath*** and run
sudo make install
cd ..
git clone https://github.com/01org/libva.git
git clone https://github.com/intel/libva.git
cd libva
CFLAGS=-fPIC CPPFLAGS=-fPIC LDFLAGS=-fPIC ./autogen.sh --enable-static
make $MAKE_THREADS_CNT

View File

@@ -102,14 +102,13 @@ Open **x86 Native Tools Command Prompt for VS 2019.bat**, go to ***BuildPath***
git clone https://github.com/telegramdesktop/openal-soft.git
cd openal-soft
git checkout fix_capture
git checkout fix_mono
cd build
cmake .. ^
-G "Visual Studio 16 2019" ^
-A Win32 ^
-D LIBTYPE:STRING=STATIC ^
-D FORCE_STATIC_VCRT=ON ^
-D ALSOFT_BACKEND_WASAPI=OFF
-D FORCE_STATIC_VCRT=ON
msbuild OpenAL.vcxproj /property:Configuration=Debug
msbuild OpenAL.vcxproj /property:Configuration=Release
cd ..\..