Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9717a8b5fa | ||
|
|
aff4f69b64 | ||
|
|
9de4c42555 | ||
|
|
1de144a48d | ||
|
|
0690d14f1b | ||
|
|
53ac4c00ad | ||
|
|
f064692e57 | ||
|
|
3d54a263b8 | ||
|
|
47bb8ec687 | ||
|
|
3a2b772a5d | ||
|
|
bc8f8bc68c | ||
|
|
bc7975ece7 | ||
|
|
52cca98144 | ||
|
|
5540b0bb8b | ||
|
|
7de9bcad03 | ||
|
|
367b028094 | ||
|
|
8b27aa5331 | ||
|
|
9697567b8d | ||
|
|
1fdfa94497 | ||
|
|
1373bd0af1 | ||
|
|
4f2b0531f8 | ||
|
|
ca67ac913f | ||
|
|
4033a091b5 | ||
|
|
0179a2ca10 | ||
|
|
f58874572d | ||
|
|
143b9682a4 | ||
|
|
00c962e557 | ||
|
|
1cabfaa6a4 | ||
|
|
b788ae0ae4 | ||
|
|
3f6399f13d | ||
|
|
b6fc418d32 | ||
|
|
245d644cd7 | ||
|
|
2aa0b674cd | ||
|
|
654784ce9f |
21
.github/stale.yml
vendored
Normal file
21
.github/stale.yml
vendored
Normal 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
|
||||
2
.github/workflows/linux.yml
vendored
2
.github/workflows/linux.yml
vendored
@@ -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)
|
||||
|
||||
9
.github/workflows/mac.yml
vendored
9
.github/workflows/mac.yml
vendored
@@ -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)
|
||||
|
||||
90
.github/workflows/user_agent_updater.yml
vendored
Normal file
90
.github/workflows/user_agent_updater.yml
vendored
Normal 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
6
.gitmodules
vendored
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -90,6 +90,7 @@ Sandbox::Sandbox(
|
||||
}
|
||||
})
|
||||
, _launcher(launcher) {
|
||||
setQuitOnLastWindowClosed(false);
|
||||
}
|
||||
|
||||
int Sandbox::start() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ enum class Command {
|
||||
FolderPrevious,
|
||||
|
||||
ShowArchive,
|
||||
ShowContacts,
|
||||
|
||||
JustSendMessage,
|
||||
SendSilentMessage,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -1005,6 +1005,7 @@ void ComposeControls::initField() {
|
||||
_field,
|
||||
&_window->session());
|
||||
_raiseEmojiSuggestions = [=] { suggestions->raise(); };
|
||||
InitSpellchecker(_window, _field);
|
||||
}
|
||||
|
||||
void ComposeControls::fieldChanged() {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ QString GetIconName();
|
||||
inline void IgnoreApplicationActivationRightNow() {
|
||||
}
|
||||
|
||||
void InstallMainDesktopFile();
|
||||
void InstallLauncher();
|
||||
|
||||
} // namespace Platform
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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), [=] {
|
||||
|
||||
1
Telegram/ThirdParty/libqtxdg
vendored
1
Telegram/ThirdParty/libqtxdg
vendored
Submodule Telegram/ThirdParty/libqtxdg deleted from ae412d30c6
1
Telegram/ThirdParty/lxqt-qtplugin
vendored
1
Telegram/ThirdParty/lxqt-qtplugin
vendored
Submodule Telegram/ThirdParty/lxqt-qtplugin deleted from 418162b36e
@@ -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
|
||||
|
||||
Submodule Telegram/lib_base updated: 4f03dbd9a0...98224799e4
Submodule Telegram/lib_spellcheck updated: 58263c0715...053e44a101
Submodule Telegram/lib_ui updated: ae340a0b76...914df12ebe
@@ -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
2
cmake
Submodule cmake updated: 5d6f8ebee3...cfc6051fb6
@@ -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
|
||||
|
||||
@@ -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 ..\..
|
||||
|
||||
Reference in New Issue
Block a user