2
0
mirror of https://github.com/kotatogram/kotatogram-desktop synced 2025-08-29 05:37:45 +00:00

Merge remote-tracking branch 'tdesktop/dev' into dev

This commit is contained in:
RadRussianRus 2020-06-26 07:25:00 +03:00
commit 0943d58ea7
120 changed files with 1095 additions and 1019 deletions

View File

@ -390,7 +390,7 @@ jobs:
run: |
cd $LibrariesPath
git clone -b 1.16 https://gitlab.freedesktop.org/wayland/wayland
git clone -b 1.18.0 https://gitlab.freedesktop.org/wayland/wayland
cd wayland
./autogen.sh \
--enable-static \

View File

@ -411,7 +411,7 @@ jobs:
uses: actions/cache@v1
with:
path: ${{ env.LibrariesPath }}/qt-cache
key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qtbase_5_12_8.diff') }}
key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qtbase_5_12_8/*') }}
- name: Use cached Qt 5.12.8.
if: steps.cache-qt.outputs.cache-hit == 'true'
run: |

View File

@ -13,7 +13,6 @@ on:
- '!.github/workflows/snap.yml'
- 'Telegram/build/**'
- 'Telegram/Patches/**'
- '!Telegram/Patches/ffmpeg.diff'
- 'Telegram/Resources/uwp/**'
- 'Telegram/Resources/winrc/**'
- 'Telegram/SourceFiles/platform/win/**'
@ -33,7 +32,6 @@ on:
- '!.github/workflows/snap.yml'
- 'Telegram/build/**'
- 'Telegram/Patches/**'
- '!Telegram/Patches/ffmpeg.diff'
- 'Telegram/Resources/uwp/**'
- 'Telegram/Resources/winrc/**'
- 'Telegram/SourceFiles/platform/win/**'
@ -45,13 +43,13 @@ on:
jobs:
linux:
name: Ubuntu 18.04
name: Ubuntu 20.04
if: >
!(github.event_name == 'push'
&& contains(github.event.head_commit.message, '[skip ci]'))
&& !(github.event_name == 'pull_request'
&& github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name)
runs-on: ubuntu-18.04
runs-on: ubuntu-20.04
env:
UPLOAD_ARTIFACT: "false"

View File

@ -301,7 +301,7 @@ jobs:
uses: actions/cache@v1
with:
path: ${{ env.LibrariesPath }}/Qt-5.12.8
key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qtbase_5_12_8.diff') }}
key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qtbase_5_12_8/*') }}
- name: Configure Qt 5.12.8.
if: steps.cache-qt.outputs.cache-hit != 'true'
shell: cmd
@ -397,7 +397,7 @@ jobs:
if: env.UPLOAD_ARTIFACT == 'true'
shell: cmd
run: |
cd %REPO_NAME%\build\bin
cd %REPO_NAME%\out\Debug
mkdir artifact
move Kotatogram.exe artifact/
move Updater.exe artifact/
@ -406,4 +406,4 @@ jobs:
if: env.UPLOAD_ARTIFACT == 'true'
with:
name: ${{ env.ARTIFACT_NAME }}
path: ${{ env.REPO_NAME }}\build\bin\artifact\
path: ${{ env.REPO_NAME }}\out\Debug\artifact\

View File

@ -1224,7 +1224,7 @@ endif()
set_target_properties(Telegram PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_folder})
if ((NOT DESKTOP_APP_DISABLE_AUTOUPDATE OR NOT LINUX) AND NOT build_macstore AND NOT build_winstore)
if ((NOT DESKTOP_APP_DISABLE_AUTOUPDATE OR APPLE) AND NOT build_macstore AND NOT build_winstore)
add_executable(Updater WIN32)
init_target(Updater)

View File

@ -1,225 +0,0 @@
diff --git a/libavcodec/aarch64/Makefile b/libavcodec/aarch64/Makefile
index 00f93bf59f..52da7036f3 100644
--- a/libavcodec/aarch64/Makefile
+++ b/libavcodec/aarch64/Makefile
@@ -6,6 +6,7 @@ OBJS-$(CONFIG_H264DSP) += aarch64/h264dsp_init_aarch64.o
OBJS-$(CONFIG_H264PRED) += aarch64/h264pred_init.o
OBJS-$(CONFIG_H264QPEL) += aarch64/h264qpel_init_aarch64.o
OBJS-$(CONFIG_HPELDSP) += aarch64/hpeldsp_init_aarch64.o
+OBJS-$(CONFIG_IDCTDSP) += aarch64/idctdsp_init_aarch64.o
OBJS-$(CONFIG_MPEGAUDIODSP) += aarch64/mpegaudiodsp_init.o
OBJS-$(CONFIG_NEON_CLOBBER_TEST) += aarch64/neontest.o
OBJS-$(CONFIG_VIDEODSP) += aarch64/videodsp_init.o
@@ -21,6 +22,7 @@ OBJS-$(CONFIG_VC1DSP) += aarch64/vc1dsp_init_aarch64.o
OBJS-$(CONFIG_VORBIS_DECODER) += aarch64/vorbisdsp_init.o
OBJS-$(CONFIG_VP9_DECODER) += aarch64/vp9dsp_init_10bpp_aarch64.o \
aarch64/vp9dsp_init_12bpp_aarch64.o \
+ aarch64/vp9mc_aarch64.o \
aarch64/vp9dsp_init_aarch64.o
# ARMv8 optimizations
@@ -41,8 +43,7 @@ NEON-OBJS-$(CONFIG_H264PRED) += aarch64/h264pred_neon.o
NEON-OBJS-$(CONFIG_H264QPEL) += aarch64/h264qpel_neon.o \
aarch64/hpeldsp_neon.o
NEON-OBJS-$(CONFIG_HPELDSP) += aarch64/hpeldsp_neon.o
-NEON-OBJS-$(CONFIG_IDCTDSP) += aarch64/idctdsp_init_aarch64.o \
- aarch64/simple_idct_neon.o
+NEON-OBJS-$(CONFIG_IDCTDSP) += aarch64/simple_idct_neon.o
NEON-OBJS-$(CONFIG_MDCT) += aarch64/mdct_neon.o
NEON-OBJS-$(CONFIG_MPEGAUDIODSP) += aarch64/mpegaudiodsp_neon.o
NEON-OBJS-$(CONFIG_VP8DSP) += aarch64/vp8dsp_neon.o
diff --git a/libavcodec/aarch64/idctdsp_init_aarch64.c b/libavcodec/aarch64/idctdsp_init_aarch64.c
index 0406e60830..742a3372e3 100644
--- a/libavcodec/aarch64/idctdsp_init_aarch64.c
+++ b/libavcodec/aarch64/idctdsp_init_aarch64.c
@@ -21,6 +21,8 @@
*/
#include "libavutil/attributes.h"
+#include "libavutil/cpu.h"
+#include "libavutil/arm/cpu.h"
#include "libavcodec/avcodec.h"
#include "libavcodec/idctdsp.h"
#include "idct.h"
@@ -28,7 +30,9 @@
av_cold void ff_idctdsp_init_aarch64(IDCTDSPContext *c, AVCodecContext *avctx,
unsigned high_bit_depth)
{
- if (!avctx->lowres && !high_bit_depth) {
+ int cpu_flags = av_get_cpu_flags();
+
+ if (have_neon(cpu_flags) && !avctx->lowres && !high_bit_depth) {
if (avctx->idct_algo == FF_IDCT_AUTO ||
avctx->idct_algo == FF_IDCT_SIMPLEAUTO ||
avctx->idct_algo == FF_IDCT_SIMPLENEON) {
diff --git a/libavcodec/aarch64/vp9mc_16bpp_neon.S b/libavcodec/aarch64/vp9mc_16bpp_neon.S
index cac6428709..53b372c262 100644
--- a/libavcodec/aarch64/vp9mc_16bpp_neon.S
+++ b/libavcodec/aarch64/vp9mc_16bpp_neon.S
@@ -25,31 +25,6 @@
// const uint8_t *ref, ptrdiff_t ref_stride,
// int h, int mx, int my);
-function ff_vp9_copy128_aarch64, export=1
-1:
- ldp x5, x6, [x2]
- ldp x7, x8, [x2, #16]
- stp x5, x6, [x0]
- ldp x9, x10, [x2, #32]
- stp x7, x8, [x0, #16]
- subs w4, w4, #1
- ldp x11, x12, [x2, #48]
- stp x9, x10, [x0, #32]
- stp x11, x12, [x0, #48]
- ldp x5, x6, [x2, #64]
- ldp x7, x8, [x2, #80]
- stp x5, x6, [x0, #64]
- ldp x9, x10, [x2, #96]
- stp x7, x8, [x0, #80]
- ldp x11, x12, [x2, #112]
- stp x9, x10, [x0, #96]
- stp x11, x12, [x0, #112]
- add x2, x2, x3
- add x0, x0, x1
- b.ne 1b
- ret
-endfunc
-
function ff_vp9_avg64_16_neon, export=1
mov x5, x0
sub x1, x1, #64
diff --git a/libavcodec/aarch64/vp9mc_aarch64.S b/libavcodec/aarch64/vp9mc_aarch64.S
new file mode 100644
index 0000000000..f17a8cf04a
--- /dev/null
+++ b/libavcodec/aarch64/vp9mc_aarch64.S
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016 Google Inc.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/aarch64/asm.S"
+
+// All public functions in this file have the following signature:
+// typedef void (*vp9_mc_func)(uint8_t *dst, ptrdiff_t dst_stride,
+// const uint8_t *ref, ptrdiff_t ref_stride,
+// int h, int mx, int my);
+
+function ff_vp9_copy128_aarch64, export=1
+1:
+ ldp x5, x6, [x2]
+ ldp x7, x8, [x2, #16]
+ stp x5, x6, [x0]
+ ldp x9, x10, [x2, #32]
+ stp x7, x8, [x0, #16]
+ subs w4, w4, #1
+ ldp x11, x12, [x2, #48]
+ stp x9, x10, [x0, #32]
+ stp x11, x12, [x0, #48]
+ ldp x5, x6, [x2, #64]
+ ldp x7, x8, [x2, #80]
+ stp x5, x6, [x0, #64]
+ ldp x9, x10, [x2, #96]
+ stp x7, x8, [x0, #80]
+ ldp x11, x12, [x2, #112]
+ stp x9, x10, [x0, #96]
+ stp x11, x12, [x0, #112]
+ add x2, x2, x3
+ add x0, x0, x1
+ b.ne 1b
+ ret
+endfunc
+
+function ff_vp9_copy64_aarch64, export=1
+1:
+ ldp x5, x6, [x2]
+ ldp x7, x8, [x2, #16]
+ stp x5, x6, [x0]
+ ldp x9, x10, [x2, #32]
+ stp x7, x8, [x0, #16]
+ subs w4, w4, #1
+ ldp x11, x12, [x2, #48]
+ stp x9, x10, [x0, #32]
+ stp x11, x12, [x0, #48]
+ add x2, x2, x3
+ add x0, x0, x1
+ b.ne 1b
+ ret
+endfunc
+
+function ff_vp9_copy32_aarch64, export=1
+1:
+ ldp x5, x6, [x2]
+ ldp x7, x8, [x2, #16]
+ stp x5, x6, [x0]
+ subs w4, w4, #1
+ stp x7, x8, [x0, #16]
+ add x2, x2, x3
+ add x0, x0, x1
+ b.ne 1b
+ ret
+endfunc
diff --git a/libavcodec/aarch64/vp9mc_neon.S b/libavcodec/aarch64/vp9mc_neon.S
index f67624ca04..abf2bae9db 100644
--- a/libavcodec/aarch64/vp9mc_neon.S
+++ b/libavcodec/aarch64/vp9mc_neon.S
@@ -25,23 +25,6 @@
// const uint8_t *ref, ptrdiff_t ref_stride,
// int h, int mx, int my);
-function ff_vp9_copy64_aarch64, export=1
-1:
- ldp x5, x6, [x2]
- ldp x7, x8, [x2, #16]
- stp x5, x6, [x0]
- ldp x9, x10, [x2, #32]
- stp x7, x8, [x0, #16]
- subs w4, w4, #1
- ldp x11, x12, [x2, #48]
- stp x9, x10, [x0, #32]
- stp x11, x12, [x0, #48]
- add x2, x2, x3
- add x0, x0, x1
- b.ne 1b
- ret
-endfunc
-
function ff_vp9_avg64_neon, export=1
mov x5, x0
1:
@@ -64,19 +47,6 @@ function ff_vp9_avg64_neon, export=1
ret
endfunc
-function ff_vp9_copy32_aarch64, export=1
-1:
- ldp x5, x6, [x2]
- ldp x7, x8, [x2, #16]
- stp x5, x6, [x0]
- subs w4, w4, #1
- stp x7, x8, [x0, #16]
- add x2, x2, x3
- add x0, x0, x1
- b.ne 1b
- ret
-endfunc
-
function ff_vp9_avg32_neon, export=1
1:
ld1 {v2.16b, v3.16b}, [x2], x3

View File

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

View File

@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,1,10,0
PRODUCTVERSION 2,1,10,0
FILEVERSION 2,1,13,0
PRODUCTVERSION 2,1,13,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.1.10.0"
VALUE "FileVersion", "2.1.13.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2020"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "2.1.10.0"
VALUE "ProductVersion", "2.1.13.0"
END
END
BLOCK "VarFileInfo"

View File

@ -254,7 +254,7 @@ int main(int argc, char *argv[])
}
QByteArray inner = f.readAll();
stream << name << quint32(inner.size()) << inner;
#if defined Q_OS_MAC || defined Q_OS_LINUX
#ifdef Q_OS_UNIX
stream << (QFileInfo(fullName).isExecutable() ? true : false);
#endif
}
@ -467,10 +467,12 @@ int main(int argc, char *argv[])
QString outName(QString("tupdate%1").arg(AlphaVersion ? AlphaVersion : version));
#elif defined Q_OS_MAC
QString outName((targetosx ? QString("tosxupd%1") : QString("tmacupd%1")).arg(AlphaVersion ? AlphaVersion : version));
#elif defined Q_OS_LINUX32
#elif defined Q_OS_UNIX
#ifndef _LP64
QString outName(QString("tlinux32upd%1").arg(AlphaVersion ? AlphaVersion : version));
#elif defined Q_OS_LINUX64
#else
QString outName(QString("tlinuxupd%1").arg(AlphaVersion ? AlphaVersion : version));
#endif
#else
#error Unknown platform!
#endif

View File

@ -93,6 +93,7 @@ void SendExistingMedia(
};
TextUtilities::Trim(caption);
auto sentEntities = EntitiesToMTP(
session,
caption.entities,
ConvertOption::SkipLocal);
if (!sentEntities.v.isEmpty()) {

View File

@ -18,11 +18,13 @@ using namespace TextUtilities;
} // namespace
EntitiesInText EntitiesFromMTP(const QVector<MTPMessageEntity> &entities) {
EntitiesInText EntitiesFromMTP(
Main::Session *session,
const QVector<MTPMessageEntity> &entities) {
auto result = EntitiesInText();
if (!entities.isEmpty()) {
result.reserve(entities.size());
for_const (auto &entity, entities) {
for (const auto &entity : entities) {
switch (entity.type()) {
case mtpc_messageEntityUrl: { auto &d = entity.c_messageEntityUrl(); result.push_back({ EntityType::Url, d.voffset().v, d.vlength().v }); } break;
case mtpc_messageEntityTextUrl: { auto &d = entity.c_messageEntityTextUrl(); result.push_back({ EntityType::CustomUrl, d.voffset().v, d.vlength().v, Clean(qs(d.vurl())) }); } break;
@ -32,28 +34,30 @@ EntitiesInText EntitiesFromMTP(const QVector<MTPMessageEntity> &entities) {
case mtpc_messageEntityPhone: break; // Skipping phones.
case mtpc_messageEntityMention: { auto &d = entity.c_messageEntityMention(); result.push_back({ EntityType::Mention, d.voffset().v, d.vlength().v }); } break;
case mtpc_messageEntityMentionName: {
auto &d = entity.c_messageEntityMentionName();
auto data = [&d] {
if (auto user = Auth().data().userLoaded(d.vuser_id().v)) {
return MentionNameDataFromFields({
d.vuser_id().v,
user->accessHash() });
const auto &d = entity.c_messageEntityMentionName();
const auto data = [&] {
if (session) {
if (const auto user = session->data().userLoaded(d.vuser_id().v)) {
return MentionNameDataFromFields({
d.vuser_id().v,
user->accessHash() });
}
}
return MentionNameDataFromFields(d.vuser_id().v);
};
result.push_back({ EntityType::MentionName, d.voffset().v, d.vlength().v, data() });
}();
result.push_back({ EntityType::MentionName, d.voffset().v, d.vlength().v, data });
} break;
case mtpc_inputMessageEntityMentionName: {
auto &d = entity.c_inputMessageEntityMentionName();
auto data = ([&d]() -> QString {
if (d.vuser_id().type() == mtpc_inputUserSelf) {
return MentionNameDataFromFields(Auth().userId());
const auto &d = entity.c_inputMessageEntityMentionName();
const auto data = [&] {
if (session && d.vuser_id().type() == mtpc_inputUserSelf) {
return MentionNameDataFromFields(session->userId());
} else if (d.vuser_id().type() == mtpc_inputUser) {
auto &user = d.vuser_id().c_inputUser();
return MentionNameDataFromFields({ user.vuser_id().v, user.vaccess_hash().v });
}
return QString();
})();
}();
if (!data.isEmpty()) {
result.push_back({ EntityType::MentionName, d.voffset().v, d.vlength().v, data });
}
@ -74,11 +78,12 @@ EntitiesInText EntitiesFromMTP(const QVector<MTPMessageEntity> &entities) {
}
MTPVector<MTPMessageEntity> EntitiesToMTP(
not_null<Main::Session*> session,
const EntitiesInText &entities,
ConvertOption option) {
auto v = QVector<MTPMessageEntity>();
v.reserve(entities.size());
for_const (auto &entity, entities) {
for (const auto &entity : entities) {
if (entity.length() <= 0) continue;
if (option == ConvertOption::SkipLocal
&& entity.type() != EntityType::Bold
@ -103,15 +108,15 @@ MTPVector<MTPMessageEntity> EntitiesToMTP(
case EntityType::Cashtag: v.push_back(MTP_messageEntityCashtag(offset, length)); break;
case EntityType::Mention: v.push_back(MTP_messageEntityMention(offset, length)); break;
case EntityType::MentionName: {
auto inputUser = ([](const QString &data) -> MTPInputUser {
auto inputUser = [&](const QString &data) -> MTPInputUser {
auto fields = MentionNameDataToFields(data);
if (fields.userId == Auth().userId()) {
if (session && fields.userId == session->userId()) {
return MTP_inputUserSelf();
} else if (fields.userId) {
return MTP_inputUser(MTP_int(fields.userId), MTP_long(fields.accessHash));
}
return MTP_inputUserEmpty();
})(entity.data());
}(entity.data());
if (inputUser.type() != mtpc_inputUserEmpty) {
v.push_back(MTP_inputMessageEntityMentionName(offset, length, inputUser));
}

View File

@ -9,14 +9,23 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/text/text_entity.h"
namespace Main {
class Session;
} // namespace Main
namespace Api {
EntitiesInText EntitiesFromMTP(const QVector<MTPMessageEntity> &entities);
enum class ConvertOption {
WithLocal,
SkipLocal,
};
MTPVector<MTPMessageEntity> EntitiesToMTP(
[[nodiscard]] EntitiesInText EntitiesFromMTP(
Main::Session *session,
const QVector<MTPMessageEntity> &entities);
[[nodiscard]] MTPVector<MTPMessageEntity> EntitiesToMTP(
not_null<Main::Session*> session,
const EntitiesInText &entities,
ConvertOption option = ConvertOption::WithLocal);

View File

@ -411,7 +411,7 @@ void ApiWrap::requestTermsUpdate() {
const auto &terms = data.vterms_of_service();
const auto &fields = terms.c_help_termsOfService();
Core::App().lockByTerms(
Window::TermsLock::FromMTP(fields));
Window::TermsLock::FromMTP(&session(), fields));
requestNext(data);
} break;
default: Unexpected("Type in requestTermsUpdate().");
@ -2442,6 +2442,7 @@ void ApiWrap::saveDraftsToCloud() {
flags |= MTPmessages_SaveDraft::Flag::f_entities;
}
auto entities = Api::EntitiesToMTP(
&session(),
TextUtilities::ConvertTextTagsToEntities(textWithTags.tags),
Api::ConvertOption::SkipLocal);
@ -4674,6 +4675,7 @@ void ApiWrap::editUploadedFile(
}
auto sentEntities = Api::EntitiesToMTP(
&session(),
item->originalText().entities,
Api::ConvertOption::SkipLocal);
@ -4826,8 +4828,11 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
if (silentPost) {
sendFlags |= MTPmessages_SendMessage::Flag::f_silent;
}
auto localEntities = Api::EntitiesToMTP(sending.entities);
auto localEntities = Api::EntitiesToMTP(
&session(),
sending.entities);
auto sentEntities = Api::EntitiesToMTP(
&session(),
sending.entities,
Api::ConvertOption::SkipLocal);
if (!sentEntities.v.isEmpty()) {
@ -5118,6 +5123,7 @@ void ApiWrap::sendMediaWithRandomId(
auto caption = item->originalText();
TextUtilities::Trim(caption);
auto sentEntities = Api::EntitiesToMTP(
&session(),
caption.entities,
Api::ConvertOption::SkipLocal);
@ -5794,6 +5800,7 @@ void ApiWrap::rescheduleMessage(
Api::SendOptions options) {
const auto text = item->originalText().text;
const auto sentEntities = Api::EntitiesToMTP(
&session(),
item->originalText().entities,
Api::ConvertOption::SkipLocal);
const auto media = item->media();

View File

@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_document_media.h"
#include "history/history.h"
#include "history/history_item.h"
#include "platform/platform_specific.h"
#include "lang/lang_keys.h"
#include "layout.h"
#include "media/streaming/media_streaming_instance.h"
@ -327,10 +328,6 @@ EditCaptionBox::EditCaptionBox(
) | rpl::start_with_next([&](bool checked) {
_asFile = checked;
}, _wayWrap->lifetime());
if (_animated) {
prepareStreamedPreview();
}
}
EditCaptionBox::~EditCaptionBox() = default;
@ -590,6 +587,10 @@ void EditCaptionBox::createEditMediaButton() {
}
void EditCaptionBox::prepare() {
if (_animated) {
prepareStreamedPreview();
}
addButton(tr::lng_settings_save(), [this] { save(); });
if (_isAllowedEditMedia) {
createEditMediaButton();
@ -656,7 +657,10 @@ bool EditCaptionBox::fileFromClipboard(not_null<const QMimeData*> data) {
if (result.error == Error::None) {
return result;
} else if (data->hasImage()) {
auto image = qvariant_cast<QImage>(data->imageData());
auto image = Platform::GetImageFromClipboard();
if (image.isNull()) {
image = qvariant_cast<QImage>(data->imageData());
}
if (!image.isNull()) {
_isImage = true;
_photo = true;
@ -934,6 +938,7 @@ void EditCaptionBox::save() {
TextUtilities::Trim(sending);
const auto sentEntities = Api::EntitiesToMTP(
&item->history()->session(),
sending.entities,
Api::ConvertOption::SkipLocal);
if (!sentEntities.v.isEmpty()) {

View File

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/send_files_box.h"
#include "platform/platform_specific.h"
#include "lang/lang_keys.h"
#include "storage/localstorage.h"
#include "storage/storage_media_prepare.h"
@ -2168,7 +2169,10 @@ bool SendFilesBox::addFiles(not_null<const QMimeData*> data) {
if (result.error == Storage::PreparedList::Error::None) {
return result;
} else if (data->hasImage()) {
auto image = qvariant_cast<QImage>(data->imageData());
auto image = Platform::GetImageFromClipboard();
if (image.isNull()) {
image = qvariant_cast<QImage>(data->imageData());
}
if (!image.isNull()) {
return Storage::PrepareMediaFromImage(
std::move(image),

View File

@ -326,7 +326,9 @@ void StickersBox::prepare() {
_session->api().updateStickers();
if (_installed.widget()) {
connect(_installed.widget(), SIGNAL(draggingScrollDelta(int)), this, SLOT(onDraggingScrollDelta(int)));
connect(_installed.widget(), &Inner::draggingScrollDelta, [=](int delta) {
scrollByDraggingDelta(delta);
});
if (!_megagroupSet) {
boxClosing() | rpl::start_with_next([=] {
saveChanges();

View File

@ -798,13 +798,9 @@ void Application::notifyFileDialogShown(bool shown) {
}
QWidget *Application::getModalParent() {
#ifdef Q_OS_LINUX
return Platform::IsWayland()
? App::wnd()
: nullptr;
#endif // Q_OS_LINUX
return nullptr;
}

View File

@ -39,7 +39,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "client/crashpad_client.h"
#endif // else for MAC_USE_BREAKPAD
#elif defined Q_OS_LINUX64 || defined Q_OS_LINUX32 // Q_OS_MAC
#elif defined Q_OS_UNIX // Q_OS_MAC
#include <execinfo.h>
#include <signal.h>
@ -47,7 +47,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "client/linux/handler/exception_handler.h"
#endif // Q_OS_LINUX64 || Q_OS_LINUX32
#endif // Q_OS_UNIX
#endif // !DESKTOP_APP_DISABLE_CRASH_REPORTS
@ -140,7 +140,7 @@ QMutex ReportingMutex;
const char *BreakpadDumpPath = nullptr;
const wchar_t *BreakpadDumpPathW = nullptr;
#if defined Q_OS_MAC || defined Q_OS_LINUX32 || defined Q_OS_LINUX64
#ifdef Q_OS_UNIX
struct sigaction SIG_def[32];
void SignalHandler(int signum, siginfo_t *info, void *ucontext) {
@ -148,9 +148,9 @@ void SignalHandler(int signum, siginfo_t *info, void *ucontext) {
sigaction(signum, &SIG_def[signum], 0);
}
#else // Q_OS_MAC || Q_OS_LINUX32 || Q_OS_LINUX64
#else // Q_OS_UNIX
void SignalHandler(int signum) {
#endif // else for Q_OS_MAC || Q_OS_LINUX || Q_OS_LINUX64
#endif // else for Q_OS_UNIX
const char* name = 0;
switch (signum) {
@ -212,7 +212,7 @@ void SignalHandler(int signum) {
}
// see https://github.com/benbjohnson/bandicoot
#if defined Q_OS_MAC || defined Q_OS_LINUX32 || defined Q_OS_LINUX64
#ifdef Q_OS_UNIX
ucontext_t *uc = (ucontext_t*)ucontext;
void *caller = 0;
@ -276,9 +276,9 @@ void SignalHandler(int signum) {
backtrace_symbols_fd(addresses, size, ReportFileNo);
#else // Q_OS_MAC || Q_OS_LINUX32 || Q_OS_LINUX64
#else // Q_OS_UNIX
dump() << "\nBacktrace omitted.\n";
#endif // else for Q_OS_MAC || Q_OS_LINUX32 || Q_OS_LINUX64
#endif // else for Q_OS_UNIX
dump() << "\n";
@ -294,9 +294,9 @@ google_breakpad::ExceptionHandler* BreakpadExceptionHandler = 0;
bool DumpCallback(const wchar_t* _dump_dir, const wchar_t* _minidump_id, void* context, EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion, bool success)
#elif defined Q_OS_MAC // Q_OS_WIN
bool DumpCallback(const char* _dump_dir, const char* _minidump_id, void *context, bool success)
#elif defined Q_OS_LINUX64 || defined Q_OS_LINUX32 // Q_OS_MAC
#elif defined Q_OS_UNIX // Q_OS_MAC
bool DumpCallback(const google_breakpad::MinidumpDescriptor &md, void *context, bool success)
#endif // Q_OS_LINUX64 || Q_OS_LINUX32
#endif // Q_OS_UNIX
{
if (CrashLogged) return success;
CrashLogged = true;
@ -392,7 +392,7 @@ void StartCatching(not_null<Core::Launcher*> launcher) {
crashpad_client.UseHandler();
}
#endif // else for MAC_USE_BREAKPAD
#elif defined Q_OS_LINUX64 || defined Q_OS_LINUX32
#elif defined Q_OS_UNIX
BreakpadExceptionHandler = new google_breakpad::ExceptionHandler(
google_breakpad::MinidumpDescriptor(QFile::encodeName(dumpspath).toStdString()),
/*FilterCallback*/ 0,
@ -401,7 +401,7 @@ void StartCatching(not_null<Core::Launcher*> launcher) {
true,
-1
);
#endif // Q_OS_LINUX64 || Q_OS_LINUX32
#endif // Q_OS_UNIX
#endif // !DESKTOP_APP_DISABLE_CRASH_REPORTS
}

View File

@ -291,7 +291,7 @@ void Launcher::init() {
QApplication::setApplicationName(qsl("KotatogramDesktop"));
#if defined(Q_OS_LINUX) && QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
#if defined Q_OS_UNIX && !defined Q_OS_MAC && QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
QApplication::setDesktopFileName(Platform::GetLauncherFilename());
#endif

View File

@ -392,7 +392,9 @@ bool HandleUnknown(
const auto callback = [=](const MTPDhelp_deepLinkInfo &result) {
const auto text = TextWithEntities{
qs(result.vmessage()),
Api::EntitiesFromMTP(result.ventities().value_or_empty())
Api::EntitiesFromMTP(
session,
result.ventities().value_or_empty())
};
if (result.is_update_app()) {
const auto box = std::make_shared<QPointer<Ui::BoxContent>>();

View File

@ -27,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "facades.h"
#include "app.h"
#include <QtGui/QSessionManager>
#include <QtGui/QScreen>
namespace Core {
@ -84,9 +85,9 @@ Sandbox::Sandbox(
: QApplication(argc, argv)
, _mainThreadId(QThread::currentThreadId())
, _handleObservables([=] {
Expects(_application != nullptr);
_application->call_handleObservables();
if (_application) {
_application->call_handleObservables();
}
})
, _launcher(launcher) {
}
@ -132,6 +133,19 @@ int Sandbox::start() {
});
});
// https://github.com/telegramdesktop/tdesktop/issues/948
// and https://github.com/telegramdesktop/tdesktop/issues/5022
const auto restartHint = [](QSessionManager &manager) {
manager.setRestartHint(QSessionManager::RestartNever);
};
connect(
this,
&QGuiApplication::saveStateRequest,
this,
restartHint,
Qt::DirectConnection);
if (cManyInstance()) {
LOG(("Many instance allowed, starting..."));
singleInstanceChecked();

View File

@ -79,68 +79,68 @@ void UiIntegration::startFontsEnd() {
}
std::shared_ptr<ClickHandler> UiIntegration::createLinkHandler(
EntityType type,
const QString &text,
const QString &data,
const TextParseOptions &options) {
switch (type) {
const EntityLinkData &data,
const std::any &context) {
const auto my = std::any_cast<Context>(&context);
switch (data.type) {
case EntityType::Url:
return (!data.isEmpty() && UrlClickHandler::IsSuspicious(data))
? std::make_shared<HiddenUrlClickHandler>(data)
: nullptr;
return (!data.data.isEmpty()
&& UrlClickHandler::IsSuspicious(data.data))
? std::make_shared<HiddenUrlClickHandler>(data.data)
: Integration::createLinkHandler(data, context);
case EntityType::CustomUrl:
return !data.isEmpty()
? std::make_shared<HiddenUrlClickHandler>(data)
: nullptr;
return !data.data.isEmpty()
? std::make_shared<HiddenUrlClickHandler>(data.data)
: Integration::createLinkHandler(data, context);
case EntityType::BotCommand:
return std::make_shared<BotCommandClickHandler>(data);
return std::make_shared<BotCommandClickHandler>(data.data);
case EntityType::Hashtag:
if (options.flags & TextTwitterMentions) {
if (my && my->type == HashtagMentionType::Twitter) {
return std::make_shared<UrlClickHandler>(
(qsl("https://twitter.com/hashtag/")
+ data.mid(1)
+ data.data.mid(1)
+ qsl("?src=hash")),
true);
} else if (options.flags & TextInstagramMentions) {
} else if (my && my->type == HashtagMentionType::Instagram) {
return std::make_shared<UrlClickHandler>(
(qsl("https://instagram.com/explore/tags/")
+ data.mid(1)
+ data.data.mid(1)
+ '/'),
true);
}
return std::make_shared<HashtagClickHandler>(data);
return std::make_shared<HashtagClickHandler>(data.data);
case EntityType::Cashtag:
return std::make_shared<CashtagClickHandler>(data);
return std::make_shared<CashtagClickHandler>(data.data);
case EntityType::Mention:
if (options.flags & TextTwitterMentions) {
if (my && my->type == HashtagMentionType::Twitter) {
return std::make_shared<UrlClickHandler>(
qsl("https://twitter.com/") + data.mid(1),
qsl("https://twitter.com/") + data.data.mid(1),
true);
} else if (options.flags & TextInstagramMentions) {
} else if (my && my->type == HashtagMentionType::Instagram) {
return std::make_shared<UrlClickHandler>(
qsl("https://instagram.com/") + data.mid(1) + '/',
qsl("https://instagram.com/") + data.data.mid(1) + '/',
true);
}
return std::make_shared<MentionClickHandler>(data);
return std::make_shared<MentionClickHandler>(data.data);
case EntityType::MentionName: {
auto fields = TextUtilities::MentionNameDataToFields(data);
auto fields = TextUtilities::MentionNameDataToFields(data.data);
if (fields.userId) {
return std::make_shared<MentionNameClickHandler>(
text,
data.text,
fields.userId,
fields.accessHash);
} else {
LOG(("Bad mention name: %1").arg(data));
LOG(("Bad mention name: %1").arg(data.data));
}
} break;
}
return nullptr;
return Integration::createLinkHandler(data, context);
}
bool UiIntegration::handleUrlClick(

View File

@ -13,6 +13,15 @@ namespace Core {
class UiIntegration : public Ui::Integration {
public:
enum class HashtagMentionType : uchar {
Telegram,
Twitter,
Instagram,
};
struct Context {
HashtagMentionType type = HashtagMentionType::Telegram;
};
void postponeCall(FnMut<void()> &&callable) override;
void registerLeaveSubscription(not_null<QWidget*> widget) override;
void unregisterLeaveSubscription(not_null<QWidget*> widget) override;
@ -27,10 +36,8 @@ public:
void startFontsEnd() override;
std::shared_ptr<ClickHandler> createLinkHandler(
EntityType type,
const QString &text,
const QString &data,
const TextParseOptions &options) override;
const EntityLinkData &data,
const std::any &context) override;
bool handleUrlClick(
const QString &url,
const QVariant &context) override;

View File

@ -409,9 +409,9 @@ bool UnpackUpdate(const QString &filepath) {
bool executable = false;
stream >> relativeName >> fileSize >> fileInnerData;
#if defined Q_OS_MAC || defined Q_OS_LINUX
#ifdef Q_OS_UNIX
stream >> executable;
#endif // Q_OS_MAC || Q_OS_LINUX
#endif // Q_OS_UNIX
if (stream.status() != QDataStream::Ok) {
LOG(("Update Error: cant read file from downloaded stream, status: %1").arg(stream.status()));
return false;
@ -1511,10 +1511,10 @@ bool checkReadyUpdate() {
#elif defined Q_OS_MAC // Q_OS_WIN
QString curUpdater = (cExeDir() + cExeName() + qsl("/Contents/Frameworks/Updater"));
QFileInfo updater(cWorkingDir() + qsl("tupdates/temp/Kotatogram.app/Contents/Frameworks/Updater"));
#elif defined Q_OS_LINUX // Q_OS_MAC
#elif defined Q_OS_UNIX // Q_OS_MAC
QString curUpdater = (cExeDir() + qsl("Updater"));
QFileInfo updater(cWorkingDir() + qsl("tupdates/temp/Updater"));
#endif // Q_OS_LINUX
#endif // Q_OS_UNIX
if (!updater.exists()) {
QFileInfo current(curUpdater);
if (!current.exists()) {
@ -1548,12 +1548,12 @@ bool checkReadyUpdate() {
ClearAll();
return false;
}
#elif defined Q_OS_LINUX // Q_OS_MAC
#elif defined Q_OS_UNIX // Q_OS_MAC
if (!linuxMoveFile(QFile::encodeName(updater.absoluteFilePath()).constData(), QFile::encodeName(curUpdater).constData())) {
ClearAll();
return false;
}
#endif // Q_OS_LINUX
#endif // Q_OS_UNIX
#ifdef Q_OS_MAC
Platform::RemoveQuarantine(QFileInfo(curUpdater).absolutePath());

View File

@ -23,7 +23,7 @@ constexpr auto AppId = "{C4A4AE8F-B9F7-4CC7-8A6C-BF7EEE87ACA5}"_cs;
constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs;
constexpr auto AppName = "Kotatogram Desktop"_cs;
constexpr auto AppFile = "Kotatogram"_cs;
constexpr auto AppVersion = 2001010;
constexpr auto AppVersionStr = "2.1.10";
constexpr auto AppVersion = 2001013;
constexpr auto AppVersionStr = "2.1.13";
constexpr auto AppBetaVersion = true;
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;

View File

@ -797,7 +797,9 @@ bool DocumentData::saveToCache() const {
|| isAnimation()
|| isVoiceMessage()
|| (type == WallPaperDocument)
|| isTheme());
|| isTheme()
|| (mimeString() == qstr("image/png")
&& _filename.startsWith("image_")));
}
void DocumentData::automaticLoadSettingsChanged() {
@ -1615,10 +1617,10 @@ bool IsExecutableName(const QString &filepath) {
qsl("\
applescript action app bin command csh osx workflow terminal url caction \
mpkg pkg scpt scptd xhtm webarchive");
#elif defined Q_OS_LINUX // Q_OS_MAC
#elif defined Q_OS_UNIX // Q_OS_MAC
qsl("bin csh deb desktop ksh out pet pkg pup rpm run sh shar \
slp zsh");
#else // Q_OS_MAC || Q_OS_LINUX
#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 \
@ -1631,7 +1633,7 @@ psm1 pssc pst py py3 pyc pyd pyi pyo pyw pywz pyz rb reg rgs scf scr sct \
search-ms settingcontent-ms shb shs slk sys t tmp u3p url vb vbe vbp vbs \
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_LINUX
#endif // !Q_OS_MAC && !Q_OS_UNIX
const auto list = joined.split(' ');
return base::flat_set<QString>(list.begin(), list.end());
}();

View File

@ -45,14 +45,19 @@ Draft::Draft(
, previewCancelled(previewCancelled) {
}
void applyPeerCloudDraft(PeerId peerId, const MTPDdraftMessage &draft) {
const auto history = Auth().data().history(peerId);
void ApplyPeerCloudDraft(
not_null<Main::Session*> session,
PeerId peerId,
const MTPDdraftMessage &draft) {
const auto history = session->data().history(peerId);
const auto textWithTags = TextWithTags {
qs(draft.vmessage()),
TextUtilities::ConvertEntitiesToTextTags(
Api::EntitiesFromMTP(draft.ventities().value_or_empty()))
Api::EntitiesFromMTP(
session,
draft.ventities().value_or_empty()))
};
auto replyTo = draft.vreply_to_msg_id().value_or_empty();
const auto replyTo = draft.vreply_to_msg_id().value_or_empty();
if (history->skipCloudDraft(textWithTags.text, replyTo, draft.vdate().v)) {
return;
}
@ -67,8 +72,11 @@ void applyPeerCloudDraft(PeerId peerId, const MTPDdraftMessage &draft) {
history->applyCloudDraft();
}
void clearPeerCloudDraft(PeerId peerId, TimeId date) {
const auto history = Auth().data().history(peerId);
void ClearPeerCloudDraft(
not_null<Main::Session*> session,
PeerId peerId,
TimeId date) {
const auto history = session->data().history(peerId);
if (history->skipCloudDraft(QString(), MsgId(0), date)) {
return;
}

View File

@ -11,10 +11,20 @@ namespace Ui {
class InputField;
} // namespace Ui
namespace Main {
class Session;
} // namespace Main
namespace Data {
void applyPeerCloudDraft(PeerId peerId, const MTPDdraftMessage &draft);
void clearPeerCloudDraft(PeerId peerId, TimeId date);
void ApplyPeerCloudDraft(
not_null<Main::Session*> session,
PeerId peerId,
const MTPDdraftMessage &draft);
void ClearPeerCloudDraft(
not_null<Main::Session*> session,
PeerId peerId,
TimeId date);
struct Draft {
Draft() = default;

View File

@ -244,8 +244,9 @@ TextWithEntities Media::consumedMessageText() const {
}
std::unique_ptr<HistoryView::Media> Media::createView(
not_null<HistoryView::Element*> message) {
return createView(message, message->data());
not_null<HistoryView::Element*> message,
HistoryView::Element *replacing) {
return createView(message, message->data(), replacing);
}
MediaPhoto::MediaPhoto(
@ -386,7 +387,8 @@ bool MediaPhoto::updateSentMedia(const MTPMessageMedia &media) {
std::unique_ptr<HistoryView::Media> MediaPhoto::createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent) {
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing) {
if (_chat) {
return std::make_unique<HistoryView::Photo>(
message,
@ -663,11 +665,15 @@ bool MediaFile::updateSentMedia(const MTPMessageMedia &media) {
std::unique_ptr<HistoryView::Media> MediaFile::createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent) {
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing) {
if (_document->sticker()) {
return std::make_unique<HistoryView::UnwrappedMedia>(
message,
std::make_unique<HistoryView::Sticker>(message, _document));
std::make_unique<HistoryView::Sticker>(
message,
_document,
replacing));
} else if (_document->isAnimation() || _document->isVideoFile()) {
return std::make_unique<HistoryView::Gif>(
message,
@ -760,7 +766,8 @@ bool MediaContact::updateSentMedia(const MTPMessageMedia &media) {
std::unique_ptr<HistoryView::Media> MediaContact::createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent) {
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing) {
return std::make_unique<HistoryView::Contact>(
message,
_contact.userId,
@ -840,7 +847,8 @@ bool MediaLocation::updateSentMedia(const MTPMessageMedia &media) {
std::unique_ptr<HistoryView::Media> MediaLocation::createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent) {
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing) {
return std::make_unique<HistoryView::Location>(
message,
_location,
@ -900,7 +908,8 @@ bool MediaCall::updateSentMedia(const MTPMessageMedia &media) {
std::unique_ptr<HistoryView::Media> MediaCall::createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent) {
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing) {
return std::make_unique<HistoryView::Call>(message, &_call);
}
@ -995,7 +1004,8 @@ bool MediaWebPage::updateSentMedia(const MTPMessageMedia &media) {
std::unique_ptr<HistoryView::Media> MediaWebPage::createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent) {
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing) {
return std::make_unique<HistoryView::WebPage>(message, _page);
}
@ -1086,7 +1096,8 @@ bool MediaGame::updateSentMedia(const MTPMessageMedia &media) {
std::unique_ptr<HistoryView::Media> MediaGame::createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent) {
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing) {
return std::make_unique<HistoryView::Game>(
message,
_game,
@ -1151,7 +1162,8 @@ bool MediaInvoice::updateSentMedia(const MTPMessageMedia &media) {
std::unique_ptr<HistoryView::Media> MediaInvoice::createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent) {
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing) {
return std::make_unique<HistoryView::Invoice>(message, &_invoice);
}
@ -1217,7 +1229,8 @@ bool MediaPoll::updateSentMedia(const MTPMessageMedia &media) {
std::unique_ptr<HistoryView::Media> MediaPoll::createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent) {
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing) {
return std::make_unique<HistoryView::Poll>(message, _poll);
}
@ -1274,7 +1287,8 @@ bool MediaDice::updateSentMedia(const MTPMessageMedia &media) {
std::unique_ptr<HistoryView::Media> MediaDice::createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent) {
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing) {
return std::make_unique<HistoryView::UnwrappedMedia>(
message,
std::make_unique<HistoryView::Dice>(message, this));

View File

@ -111,9 +111,11 @@ public:
virtual bool updateSentMedia(const MTPMessageMedia &media) = 0;
virtual std::unique_ptr<HistoryView::Media> createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent) = 0;
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing = nullptr) = 0;
std::unique_ptr<HistoryView::Media> createView(
not_null<HistoryView::Element*> message);
not_null<HistoryView::Element*> message,
HistoryView::Element *replacing = nullptr);
private:
const not_null<HistoryItem*> _parent;
@ -152,7 +154,8 @@ public:
bool updateSentMedia(const MTPMessageMedia &media) override;
std::unique_ptr<HistoryView::Media> createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent) override;
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing = nullptr) override;
private:
not_null<PhotoData*> _photo;
@ -189,7 +192,8 @@ public:
bool updateSentMedia(const MTPMessageMedia &media) override;
std::unique_ptr<HistoryView::Media> createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent) override;
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing = nullptr) override;
private:
not_null<DocumentData*> _document;
@ -218,7 +222,8 @@ public:
bool updateSentMedia(const MTPMessageMedia &media) override;
std::unique_ptr<HistoryView::Media> createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent) override;
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing = nullptr) override;
private:
SharedContact _contact;
@ -248,7 +253,8 @@ public:
bool updateSentMedia(const MTPMessageMedia &media) override;
std::unique_ptr<HistoryView::Media> createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent) override;
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing = nullptr) override;
private:
LocationPoint _point;
@ -276,7 +282,8 @@ public:
bool updateSentMedia(const MTPMessageMedia &media) override;
std::unique_ptr<HistoryView::Media> createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent) override;
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing = nullptr) override;
static QString Text(
not_null<HistoryItem*> item,
@ -312,7 +319,8 @@ public:
bool updateSentMedia(const MTPMessageMedia &media) override;
std::unique_ptr<HistoryView::Media> createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent) override;
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing = nullptr) override;
private:
not_null<WebPageData*> _page;
@ -343,7 +351,8 @@ public:
bool updateSentMedia(const MTPMessageMedia &media) override;
std::unique_ptr<HistoryView::Media> createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent) override;
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing = nullptr) override;
private:
not_null<GameData*> _game;
@ -374,7 +383,8 @@ public:
bool updateSentMedia(const MTPMessageMedia &media) override;
std::unique_ptr<HistoryView::Media> createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent) override;
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing = nullptr) override;
private:
Invoice _invoice;
@ -401,7 +411,8 @@ public:
bool updateSentMedia(const MTPMessageMedia &media) override;
std::unique_ptr<HistoryView::Media> createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent) override;
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing = nullptr) override;
private:
not_null<PollData*> _poll;
@ -425,7 +436,8 @@ public:
bool updateSentMedia(const MTPMessageMedia &media) override;
std::unique_ptr<HistoryView::Media> createView(
not_null<HistoryView::Element*> message,
not_null<HistoryItem*> realParent) override;
not_null<HistoryItem*> realParent,
HistoryView::Element *replacing = nullptr) override;
private:
QString _emoji;

View File

@ -45,6 +45,14 @@ PollData::PollData(not_null<Data::Session*> owner, PollId id)
, _owner(owner) {
}
Data::Session &PollData::owner() const {
return *_owner;
}
Main::Session &PollData::session() const {
return _owner->session();
}
bool PollData::closeByTimer() {
if (closed()) {
return false;
@ -151,6 +159,7 @@ bool PollData::applyResults(const MTPPollResults &results) {
auto newSolution = TextWithEntities{
results.vsolution().value_or_empty(),
Api::EntitiesFromMTP(
&_owner->session(),
results.vsolution_entities().value_or_empty())
};
if (solution != newSolution) {
@ -293,6 +302,7 @@ MTPInputMedia PollDataToInputMedia(
TextUtilities::PrepareForSending(solution, prepareFlags);
TextUtilities::Trim(solution);
const auto sentEntities = Api::EntitiesToMTP(
&poll->session(),
solution.entities,
Api::ConvertOption::SkipLocal);
if (!solution.text.isEmpty()) {

View File

@ -11,6 +11,10 @@ namespace Data {
class Session;
} // namespace Data
namespace Main {
class Session;
} // namespace Main
struct PollAnswer {
QString text;
QByteArray option;
@ -31,6 +35,9 @@ inline bool operator!=(const PollAnswer &a, const PollAnswer &b) {
struct PollData {
PollData(not_null<Data::Session*> owner, PollId id);
[[nodiscard]] Data::Session &owner() const;
[[nodiscard]] Main::Session &session() const;
enum class Flag {
Closed = 0x01,
PublicVotes = 0x02,

View File

@ -152,7 +152,7 @@ void ScheduledMessages::sendNowSimpleMessage(
// we know for sure that a message can't have fields such as the author,
// views count, etc.
const auto &history = local->history();
const auto history = local->history();
auto flags = NewMessageFlags(history->peer)
| MTPDmessage::Flag::f_entities
| MTPDmessage::Flag::f_from_id
@ -175,7 +175,9 @@ void ScheduledMessages::sendNowSimpleMessage(
MTP_string(local->originalText().text),
MTP_messageMediaEmpty(),
MTPReplyMarkup(),
Api::EntitiesToMTP(local->originalText().entities),
Api::EntitiesToMTP(
&history->session(),
local->originalText().entities),
MTP_int(1),
MTPint(),
MTP_string(),
@ -234,7 +236,7 @@ void ScheduledMessages::checkEntitiesAndUpdate(const MTPDmessage &data) {
Assert(existing->date() == kScheduledUntilOnlineTimestamp);
existing->updateSentContent({
qs(data.vmessage()),
Api::EntitiesFromMTP(data.ventities().value_or_empty())
Api::EntitiesFromMTP(_session, data.ventities().value_or_empty())
}, data.vmedia());
existing->updateReplyMarkup(data.vreply_markup());
existing->updateForwardedInfo(data.vfwd_from());
@ -410,7 +412,9 @@ HistoryItem *ScheduledMessages::append(
message.match([&](const MTPDmessage &data) {
existing->updateSentContent({
qs(data.vmessage()),
Api::EntitiesFromMTP(data.ventities().value_or_empty())
Api::EntitiesFromMTP(
_session,
data.ventities().value_or_empty())
}, data.vmedia());
existing->updateReplyMarkup(data.vreply_markup());
existing->updateForwardedInfo(data.vfwd_from());

View File

@ -1703,7 +1703,9 @@ bool Session::checkEntitiesAndViewsUpdate(const MTPDmessage &data) {
if (const auto existing = message(peerToChannel(peer), data.vid().v)) {
existing->updateSentContent({
qs(data.vmessage()),
Api::EntitiesFromMTP(data.ventities().value_or_empty())
Api::EntitiesFromMTP(
&session(),
data.ventities().value_or_empty())
}, data.vmedia());
existing->updateReplyMarkup(data.vreply_markup());
existing->updateForwardedInfo(data.vfwd_from());
@ -3725,7 +3727,7 @@ void Session::insertCheckedServiceNotification(
MTP_string(sending.text),
media,
MTPReplyMarkup(),
Api::EntitiesToMTP(sending.entities),
Api::EntitiesToMTP(&session(), sending.entities),
MTPint(),
MTPint(),
MTPstring(),

View File

@ -538,13 +538,15 @@ HistoryView::Context InnerWidget::elementContext() {
}
std::unique_ptr<HistoryView::Element> InnerWidget::elementCreate(
not_null<HistoryMessage*> message) {
return std::make_unique<HistoryView::Message>(this, message);
not_null<HistoryMessage*> message,
Element *replacing) {
return std::make_unique<HistoryView::Message>(this, message, replacing);
}
std::unique_ptr<HistoryView::Element> InnerWidget::elementCreate(
not_null<HistoryService*> message) {
return std::make_unique<HistoryView::Service>(this, message);
not_null<HistoryService*> message,
Element *replacing) {
return std::make_unique<HistoryView::Service>(this, message, replacing);
}
bool InnerWidget::elementUnderCursor(
@ -1535,13 +1537,13 @@ void InnerWidget::mouseActionFinish(const QPoint &screenPos, Qt::MouseButton but
_mouseSelectType = TextSelectType::Letters;
//_widget->noSelectingScroll(); // TODO
#if defined Q_OS_LINUX32 || defined Q_OS_LINUX64
#if defined Q_OS_UNIX && !defined Q_OS_MAC
if (_selectedItem && _selectedText.from != _selectedText.to) {
TextUtilities::SetClipboardText(
_selectedItem->selectedText(_selectedText),
QClipboard::Selection);
}
#endif // Q_OS_LINUX32 || Q_OS_LINUX64
#endif // Q_OS_UNIX && !Q_OS_MAC
}
void InnerWidget::updateSelected() {

View File

@ -89,9 +89,11 @@ public:
// HistoryView::ElementDelegate interface.
HistoryView::Context elementContext() override;
std::unique_ptr<HistoryView::Element> elementCreate(
not_null<HistoryMessage*> message) override;
not_null<HistoryMessage*> message,
HistoryView::Element *replacing = nullptr) override;
std::unique_ptr<HistoryView::Element> elementCreate(
not_null<HistoryService*> message) override;
not_null<HistoryService*> message,
HistoryView::Element *replacing = nullptr) override;
bool elementUnderCursor(
not_null<const HistoryView::Element*> view) override;
void elementAnimationAutoplayAsync(

View File

@ -111,14 +111,16 @@ bool MediaCanHaveCaption(const MTPMessage &message) {
return (mediaType == mtpc_messageMediaDocument || mediaType == mtpc_messageMediaPhoto);
}
TextWithEntities ExtractEditedText(const MTPMessage &message) {
TextWithEntities ExtractEditedText(
not_null<Main::Session*> session,
const MTPMessage &message) {
if (message.type() != mtpc_message) {
return TextWithEntities();
}
const auto &data = message.c_message();
return {
TextUtilities::Clean(qs(data.vmessage())),
Api::EntitiesFromMTP(data.ventities().value_or_empty())
Api::EntitiesFromMTP(session, data.ventities().value_or_empty())
};
}
@ -376,19 +378,20 @@ void GenerateItems(
Fn<void(OwnedItem item)> callback) {
Expects(history->peer->isChannel());
auto id = event.vid().v;
auto from = Auth().data().user(event.vuser_id().v);
auto channel = history->peer->asChannel();
auto &action = event.vaction();
auto date = event.vdate().v;
auto addPart = [&](not_null<HistoryItem*> item) {
const auto session = &history->session();
const auto id = event.vid().v;
const auto from = Auth().data().user(event.vuser_id().v);
const auto channel = history->peer->asChannel();
const auto &action = event.vaction();
const auto date = event.vdate().v;
const auto addPart = [&](not_null<HistoryItem*> item) {
return callback(OwnedItem(delegate, item));
};
using Flag = MTPDmessage::Flag;
auto fromName = from->name;
auto fromLink = from->createOpenLink();
auto fromLinkText = textcmdLink(1, fromName);
const auto fromName = from->name;
const auto fromLink = from->createOpenLink();
const auto fromLinkText = textcmdLink(1, fromName);
auto addSimpleServiceMessage = [&](const QString &text, PhotoData *photo = nullptr) {
auto message = HistoryService::PreparedText { text };
@ -542,7 +545,7 @@ void GenerateItems(
};
auto createEditMessage = [&](const MTPDchannelAdminLogEventActionEditMessage &action) {
auto newValue = ExtractEditedText(action.vnew_message());
auto newValue = ExtractEditedText(session, action.vnew_message());
auto canHaveCaption = MediaCanHaveCaption(action.vnew_message());
auto text = (!canHaveCaption
? tr::lng_admin_log_edited_message
@ -554,7 +557,7 @@ void GenerateItems(
fromLinkText);
addSimpleServiceMessage(text);
auto oldValue = ExtractEditedText(action.vprev_message());
auto oldValue = ExtractEditedText(session, action.vprev_message());
auto detachExistingItem = false;
auto body = history->createItem(
PrepareLogMessage(

View File

@ -2700,7 +2700,10 @@ void History::applyDialog(
const auto draft = data.vdraft();
if (draft && draft->type() == mtpc_draftMessage) {
Data::applyPeerCloudDraft(peer->id, draft->c_draftMessage());
Data::ApplyPeerCloudDraft(
&session(),
peer->id,
draft->c_draftMessage());
}
owner().histories().dialogEntryApplied(this);
}
@ -3361,7 +3364,9 @@ void HistoryBlock::refreshView(not_null<Element*> view) {
Expects(view->block() == this);
const auto item = view->data();
auto refreshed = item->createView(HistoryInner::ElementDelegate());
auto refreshed = item->createView(
HistoryInner::ElementDelegate(),
view);
auto blockIndex = indexInHistory();
auto itemIndex = view->indexInBlock();

View File

@ -1427,7 +1427,7 @@ void HistoryInner::mouseActionFinish(
_widget->noSelectingScroll();
_widget->updateTopBarSelection();
#if defined Q_OS_LINUX32 || defined Q_OS_LINUX64
#if defined Q_OS_UNIX && !defined Q_OS_MAC
if (!_selected.empty() && _selected.cbegin()->second != FullSelection) {
const auto [item, selection] = *_selected.cbegin();
if (const auto view = item->mainView()) {
@ -1436,7 +1436,7 @@ void HistoryInner::mouseActionFinish(
QClipboard::Selection);
}
}
#endif // Q_OS_LINUX32 || Q_OS_LINUX64
#endif // Q_OS_UNIX && !Q_OS_MAC
}
void HistoryInner::mouseReleaseEvent(QMouseEvent *e) {
@ -2373,7 +2373,7 @@ HistoryInner::~HistoryInner() {
for (const auto &item : _animatedStickersPlayed) {
if (const auto view = item->mainView()) {
if (const auto media = view->media()) {
media->clearStickerLoopPlayed();
media->stickerClearLoopPlayed();
}
}
}
@ -3323,12 +3323,20 @@ not_null<HistoryView::ElementDelegate*> HistoryInner::ElementDelegate() {
return HistoryView::Context::History;
}
std::unique_ptr<HistoryView::Element> elementCreate(
not_null<HistoryMessage*> message) override {
return std::make_unique<HistoryView::Message>(this, message);
not_null<HistoryMessage*> message,
Element *replacing = nullptr) override {
return std::make_unique<HistoryView::Message>(
this,
message,
replacing);
}
std::unique_ptr<HistoryView::Element> elementCreate(
not_null<HistoryService*> message) override {
return std::make_unique<HistoryView::Service>(this, message);
not_null<HistoryService*> message,
Element *replacing = nullptr) override {
return std::make_unique<HistoryView::Service>(
this,
message,
replacing);
}
bool elementUnderCursor(
not_null<const HistoryView::Element*> view) override {

View File

@ -326,7 +326,8 @@ public:
[[nodiscard]] PeerData *displayFrom() const;
[[nodiscard]] virtual std::unique_ptr<HistoryView::Element> createView(
not_null<HistoryView::ElementDelegate*> delegate) = 0;
not_null<HistoryView::ElementDelegate*> delegate,
HistoryView::Element *replacing = nullptr) = 0;
void updateDate(TimeId newDate);
[[nodiscard]] bool canUpdateDate() const;

View File

@ -458,7 +458,9 @@ HistoryMessage::HistoryMessage(
}
const auto textWithEntities = TextWithEntities{
TextUtilities::Clean(qs(data.vmessage())),
Api::EntitiesFromMTP(data.ventities().value_or_empty())
Api::EntitiesFromMTP(
&history->session(),
data.ventities().value_or_empty())
};
setText(_media ? textWithEntities : EnsureNonEmpty(textWithEntities));
if (const auto groupedId = data.vgrouped_id()) {
@ -1072,7 +1074,9 @@ void HistoryMessage::applyEdition(const MTPDmessage &message) {
const auto textWithEntities = TextWithEntities{
qs(message.vmessage()),
Api::EntitiesFromMTP(message.ventities().value_or_empty())
Api::EntitiesFromMTP(
&history()->session(),
message.ventities().value_or_empty())
};
setReplyMarkup(message.vreply_markup());
if (!isLocalUpdateMedia()) {
@ -1383,8 +1387,9 @@ QString HistoryMessage::notificationHeader() const {
}
std::unique_ptr<HistoryView::Element> HistoryMessage::createView(
not_null<HistoryView::ElementDelegate*> delegate) {
return delegate->elementCreate(this);
not_null<HistoryView::ElementDelegate*> delegate,
HistoryView::Element *replacing) {
return delegate->elementCreate(this, replacing);
}
HistoryMessage::~HistoryMessage() {

View File

@ -168,7 +168,8 @@ public:
}
[[nodiscard]] std::unique_ptr<HistoryView::Element> createView(
not_null<HistoryView::ElementDelegate*> delegate) override;
not_null<HistoryView::ElementDelegate*> delegate,
HistoryView::Element *replacing = nullptr) override;
~HistoryMessage();

View File

@ -570,8 +570,9 @@ QString HistoryService::inReplyText() const {
}
std::unique_ptr<HistoryView::Element> HistoryService::createView(
not_null<HistoryView::ElementDelegate*> delegate) {
return delegate->elementCreate(this);
not_null<HistoryView::ElementDelegate*> delegate,
HistoryView::Element *replacing) {
return delegate->elementCreate(this, replacing);
}
QString HistoryService::fromLinkText() const {

View File

@ -105,7 +105,8 @@ public:
QString inReplyText() const override;
std::unique_ptr<HistoryView::Element> createView(
not_null<HistoryView::ElementDelegate*> delegate) override;
not_null<HistoryView::ElementDelegate*> delegate,
HistoryView::Element *replacing = nullptr) override;
~HistoryService();

View File

@ -65,6 +65,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "chat_helpers/tabbed_section.h"
#include "chat_helpers/bot_keyboard.h"
#include "chat_helpers/message_field.h"
#include "platform/platform_specific.h"
#include "lang/lang_keys.h"
#include "mainwidget.h"
#include "mainwindow.h"
@ -2102,6 +2103,7 @@ void HistoryWidget::refreshScheduledToggle() {
controller()->showSection(
HistoryView::ScheduledMemento(_history));
});
orderWidgets(); // Raise drag areas to the top.
}
}
}
@ -3068,8 +3070,9 @@ void HistoryWidget::saveEditMsg() {
if (webPageId == CancelledWebPageId) {
sendFlags |= MTPmessages_EditMessage::Flag::f_no_webpage;
}
auto localEntities = Api::EntitiesToMTP(sending.entities);
auto localEntities = Api::EntitiesToMTP(&session(), sending.entities);
auto sentEntities = Api::EntitiesToMTP(
&session(),
sending.entities,
Api::ConvertOption::SkipLocal);
if (!sentEntities.v.isEmpty()) {
@ -4605,7 +4608,10 @@ bool HistoryWidget::confirmSendingFiles(
}
if (hasImage) {
auto image = qvariant_cast<QImage>(data->imageData());
auto image = Platform::GetImageFromClipboard();
if (image.isNull()) {
image = qvariant_cast<QImage>(data->imageData());
}
if (!image.isNull()) {
confirmSendingFiles(
std::move(image),
@ -4755,7 +4761,7 @@ void HistoryWidget::sendFileConfirmed(
session().user()).flags;
TextUtilities::PrepareForSending(caption, prepareFlags);
TextUtilities::Trim(caption);
auto localEntities = Api::EntitiesToMTP(caption.entities);
auto localEntities = Api::EntitiesToMTP(&session(), caption.entities);
if (itemToEdit) {
if (const auto id = itemToEdit->groupId()) {

View File

@ -430,12 +430,17 @@ bool AddRescheduleMessageAction(
? SendMenuType::ScheduledToUser
: SendMenuType::Scheduled;
using S = Data::ScheduledMessages;
const auto date = (item->date() == S::kScheduledUntilOnlineTimestamp)
? HistoryView::DefaultScheduleTime()
: item->date() + 600;
Ui::show(
HistoryView::PrepareScheduleBox(
&request.navigation->session(),
sendMenuType,
callback,
item->date() + 600),
date),
Ui::LayerOption::KeepOther);
});
return true;

View File

@ -56,13 +56,15 @@ bool IsAttachedToPreviousInSavedMessages(
std::unique_ptr<HistoryView::Element> SimpleElementDelegate::elementCreate(
not_null<HistoryMessage*> message) {
return std::make_unique<HistoryView::Message>(this, message);
not_null<HistoryMessage*> message,
Element *replacing) {
return std::make_unique<HistoryView::Message>(this, message, replacing);
}
std::unique_ptr<HistoryView::Element> SimpleElementDelegate::elementCreate(
not_null<HistoryService*> message) {
return std::make_unique<HistoryView::Service>(this, message);
not_null<HistoryService*> message,
Element *replacing) {
return std::make_unique<HistoryView::Service>(this, message, replacing);
}
bool SimpleElementDelegate::elementUnderCursor(
@ -203,14 +205,15 @@ void DateBadge::paint(Painter &p, int y, int w) const {
Element::Element(
not_null<ElementDelegate*> delegate,
not_null<HistoryItem*> data)
not_null<HistoryItem*> data,
Element *replacing)
: _delegate(delegate)
, _data(data)
, _isScheduledUntilOnline(IsItemScheduledUntilOnline(data))
, _dateTime(_isScheduledUntilOnline ? QDateTime() : ItemDateTime(data))
, _context(delegate->elementContext()) {
history()->owner().registerItemView(this);
refreshMedia();
refreshMedia(replacing);
if (_context == Context::History) {
history()->setHasPendingResizedItems();
}
@ -342,7 +345,7 @@ bool Element::isHidden() const {
return isHiddenByGroup();
}
void Element::refreshMedia() {
void Element::refreshMedia(Element *replacing) {
_flags &= ~Flag::HiddenByGroup;
const auto item = data();
@ -365,7 +368,7 @@ void Element::refreshMedia() {
}
const auto session = &history()->session();
if (const auto media = _data->media()) {
_media = media->createView(this);
_media = media->createView(this, replacing);
} else if (_data->isIsolatedEmoji()
&& session->settings().largeEmoji()) {
const auto emoji = _data->isolatedEmoji();
@ -376,6 +379,7 @@ void Element::refreshMedia() {
std::make_unique<Sticker>(
this,
sticker.document,
replacing,
sticker.replacements));
} else {
_media = std::make_unique<UnwrappedMedia>(

View File

@ -37,9 +37,11 @@ class ElementDelegate {
public:
virtual Context elementContext() = 0;
virtual std::unique_ptr<Element> elementCreate(
not_null<HistoryMessage*> message) = 0;
not_null<HistoryMessage*> message,
Element *replacing = nullptr) = 0;
virtual std::unique_ptr<Element> elementCreate(
not_null<HistoryService*> message) = 0;
not_null<HistoryService*> message,
Element *replacing = nullptr) = 0;
virtual bool elementUnderCursor(not_null<const Element*> view) = 0;
virtual void elementAnimationAutoplayAsync(
not_null<const Element*> element) = 0;
@ -63,9 +65,11 @@ public:
class SimpleElementDelegate : public ElementDelegate {
public:
std::unique_ptr<Element> elementCreate(
not_null<HistoryMessage*> message) override;
not_null<HistoryMessage*> message,
Element *replacing = nullptr) override;
std::unique_ptr<Element> elementCreate(
not_null<HistoryService*> message) override;
not_null<HistoryService*> message,
Element *replacing = nullptr) override;
bool elementUnderCursor(not_null<const Element*> view) override;
void elementAnimationAutoplayAsync(
not_null<const Element*> element) override;
@ -134,7 +138,8 @@ class Element
public:
Element(
not_null<ElementDelegate*> delegate,
not_null<HistoryItem*> data);
not_null<HistoryItem*> data,
Element *replacing);
enum class Flag : uchar {
NeedsResize = 0x01,
@ -305,7 +310,7 @@ private:
virtual QSize performCountOptimalSize() = 0;
virtual QSize performCountCurrentSize(int newWidth) = 0;
void refreshMedia();
void refreshMedia(Element *replacing);
const not_null<ElementDelegate*> _delegate;
const not_null<HistoryItem*> _data;

View File

@ -1107,13 +1107,15 @@ Context ListWidget::elementContext() {
}
std::unique_ptr<Element> ListWidget::elementCreate(
not_null<HistoryMessage*> message) {
return std::make_unique<Message>(this, message);
not_null<HistoryMessage*> message,
Element *replacing) {
return std::make_unique<Message>(this, message, replacing);
}
std::unique_ptr<Element> ListWidget::elementCreate(
not_null<HistoryService*> message) {
return std::make_unique<Service>(this, message);
not_null<HistoryService*> message,
Element *replacing) {
return std::make_unique<Service>(this, message, replacing);
}
bool ListWidget::elementUnderCursor(
@ -2083,7 +2085,7 @@ void ListWidget::mouseActionFinish(
_mouseSelectType = TextSelectType::Letters;
//_widget->noSelectingScroll(); // #TODO select scroll
#if defined Q_OS_LINUX32 || defined Q_OS_LINUX64
#if defined Q_OS_UNIX && !defined Q_OS_MAC
if (_selectedTextItem
&& _selectedTextRange.from != _selectedTextRange.to) {
if (const auto view = viewForItem(_selectedTextItem)) {
@ -2092,7 +2094,7 @@ void ListWidget::mouseActionFinish(
QClipboard::Selection);
}
}
#endif // Q_OS_LINUX32 || Q_OS_LINUX64
#endif // Q_OS_UNIX && !Q_OS_MAC
}
void ListWidget::mouseActionUpdate() {

View File

@ -184,9 +184,11 @@ public:
// ElementDelegate interface.
Context elementContext() override;
std::unique_ptr<Element> elementCreate(
not_null<HistoryMessage*> message) override;
not_null<HistoryMessage*> message,
Element *replacing = nullptr) override;
std::unique_ptr<Element> elementCreate(
not_null<HistoryService*> message) override;
not_null<HistoryService*> message,
Element *replacing = nullptr) override;
bool elementUnderCursor(not_null<const Element*> view) override;
void elementAnimationAutoplayAsync(
not_null<const Element*> view) override;

View File

@ -217,8 +217,9 @@ LogEntryOriginal::~LogEntryOriginal() = default;
Message::Message(
not_null<ElementDelegate*> delegate,
not_null<HistoryMessage*> data)
: Element(delegate, data) {
not_null<HistoryMessage*> data,
Element *replacing)
: Element(delegate, data, replacing) {
initLogEntryOriginal();
initPsa();
}

View File

@ -41,7 +41,8 @@ class Message : public Element, public base::has_weak_ptr {
public:
Message(
not_null<ElementDelegate*> delegate,
not_null<HistoryMessage*> data);
not_null<HistoryMessage*> data,
Element *replacing);
int marginTop() const override;
int marginBottom() const override;

View File

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h"
#include "data/data_scheduled_messages.h" // kScheduledUntilOnlineTimestamp
#include "lang/lang_keys.h"
#include "base/event_filter.h"
#include "base/unixtime.h"
#include "boxes/calendar_box.h"
#include "ui/widgets/input_fields.h"
@ -65,17 +66,30 @@ QString TimeString(TimeId time) {
).arg(parsed.minute(), 2, 10, QLatin1Char('0'));
}
int ProcessWheelEvent(not_null<QWheelEvent*> e) {
// Only a mouse wheel is accepted.
constexpr auto step = static_cast<int>(QWheelEvent::DefaultDeltasPerStep);
const auto delta = e->angleDelta().y();
const auto absDelta = std::abs(delta);
if (absDelta != step) {
return 0;
}
return (delta / absDelta);
}
class TimePart final : public Ui::MaskedInputField {
public:
using MaskedInputField::MaskedInputField;
void setMaxValue(int value);
void setWheelStep(int value);
rpl::producer<> erasePrevious() const;
rpl::producer<QChar> putNext() const;
protected:
void keyPressEvent(QKeyEvent *e) override;
void wheelEvent(QWheelEvent *e) override;
void correctValue(
const QString &was,
@ -86,11 +100,21 @@ protected:
private:
int _maxValue = 0;
int _maxDigits = 0;
int _wheelStep = 0;
rpl::event_stream<> _erasePrevious;
rpl::event_stream<QChar> _putNext;
};
int Number(not_null<TimePart*> field) {
const auto text = field->getLastText();
auto ref = text.midRef(0);
while (!ref.isEmpty() && ref.at(0) == '0') {
ref = ref.mid(1);
}
return ref.toInt();
}
class TimeInput final : public Ui::RpWidget {
public:
TimeInput(QWidget *parent, const QString &value);
@ -121,7 +145,6 @@ private:
int hour() const;
int minute() const;
int number(const object_ptr<TimePart> &field) const;
object_ptr<TimePart> _hour;
object_ptr<Ui::PaddingWrap<Ui::FlatLabel>> _separator1;
@ -181,6 +204,10 @@ void TimePart::setMaxValue(int value) {
}
}
void TimePart::setWheelStep(int value) {
_wheelStep = value;
}
rpl::producer<> TimePart::erasePrevious() const {
return _erasePrevious.events();
}
@ -199,6 +226,18 @@ void TimePart::keyPressEvent(QKeyEvent *e) {
}
}
void TimePart::wheelEvent(QWheelEvent *e) {
const auto direction = ProcessWheelEvent(e);
auto time = Number(this) + (direction * _wheelStep);
const auto max = _maxValue + 1;
if (time < 0) {
time += max;
} else if (time >= max) {
time -= max;
}
setText(QString::number(time));
}
void TimePart::correctValue(
const QString &was,
int wasCursor,
@ -290,10 +329,12 @@ TimeInput::TimeInput(QWidget *parent, const QString &value)
connect(_hour, &Ui::MaskedInputField::changed, changed);
connect(_minute, &Ui::MaskedInputField::changed, changed);
_hour->setMaxValue(23);
_hour->setWheelStep(1);
_hour->putNext() | rpl::start_with_next([=](QChar ch) {
putNext(_minute, ch);
}, lifetime());
_minute->setMaxValue(59);
_minute->setWheelStep(10);
_minute->erasePrevious() | rpl::start_with_next([=] {
erasePrevious(_hour);
}, lifetime());
@ -356,21 +397,12 @@ bool TimeInput::setFocusFast() {
return true;
}
int TimeInput::number(const object_ptr<TimePart> &field) const {
const auto text = field->getLastText();
auto ref = text.midRef(0);
while (!ref.isEmpty() && ref.at(0) == '0') {
ref = ref.mid(1);
}
return ref.toInt();
}
int TimeInput::hour() const {
return number(_hour);
return Number(_hour);
}
int TimeInput::minute() const {
return number(_minute);
return Number(_minute);
}
QString TimeInput::valueCurrent() const {
@ -601,6 +633,24 @@ void ScheduleBox(
timeInput->setFocusFast();
}, dayInput->lifetime());
const auto minDate = QDate::currentDate();
const auto maxDate = minDate.addYears(1).addDays(-1);
const auto &dayViewport = dayInput->rawTextEdit()->viewport();
base::install_event_filter(dayViewport, [=](not_null<QEvent*> event) {
if (event->type() == QEvent::Wheel) {
const auto e = static_cast<QWheelEvent*>(event.get());
const auto direction = ProcessWheelEvent(e);
if (!direction) {
return base::EventFilterResult::Continue;
}
const auto d = date->current().addDays(direction);
*date = std::clamp(d, minDate, maxDate);
return base::EventFilterResult::Cancel;
}
return base::EventFilterResult::Continue;
});
content->widthValue(
) | rpl::start_with_next([=](int width) {
const auto paddings = width
@ -622,16 +672,19 @@ void ScheduleBox(
width);
}, content->lifetime());
const auto calendar =
content->lifetime().make_state<QPointer<CalendarBox>>();
QObject::connect(dayInput, &Ui::InputField::focused, [=] {
const auto calendar = std::make_shared<QPointer<CalendarBox>>();
if (*calendar) {
return;
}
const auto chosen = [=](QDate chosen) {
*date = chosen;
(*calendar)->closeBox();
};
const auto finalize = [=](not_null<CalendarBox*> box) {
const auto now = QDate::currentDate();
box->setMinDate(now);
box->setMaxDate(now.addYears(1).addDays(-1));
box->setMinDate(minDate);
box->setMaxDate(maxDate);
};
*calendar = box->getDelegate()->show(Box<CalendarBox>(
date->current(),

View File

@ -36,6 +36,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "storage/storage_media_prepare.h"
#include "storage/localstorage.h"
#include "inline_bots/inline_bot_result.h"
#include "platform/platform_specific.h"
#include "lang/lang_keys.h"
#include "facades.h"
#include "app.h"
@ -265,7 +266,10 @@ bool ScheduledWidget::confirmSendingFiles(
}
if (hasImage) {
auto image = qvariant_cast<QImage>(data->imageData());
auto image = Platform::GetImageFromClipboard();
if (image.isNull()) {
image = qvariant_cast<QImage>(data->imageData());
}
if (!image.isNull()) {
confirmSendingFiles(
std::move(image),

View File

@ -309,8 +309,9 @@ void serviceColorsUpdated() {
Service::Service(
not_null<ElementDelegate*> delegate,
not_null<HistoryService*> data)
: Element(delegate, data) {
not_null<HistoryService*> data,
Element *replacing)
: Element(delegate, data, replacing) {
}
not_null<HistoryService*> Service::message() const {

View File

@ -17,7 +17,8 @@ class Service : public Element {
public:
Service(
not_null<ElementDelegate*> delegate,
not_null<HistoryService*> data);
not_null<HistoryService*> data,
Element *replacing);
int marginTop() const override;
int marginBottom() const override;

View File

@ -26,8 +26,6 @@ public:
ClickHandlerPtr link() override;
void clearStickerLoopPlayed() override {
}
bool hasHeavyPart() const override {
return (_start ? _start->hasHeavyPart() : false)
|| (_end ? _end->hasHeavyPart() : false);

View File

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item.h"
#include "history/view/history_view_element.h"
#include "history/view/history_view_cursor_state.h"
#include "lottie/lottie_single_player.h"
#include "storage/storage_shared_media.h"
#include "data/data_document.h"
#include "ui/text_options.h"
@ -165,6 +166,10 @@ PointState Media::pointState(QPoint point) const {
: PointState::Outside;
}
std::unique_ptr<Lottie::SinglePlayer> Media::stickerTakeLottie() {
return nullptr;
}
TextState Media::getStateGrouped(
const QRect &geometry,
RectParts sides,

View File

@ -24,6 +24,10 @@ enum class SharedMediaType : signed char;
using SharedMediaTypesMask = base::enum_mask<SharedMediaType>;
} // namespace Storage
namespace Lottie {
class SinglePlayer;
} // namespace Lottie
namespace HistoryView {
enum class PointState : char;
@ -139,8 +143,9 @@ public:
}
virtual void stopAnimation() {
}
virtual void clearStickerLoopPlayed() {
virtual void stickerClearLoopPlayed() {
}
virtual std::unique_ptr<Lottie::SinglePlayer> stickerTakeLottie();
virtual void checkAnimation() {
}

View File

@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history.h"
#include "history/history_item.h"
#include "history/history_item_components.h"
#include "lottie/lottie_single_player.h"
#include "data/data_session.h"
#include "layout.h"
#include "facades.h"
@ -26,6 +27,11 @@ constexpr auto kMaxForwardedBarLines = 4;
} // namespace
auto UnwrappedMedia::Content::stickerTakeLottie()
-> std::unique_ptr<Lottie::SinglePlayer> {
return nullptr;
}
UnwrappedMedia::UnwrappedMedia(
not_null<Element*> parent,
std::unique_ptr<Content> content)
@ -387,6 +393,10 @@ TextState UnwrappedMedia::textState(QPoint point, StateRequest request) const {
return result;
}
std::unique_ptr<Lottie::SinglePlayer> UnwrappedMedia::stickerTakeLottie() {
return _content->stickerTakeLottie();
}
int UnwrappedMedia::calculateFullRight(const QRect &inner) const {
const auto rightAligned = _parent->hasOutLayout() && !Adaptive::ChatWide();
const auto infoWidth = _parent->infoWidth()

View File

@ -32,8 +32,9 @@ public:
[[nodiscard]] virtual DocumentData *document() {
return nullptr;
}
virtual void clearStickerLoopPlayed() {
virtual void stickerClearLoopPlayed() {
}
virtual std::unique_ptr<Lottie::SinglePlayer> stickerTakeLottie();
virtual bool hasHeavyPart() const {
return false;
}
@ -81,9 +82,10 @@ public:
bool hidesForwardedInfo() const override {
return _content->hidesForwardedInfo();
}
void clearStickerLoopPlayed() override {
_content->clearStickerLoopPlayed();
void stickerClearLoopPlayed() override {
_content->stickerClearLoopPlayed();
}
std::unique_ptr<Lottie::SinglePlayer> stickerTakeLottie() override;
bool hasHeavyPart() const override {
return _content->hasHeavyPart();

View File

@ -57,11 +57,22 @@ namespace {
Sticker::Sticker(
not_null<Element*> parent,
not_null<DocumentData*> data,
Element *replacing,
const Lottie::ColorReplacements *replacements)
: _parent(parent)
, _data(data)
, _replacements(replacements) {
_data->loadThumbnail(parent->data()->fullId());
if ((_dataMedia = _data->activeMediaView())) {
dataMediaCreated();
} else {
_data->loadThumbnail(parent->data()->fullId());
}
if (const auto media = replacing ? replacing->media() : nullptr) {
_lottie = media->stickerTakeLottie();
if (_lottie) {
lottieCreated();
}
}
}
Sticker::~Sticker() {
@ -266,6 +277,12 @@ void Sticker::ensureDataMediaCreated() const {
return;
}
_dataMedia = _data->createMediaView();
dataMediaCreated();
}
void Sticker::dataMediaCreated() const {
Expects(_dataMedia != nullptr);
_dataMedia->goodThumbnailWanted();
_dataMedia->thumbnailWanted(_parent->data()->fullId());
_parent->history()->owner().registerHeavyViewPart(_parent);
@ -285,6 +302,12 @@ void Sticker::setupLottie() {
Stickers::LottieSize::MessageHistory,
_size * cIntRetinaFactor(),
Lottie::Quality::High);
lottieCreated();
}
void Sticker::lottieCreated() {
Expects(_lottie != nullptr);
_parent->history()->owner().registerHeavyViewPart(_parent);
_lottie->updates(
@ -318,4 +341,8 @@ void Sticker::unloadLottie() {
_parent->checkHeavyPart();
}
std::unique_ptr< Lottie::SinglePlayer> Sticker::stickerTakeLottie() {
return std::move(_lottie);
}
} // namespace HistoryView

View File

@ -33,6 +33,7 @@ public:
Sticker(
not_null<Element*> parent,
not_null<DocumentData*> data,
Element *replacing = nullptr,
const Lottie::ColorReplacements *replacements = nullptr);
~Sticker();
@ -46,9 +47,10 @@ public:
DocumentData *document() override {
return _data;
}
void clearStickerLoopPlayed() override {
void stickerClearLoopPlayed() override {
_lottieOncePlayed = false;
}
std::unique_ptr<Lottie::SinglePlayer> stickerTakeLottie() override;
bool hasHeavyPart() const override;
void unloadHeavyPart() override;
@ -74,8 +76,10 @@ private:
[[nodiscard]] QPixmap paintedPixmap(bool selected) const;
void ensureDataMediaCreated() const;
void dataMediaCreated() const;
void setupLottie();
void lottieCreated();
void unloadLottie();
const not_null<Element*> _parent;

View File

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "layout.h"
#include "core/click_handler_types.h"
#include "core/ui_integration.h"
#include "lang/lang_keys.h"
#include "history/history_item_components.h"
#include "history/history_item.h"
@ -199,10 +200,17 @@ QSize WebPage::countOptimalSize() {
- st::msgPadding.right()
- st::webPageLeft);
}
auto context = Core::UiIntegration::Context();
if (_data->siteName == qstr("Twitter")) {
context.type = Core::UiIntegration::HashtagMentionType::Twitter;
} else if (_data->siteName == qstr("Instagram")) {
context.type = Core::UiIntegration::HashtagMentionType::Instagram;
}
_description.setMarkedText(
st::webPageDescriptionStyle,
text,
Ui::WebpageTextDescriptionOptions(_data->siteName));
Ui::WebpageTextDescriptionOptions(),
context);
}
if (!displayedSiteName().isEmpty()) {
_siteNameLines = 1;

View File

@ -2107,11 +2107,11 @@ void ListWidget::mouseActionFinish(
//_widget->noSelectingScroll(); // #TODO scroll by drag
//_widget->updateTopBarSelection();
#if defined Q_OS_LINUX32 || defined Q_OS_LINUX64
#if defined Q_OS_UNIX && !defined Q_OS_MAC
//if (hasSelectedText()) { // #TODO linux clipboard
// TextUtilities::SetClipboardText(_selected.cbegin()->first->selectedText(_selected.cbegin()->second), QClipboard::Selection);
//}
#endif // Q_OS_LINUX32 || Q_OS_LINUX64
#endif // Q_OS_UNIX && !Q_OS_MAC
}
void ListWidget::applyDragSelection() {

View File

@ -550,7 +550,7 @@ void Sticker::prepareThumbnail() const {
}
_dataMedia->checkStickerSmall();
if (const auto sticker = _dataMedia->getStickerSmall()) {
if (!_lottie && !_thumbLoaded && _dataMedia->loaded()) {
if (!_lottie && !_thumbLoaded) {
const auto thumbSize = getThumbSize();
_thumb = sticker->pix(
thumbSize.width(),
@ -679,8 +679,6 @@ Video::Video(not_null<Context*> context, not_null<Result*> result)
, _link(getResultPreviewHandler())
, _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip)
, _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) {
Assert(getResultDocument() != nullptr);
if (int duration = content_duration()) {
_duration = formatDurationText(duration);
_durationWidth = st::normalFont->width(_duration);
@ -688,10 +686,12 @@ Video::Video(not_null<Context*> context, not_null<Result*> result)
}
bool Video::withThumbnail() const {
const auto document = getShownDocument();
Assert(document != nullptr);
return document->hasThumbnail();
if (const auto document = getShownDocument()) {
if (document->hasThumbnail()) {
return true;
}
}
return hasResultThumb();
}
void Video::initDimensions() {
@ -761,6 +761,7 @@ void Video::paint(Painter &p, const QRect &clip, const PaintContext *context) co
void Video::unloadHeavyPart() {
_documentMedia = nullptr;
ItemBase::unloadHeavyPart();
}
TextState Video::getState(
@ -776,17 +777,20 @@ TextState Video::getState(
}
void Video::prepareThumbnail(QSize size) const {
const auto document = getShownDocument();
if (document->hasThumbnail()) {
if (!_documentMedia) {
_documentMedia = document->createMediaView();
_documentMedia->thumbnailWanted(fileOrigin());
}
if (!_documentMedia->thumbnail()) {
return;
if (const auto document = getShownDocument()) {
if (document->hasThumbnail()) {
if (!_documentMedia) {
_documentMedia = document->createMediaView();
_documentMedia->thumbnailWanted(fileOrigin());
}
if (!_documentMedia->thumbnail()) {
return;
}
}
}
const auto thumb = _documentMedia->thumbnail();
const auto thumb = _documentMedia
? _documentMedia->thumbnail()
: getResultThumb(fileOrigin());
if (!thumb) {
return;
}

View File

@ -162,7 +162,6 @@ std::unique_ptr<Result> Result::Create(
}
} else if (result->_type == Type::Audio
|| result->_type == Type::File
|| result->_type == Type::Video
|| result->_type == Type::Sticker
|| result->_type == Type::Gif) {
if (!result->_document) {
@ -175,24 +174,28 @@ std::unique_ptr<Result> Result::Create(
const auto &r = message->c_botInlineMessageMediaAuto();
const auto message = qs(r.vmessage());
const auto entities = Api::EntitiesFromMTP(
session,
r.ventities().value_or_empty());
if (result->_type == Type::Photo) {
if (!result->_photo) {
return nullptr;
}
result->sendData = std::make_unique<internal::SendPhoto>(
session,
result->_photo,
message,
entities);
} else if (result->_type == Type::Game) {
result->createGame();
result->sendData = std::make_unique<internal::SendGame>(
session,
result->_game);
} else {
if (!result->_document) {
return nullptr;
}
result->sendData = std::make_unique<internal::SendFile>(
session,
result->_document,
message,
entities);
@ -205,22 +208,10 @@ std::unique_ptr<Result> Result::Create(
case mtpc_botInlineMessageText: {
const auto &r = message->c_botInlineMessageText();
result->sendData = std::make_unique<internal::SendText>(
session,
qs(r.vmessage()),
Api::EntitiesFromMTP(r.ventities().value_or_empty()),
Api::EntitiesFromMTP(session, r.ventities().value_or_empty()),
r.is_no_webpage());
if (result->_type == Type::Photo) {
if (!result->_photo) {
return nullptr;
}
} else if (result->_type == Type::Audio
|| result->_type == Type::File
|| result->_type == Type::Video
|| result->_type == Type::Sticker
|| result->_type == Type::Gif) {
if (!result->_document) {
return nullptr;
}
}
if (const auto markup = r.vreply_markup()) {
result->_mtpKeyboard = std::make_unique<MTPReplyMarkup>(*markup);
}
@ -230,7 +221,9 @@ std::unique_ptr<Result> Result::Create(
// #TODO layer 72 save period and send live location?..
auto &r = message->c_botInlineMessageMediaGeo();
if (r.vgeo().type() == mtpc_geoPoint) {
result->sendData = std::make_unique<internal::SendGeo>(r.vgeo().c_geoPoint());
result->sendData = std::make_unique<internal::SendGeo>(
session,
r.vgeo().c_geoPoint());
} else {
badAttachment = true;
}
@ -242,7 +235,13 @@ std::unique_ptr<Result> Result::Create(
case mtpc_botInlineMessageMediaVenue: {
auto &r = message->c_botInlineMessageMediaVenue();
if (r.vgeo().type() == mtpc_geoPoint) {
result->sendData = std::make_unique<internal::SendVenue>(r.vgeo().c_geoPoint(), qs(r.vvenue_id()), qs(r.vprovider()), qs(r.vtitle()), qs(r.vaddress()));
result->sendData = std::make_unique<internal::SendVenue>(
session,
r.vgeo().c_geoPoint(),
qs(r.vvenue_id()),
qs(r.vprovider()),
qs(r.vtitle()),
qs(r.vaddress()));
} else {
badAttachment = true;
}
@ -253,7 +252,11 @@ std::unique_ptr<Result> Result::Create(
case mtpc_botInlineMessageMediaContact: {
auto &r = message->c_botInlineMessageMediaContact();
result->sendData = std::make_unique<internal::SendContact>(qs(r.vfirst_name()), qs(r.vlast_name()), qs(r.vphone_number()));
result->sendData = std::make_unique<internal::SendContact>(
session,
qs(r.vfirst_name()),
qs(r.vlast_name()),
qs(r.vphone_number()));
if (const auto markup = r.vreply_markup()) {
result->_mtpKeyboard = std::make_unique<MTPReplyMarkup>(*markup);
}

View File

@ -79,7 +79,7 @@ QString SendDataCommon::getErrorOnSend(
SendDataCommon::SentMTPMessageFields SendText::getSentMessageFields() const {
SentMTPMessageFields result;
result.text = MTP_string(_message);
result.entities = Api::EntitiesToMTP(_entities);
result.entities = Api::EntitiesToMTP(&session(), _entities);
return result;
}

View File

@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_location_manager.h"
namespace Main {
class Session;
} // namespace Main
class History;
namespace InlineBots {
@ -22,11 +26,16 @@ namespace internal {
// For each type of message that can be sent there will be a subclass.
class SendData {
public:
SendData() = default;
explicit SendData(not_null<Main::Session*> session) : _session(session) {
}
SendData(const SendData &other) = delete;
SendData &operator=(const SendData &other) = delete;
virtual ~SendData() = default;
[[nodiscard]] Main::Session &session() const {
return *_session;
}
virtual bool isValid() const = 0;
virtual void addToHistory(
@ -54,6 +63,9 @@ public:
virtual QString getLayoutTitle(const Result *owner) const;
virtual QString getLayoutDescription(const Result *owner) const;
private:
not_null<Main::Session*> _session;
};
// This class implements addHistory() for most of the types hiding
@ -61,6 +73,8 @@ public:
// Only SendFile and SendPhoto work by their own.
class SendDataCommon : public SendData {
public:
using SendData::SendData;
struct SentMTPMessageFields {
MTPString text = MTP_string();
MTPVector<MTPMessageEntity> entities = MTP_vector<MTPMessageEntity>();
@ -91,10 +105,12 @@ public:
class SendText : public SendDataCommon {
public:
SendText(
not_null<Main::Session*> session,
const QString &message,
const EntitiesInText &entities,
bool/* noWebPage*/)
: _message(message)
: SendDataCommon(session)
, _message(message)
, _entities(entities) {
}
@ -113,7 +129,11 @@ private:
// Message with geo location point media.
class SendGeo : public SendDataCommon {
public:
explicit SendGeo(const MTPDgeoPoint &point) : _location(point) {
SendGeo(
not_null<Main::Session*> session,
const MTPDgeoPoint &point)
: SendDataCommon(session)
, _location(point) {
}
bool isValid() const override {
@ -137,13 +157,19 @@ private:
// Message with venue media.
class SendVenue : public SendDataCommon {
public:
SendVenue(const MTPDgeoPoint &point, const QString &venueId,
const QString &provider, const QString &title, const QString &address)
: _location(point)
, _venueId(venueId)
, _provider(provider)
, _title(title)
, _address(address) {
SendVenue(
not_null<Main::Session*> session,
const MTPDgeoPoint &point,
const QString &venueId,
const QString &provider,
const QString &title,
const QString &address)
: SendDataCommon(session)
, _location(point)
, _venueId(venueId)
, _provider(provider)
, _title(title)
, _address(address) {
}
bool isValid() const override {
@ -168,10 +194,15 @@ private:
// Message with shared contact media.
class SendContact : public SendDataCommon {
public:
SendContact(const QString &firstName, const QString &lastName, const QString &phoneNumber)
: _firstName(firstName)
, _lastName(lastName)
, _phoneNumber(phoneNumber) {
SendContact(
not_null<Main::Session*> session,
const QString &firstName,
const QString &lastName,
const QString &phoneNumber)
: SendDataCommon(session)
, _firstName(firstName)
, _lastName(lastName)
, _phoneNumber(phoneNumber) {
}
bool isValid() const override {
@ -191,10 +222,12 @@ private:
class SendPhoto : public SendData {
public:
SendPhoto(
not_null<Main::Session*> session,
PhotoData *photo,
const QString &message,
const EntitiesInText &entities)
: _photo(photo)
: SendData(session)
, _photo(photo)
, _message(message)
, _entities(entities) {
}
@ -231,10 +264,12 @@ private:
class SendFile : public SendData {
public:
SendFile(
not_null<Main::Session*> session,
DocumentData *document,
const QString &message,
const EntitiesInText &entities)
: _document(document)
: SendData(session)
, _document(document)
, _message(message)
, _entities(entities) {
}
@ -270,8 +305,9 @@ private:
// Message with game.
class SendGame : public SendData {
public:
SendGame(GameData *game)
: _game(game) {
SendGame(not_null<Main::Session*> session, GameData *game)
: SendData(session)
, _game(game) {
}
bool isValid() const override {

View File

@ -248,7 +248,9 @@ void CodeWidget::codeSubmitDone(const MTPauth_Authorization &result) {
}, [&](const MTPDauth_authorizationSignUpRequired &data) {
if (const auto terms = data.vterms_of_service()) {
terms->match([&](const MTPDhelp_termsOfService &data) {
getData()->termsLock = Window::TermsLock::FromMTP(data);
getData()->termsLock = Window::TermsLock::FromMTP(
nullptr,
data);
});
} else {
getData()->termsLock = Window::TermsLock();

View File

@ -146,7 +146,7 @@ void Widget::handleUpdate(const MTPUpdate &update) {
}, [&](const MTPDupdateServiceNotification &data) {
const auto text = TextWithEntities{
qs(data.vmessage()),
Api::EntitiesFromMTP(data.ventities().v)
Api::EntitiesFromMTP(nullptr, data.ventities().v)
};
Ui::show(Box<InformBox>(text));
}, [](const auto &) {});

View File

@ -343,7 +343,7 @@ void start(not_null<Core::Launcher*> launcher) {
workingDirChosen = true;
} else {
#if defined Q_OS_MAC || defined Q_OS_LINUX
#ifdef Q_OS_UNIX
if (!cWorkingDir().isEmpty()) {
// This value must come from TelegramForcePortable
@ -358,16 +358,16 @@ void start(not_null<Core::Launcher*> launcher) {
}
workingDirChosen = true;
#if defined Q_OS_LINUX && !defined _DEBUG // fix first version
#if !defined Q_OS_MAC && !defined _DEBUG // fix first version
moveOldDataFrom = initialWorkingDir;
#endif // Q_OS_LINUX && !_DEBUG
#endif // !Q_OS_MAC && !_DEBUG
#elif defined Q_OS_WINRT // Q_OS_MAC || Q_OS_LINUX
#elif defined Q_OS_WINRT // Q_OS_UNIX
cForceWorkingDir(psAppDataPath());
workingDirChosen = true;
#elif defined OS_WIN_STORE // Q_OS_MAC || Q_OS_LINUX || Q_OS_WINRT
#elif defined OS_WIN_STORE // Q_OS_UNIX || Q_OS_WINRT
#ifdef _DEBUG
cForceWorkingDir(cExeDir());
@ -385,7 +385,7 @@ void start(not_null<Core::Launcher*> launcher) {
workingDirChosen = true;
}
#endif // Q_OS_MAC || Q_OS_LINUX || Q_OS_WINRT || OS_WIN_STORE
#endif // Q_OS_UNIX || Q_OS_WINRT || OS_WIN_STORE
}
@ -561,7 +561,7 @@ void writeDebug(const char *file, int32 line, const QString &v) {
//OutputDebugString(reinterpret_cast<const wchar_t *>(msg.utf16()));
#elif defined Q_OS_MAC
//objc_outputDebugString(msg);
#elif defined Q_OS_LINUX && defined _DEBUG
#elif defined Q_OS_UNIX && defined _DEBUG
//std::cout << msg.toUtf8().constData();
#endif
}

View File

@ -400,6 +400,15 @@ MainWidget::MainWidget(
floatPlayerClosed(itemId);
}, lifetime());
// Load current userpic and keep it loaded.
Notify::PeerUpdateValue(
session().user(),
Notify::PeerUpdate::Flag::PhotoChanged
) | rpl::start_with_next([=] {
[[maybe_unused]] const auto image = session().user()->currentUserpic(
_selfUserpicView);
}, lifetime());
_ptsWaiter.setRequesting(true);
updateScrollColors();
setupConnectingWidget();
@ -3821,7 +3830,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
}
item->updateSentContent({
sent.text,
Api::EntitiesFromMTP(list.value_or_empty())
Api::EntitiesFromMTP(&session(), list.value_or_empty())
}, d.vmedia());
item->contributeToSlowmode(d.vdate().v);
if (!wasAlready) {
@ -4330,7 +4339,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
const auto &d = update.c_updateServiceNotification();
const auto text = TextWithEntities {
qs(d.vmessage()),
Api::EntitiesFromMTP(d.ventities().v)
Api::EntitiesFromMTP(&session(), d.ventities().v)
};
if (IsForceLogoutNotification(d)) {
Core::App().forceLogOut(text);
@ -4604,9 +4613,10 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
const auto &data = update.c_updateDraftMessage();
const auto peerId = peerFromMTP(data.vpeer());
data.vdraft().match([&](const MTPDdraftMessage &data) {
Data::applyPeerCloudDraft(peerId, data);
Data::ApplyPeerCloudDraft(&session(), peerId, data);
}, [&](const MTPDdraftMessageEmpty &data) {
Data::clearPeerCloudDraft(
Data::ClearPeerCloudDraft(
&session(),
peerId,
data.vdate().value_or_empty());
});

View File

@ -38,6 +38,7 @@ struct PeerUpdate;
namespace Data {
class WallPaper;
class CloudImageView;
} // namespace Data
namespace Dialogs {
@ -107,7 +108,9 @@ class MainWidget
public:
using SectionShow = Window::SectionShow;
MainWidget(QWidget *parent, not_null<Window::SessionController*> controller);
MainWidget(
QWidget *parent,
not_null<Window::SessionController*> controller);
[[nodiscard]] Main::Session &session() const;
@ -463,6 +466,8 @@ private:
int _thirdColumnWidth = 0;
Ui::Animations::Simple _a_dialogsWidth;
std::shared_ptr<Data::CloudImageView> _selfUserpicView;
object_ptr<Ui::PlainShadow> _sideShadow;
object_ptr<Ui::PlainShadow> _thirdShadow = { nullptr };
object_ptr<Ui::ResizeArea> _firstColumnResizeArea = { nullptr };

View File

@ -139,7 +139,7 @@ void MainWindow::createTrayIconMenu() {
? tr::ktg_settings_disable_sound_from_tray(tr::now)
: tr::ktg_settings_enable_sound_from_tray(tr::now);
if (Platform::IsLinux()) {
if (Platform::IsLinux() && !Platform::IsWayland()) {
trayIconMenu->addAction(tr::ktg_open_from_tray(tr::now), this, SLOT(showFromTray()));
}
trayIconMenu->addAction(tr::lng_minimize_to_tray(tr::now), this, SLOT(minimizeToTray()));
@ -593,12 +593,12 @@ void MainWindow::updateTrayMenu(bool force) {
if (!trayIconMenu || (Platform::IsWindows() && !force)) return;
auto actions = trayIconMenu->actions();
if (Platform::IsLinux()) {
if (Platform::IsLinux() && !Platform::IsWayland()) {
auto minimizeAction = actions.at(1);
minimizeAction->setEnabled(isVisible());
} else {
updateIsActive(0);
auto active = isActive();
auto active = Platform::IsWayland() ? isVisible() : isActive();
auto toggleAction = actions.at(0);
disconnect(toggleAction, SIGNAL(triggered(bool)), this, SLOT(minimizeToTray()));
disconnect(toggleAction, SIGNAL(triggered(bool)), this, SLOT(showFromTray()));
@ -607,7 +607,7 @@ void MainWindow::updateTrayMenu(bool force) {
? tr::lng_minimize_to_tray(tr::now)
: tr::ktg_open_from_tray(tr::now));
}
auto notificationAction = actions.at(Platform::IsLinux() ? 2 : 1);
auto notificationAction = actions.at(Platform::IsLinux() && !Platform::IsWayland() ? 2 : 1);
auto notificationActionText = Global::DesktopNotify()
? tr::lng_disable_notifications_from_tray(tr::now)
: tr::lng_enable_notifications_from_tray(tr::now);
@ -738,7 +738,7 @@ void MainWindow::handleTrayIconActication(
updateTrayMenu(true);
QTimer::singleShot(1, this, SLOT(psShowTrayMenu()));
} else if (!skipTrayClick()) {
if (isActive()) {
if (Platform::IsWayland() ? isVisible() : isActive()) {
minimizeToTray();
} else {
showFromTray(reason);

View File

@ -353,11 +353,11 @@ OverlayWidget::OverlayWidget()
}
}, lifetime());
#ifdef Q_OS_LINUX
#if defined Q_OS_UNIX && !defined Q_OS_MAC
setWindowFlags(Qt::FramelessWindowHint | Qt::MaximizeUsingFullscreenGeometryHint);
#else // Q_OS_LINUX
#else // Q_OS_UNIX && !Q_OS_MAC
setWindowFlags(Qt::FramelessWindowHint);
#endif // Q_OS_LINUX
#endif // Q_OS_UNIX && !Q_OS_MAC
moveToScreen();
setAttribute(Qt::WA_NoSystemBackground, true);
setAttribute(Qt::WA_TranslucentBackground, true);
@ -1538,6 +1538,21 @@ Data::FileOrigin OverlayWidget::fileOrigin() const {
return Data::FileOrigin();
}
Data::FileOrigin OverlayWidget::fileOrigin(const Entity &entity) const {
if (const auto item = entity.item) {
return item->fullId();
} else if (!entity.data.is<not_null<PhotoData*>>()) {
return Data::FileOrigin();
}
const auto photo = entity.data.get_unchecked<not_null<PhotoData*>>();
if (_user) {
return Data::FileOriginUserPhoto(_user->bareId(), photo->id);
} else if (_peer && _peer->userpicPhotoId() == photo->id) {
return Data::FileOriginPeerPhoto(_peer->id);
}
return Data::FileOrigin();
}
bool OverlayWidget::validSharedMedia() const {
if (auto key = sharedMediaKey()) {
if (!_sharedMedia) {
@ -1883,8 +1898,6 @@ void OverlayWidget::showPhoto(not_null<PhotoData*> photo, HistoryItem *context)
_firstOpenedPeerPhoto = false;
assignMediaPointer(photo);
refreshMediaViewer();
displayPhoto(photo, context);
preloadData(0);
activateControls();
@ -1897,8 +1910,6 @@ void OverlayWidget::showPhoto(not_null<PhotoData*> photo, not_null<PeerData*> co
_firstOpenedPeerPhoto = true;
assignMediaPointer(photo);
refreshMediaViewer();
displayPhoto(photo, nullptr);
preloadData(0);
activateControls();
@ -2031,6 +2042,7 @@ void OverlayWidget::displayDocument(
initThemePreview();
} else {
_documentMedia->automaticLoad(fileOrigin(), item);
_document->saveFromDataSilent();
auto &location = _document->location(true);
if (location.accessEnable()) {
const auto &path = location.name();
@ -2144,11 +2156,11 @@ void OverlayWidget::displayFinished() {
updateControls();
if (isHidden()) {
Ui::Platform::UpdateOverlayed(this);
#ifdef Q_OS_LINUX
#if defined Q_OS_UNIX && !defined Q_OS_MAC
showFullScreen();
#else // Q_OS_LINUX
#else // Q_OS_UNIX && !Q_OS_MAC
show();
#endif // Q_OS_LINUX
#endif // Q_OS_UNIX && !Q_OS_MAC
Ui::Platform::ShowOverAll(this);
activateWindow();
QApplication::setActiveWindow(this);
@ -3420,16 +3432,17 @@ OverlayWidget::Entity OverlayWidget::entityByIndex(int index) const {
return { std::nullopt, nullptr };
}
void OverlayWidget::setContext(base::optional_variant<
void OverlayWidget::setContext(
base::optional_variant<
not_null<HistoryItem*>,
not_null<PeerData*>> context) {
if (auto item = base::get_if<not_null<HistoryItem*>>(&context)) {
if (const auto item = base::get_if<not_null<HistoryItem*>>(&context)) {
_msgid = (*item)->fullId();
_canForwardItem = (*item)->allowsForward();
_canDeleteItem = (*item)->canDelete();
_history = (*item)->history();
_peer = _history->peer;
} else if (auto peer = base::get_if<not_null<PeerData*>>(&context)) {
} else if (const auto peer = base::get_if<not_null<PeerData*>>(&context)) {
_msgid = FullMsgId();
_canForwardItem = _canDeleteItem = false;
_history = (*peer)->owner().history(*peer);
@ -3498,15 +3511,15 @@ void OverlayWidget::preloadData(int delta) {
auto entity = entityByIndex(index);
if (auto photo = base::get_if<not_null<PhotoData*>>(&entity.data)) {
const auto [i, ok] = photos.emplace((*photo)->createMediaView());
(*i)->wanted(Data::PhotoSize::Small, fileOrigin());
(*photo)->load(fileOrigin(), LoadFromCloudOrLocal, true);
(*i)->wanted(Data::PhotoSize::Small, fileOrigin(entity));
(*photo)->load(fileOrigin(entity), LoadFromCloudOrLocal, true);
} else if (auto document = base::get_if<not_null<DocumentData*>>(
&entity.data)) {
const auto [i, ok] = documents.emplace(
(*document)->createMediaView());
(*i)->thumbnailWanted(fileOrigin());
(*i)->thumbnailWanted(fileOrigin(entity));
if (!(*i)->canBePlayed()) {
(*i)->automaticLoad(fileOrigin(), entity.item);
(*i)->automaticLoad(fileOrigin(entity), entity.item);
}
}
}

View File

@ -239,7 +239,8 @@ private:
bool validCollage() const;
void validateCollage();
Data::FileOrigin fileOrigin() const;
[[nodiscard]] Data::FileOrigin fileOrigin() const;
[[nodiscard]] Data::FileOrigin fileOrigin(const Entity& entity) const;
void refreshFromLabel(HistoryItem *item);
void refreshCaption(HistoryItem *item);

View File

@ -438,7 +438,8 @@ PipPanel::Position PipPanel::countPosition() const {
const auto right = left + result.geometry.width();
const auto top = result.geometry.y();
const auto bottom = top + result.geometry.height();
if (!_dragState || *_dragState != RectPart::Center) {
if ((!_dragState || *_dragState != RectPart::Center)
&& !Platform::IsWayland()) {
if (left == available.x()) {
result.attached |= RectPart::Left;
} else if (right == available.x() + available.width()) {
@ -514,6 +515,11 @@ void PipPanel::setPositionOnScreen(Position position, QRect available) {
std::max(normalized.width(), minimalSize.width()),
std::max(normalized.height(), minimalSize.height()));
// Apply maximal size.
const auto maximalSize = (_ratio.width() > _ratio.height())
? QSize(fit.width(), fit.width() * _ratio.height() / _ratio.width())
: QSize(fit.height() * _ratio.width() / _ratio.height(), fit.height());
// Apply left-right screen borders.
const auto skip = st::pipBorderSkip;
const auto inner = screen.marginsRemoved({ skip, skip, skip, skip });
@ -547,8 +553,10 @@ void PipPanel::setPositionOnScreen(Position position, QRect available) {
geometry += _padding;
setGeometry(geometry);
setMinimumSize(geometry.size());
setMaximumSize(geometry.size());
setMinimumSize(minimalSize);
setMaximumSize(
std::max(minimalSize.width(), maximalSize.width()),
std::max(minimalSize.height(), maximalSize.height()));
updateDecorations();
update();
}
@ -671,6 +679,40 @@ void PipPanel::mouseMoveEvent(QMouseEvent *e) {
if (!_dragState
&& (point - _pressPoint).manhattanLength() > distance
&& !_dragDisabled) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) || defined DESKTOP_APP_QT_PATCHED
if (Platform::IsWayland()) {
switch (*_pressState) {
case RectPart::Center:
windowHandle()->startSystemMove();
break;
case RectPart::TopLeft:
windowHandle()->startSystemResize(Qt::TopEdge | Qt::LeftEdge);
break;
case RectPart::TopRight:
windowHandle()->startSystemResize(Qt::TopEdge | Qt::RightEdge);
break;
case RectPart::BottomRight:
windowHandle()->startSystemResize(Qt::BottomEdge | Qt::RightEdge);
break;
case RectPart::BottomLeft:
windowHandle()->startSystemResize(Qt::BottomEdge | Qt::LeftEdge);
break;
case RectPart::Left:
windowHandle()->startSystemResize(Qt::LeftEdge);
break;
case RectPart::Top:
windowHandle()->startSystemResize(Qt::TopEdge);
break;
case RectPart::Right:
windowHandle()->startSystemResize(Qt::RightEdge);
break;
case RectPart::Bottom:
windowHandle()->startSystemResize(Qt::BottomEdge);
break;
}
return;
}
#endif // Qt >= 5.15 || DESKTOP_APP_QT_PATCHED
_dragState = _pressState;
updateDecorations();
_dragStartGeometry = geometry().marginsRemoved(_padding);
@ -722,8 +764,6 @@ void PipPanel::processDrag(QPoint point) {
const auto newGeometry = valid.marginsAdded(_padding);
_positionAnimation.stop();
setGeometry(newGeometry);
setMinimumSize(newGeometry.size());
setMaximumSize(newGeometry.size());
}
}
@ -810,8 +850,6 @@ void PipPanel::updateDecorations() {
_useTransparency = use;
setAttribute(Qt::WA_OpaquePaintEvent, !_useTransparency);
setGeometry(newGeometry);
setMinimumSize(newGeometry.size());
setMaximumSize(newGeometry.size());
update();
}

View File

@ -72,10 +72,10 @@ bool GdkHelperLoadGtk3(QLibrary &lib) {
void GdkHelperLoad(QLibrary &lib) {
gdk_helper_loaded = GtkLoaded::GtkNone;
if (GdkHelperLoadGtk2(lib)) {
gdk_helper_loaded = GtkLoaded::Gtk2;
} else if (GdkHelperLoadGtk3(lib)) {
if (GdkHelperLoadGtk3(lib)) {
gdk_helper_loaded = GtkLoaded::Gtk3;
} else if (GdkHelperLoadGtk2(lib)) {
gdk_helper_loaded = GtkLoaded::Gtk2;
}
}

View File

@ -69,24 +69,19 @@ void gtkMessageHandler(
bool setupGtkBase(QLibrary &lib_gtk) {
if (!load(lib_gtk, "gtk_init_check", gtk_init_check)) return false;
if (!load(lib_gtk, "gtk_settings_get_default", gtk_settings_get_default)) return false;
if (!load(lib_gtk, "gtk_menu_new", gtk_menu_new)) return false;
if (!load(lib_gtk, "gtk_menu_get_type", gtk_menu_get_type)) return false;
if (!load(lib_gtk, "gtk_menu_item_new_with_label", gtk_menu_item_new_with_label)) return false;
if (!load(lib_gtk, "gtk_menu_item_set_label", gtk_menu_item_set_label)) return false;
if (!load(lib_gtk, "gtk_menu_shell_append", gtk_menu_shell_append)) return false;
if (!load(lib_gtk, "gtk_menu_shell_get_type", gtk_menu_shell_get_type)) return false;
if (!load(lib_gtk, "gtk_widget_show", gtk_widget_show)) return false;
if (!load(lib_gtk, "gtk_widget_hide", gtk_widget_hide)) return false;
if (!load(lib_gtk, "gtk_widget_get_toplevel", gtk_widget_get_toplevel)) return false;
if (!load(lib_gtk, "gtk_widget_get_visible", gtk_widget_get_visible)) return false;
if (!load(lib_gtk, "gtk_widget_get_window", gtk_widget_get_window)) return false;
if (!load(lib_gtk, "gtk_widget_set_sensitive", gtk_widget_set_sensitive)) return false;
if (!load(lib_gtk, "gtk_widget_realize", gtk_widget_realize)) return false;
if (!load(lib_gtk, "gtk_widget_hide_on_delete", gtk_widget_hide_on_delete)) return false;
if (!load(lib_gtk, "gtk_widget_destroy", gtk_widget_destroy)) return false;
if (!load(lib_gtk, "gtk_clipboard_get", gtk_clipboard_get)) return false;
if (!load(lib_gtk, "gtk_clipboard_store", gtk_clipboard_store)) return false;
if (!load(lib_gtk, "gtk_clipboard_wait_for_contents", gtk_clipboard_wait_for_contents)) return false;
if (!load(lib_gtk, "gtk_clipboard_wait_for_image", gtk_clipboard_wait_for_image)) return false;
if (!load(lib_gtk, "gtk_selection_data_targets_include_image", gtk_selection_data_targets_include_image)) return false;
if (!load(lib_gtk, "gtk_selection_data_free", gtk_selection_data_free)) return false;
if (!load(lib_gtk, "gtk_file_chooser_dialog_new", gtk_file_chooser_dialog_new)) return false;
if (!load(lib_gtk, "gtk_file_chooser_get_type", gtk_file_chooser_get_type)) return false;
if (!load(lib_gtk, "gtk_image_get_type", gtk_image_get_type)) return false;
@ -122,22 +117,23 @@ bool setupGtkBase(QLibrary &lib_gtk) {
if (!load(lib_gtk, "g_type_check_instance_cast", g_type_check_instance_cast)) return false;
if (!load(lib_gtk, "g_type_check_instance_is_a", g_type_check_instance_is_a)) return false;
if (!load(lib_gtk, "g_signal_connect_data", g_signal_connect_data)) return false;
if (!load(lib_gtk, "g_signal_handler_disconnect", g_signal_handler_disconnect)) return false;
if (!load(lib_gtk, "g_object_get", g_object_get)) return false;
if (!load(lib_gtk, "g_object_ref_sink", g_object_ref_sink)) return false;
if (!load(lib_gtk, "g_object_unref", g_object_unref)) return false;
if (!load(lib_gtk, "g_free", g_free)) return false;
if (!load(lib_gtk, "g_list_foreach", g_list_foreach)) return false;
if (!load(lib_gtk, "g_list_free", g_list_free)) return false;
if (!load(lib_gtk, "g_list_free_full", g_list_free_full)) return false;
if (!load(lib_gtk, "g_error_free", g_error_free)) return false;
if (!load(lib_gtk, "g_slist_free", g_slist_free)) return false;
if (!load(lib_gtk, "g_log_set_handler", g_log_set_handler)) return false;
if (!load(lib_gtk, "g_log_default_handler", g_log_default_handler)) return false;
if (!load(lib_gtk, "gdk_atom_intern", gdk_atom_intern)) return false;
if (!load(lib_gtk, "gdk_pixbuf_get_has_alpha", gdk_pixbuf_get_has_alpha)) return false;
if (!load(lib_gtk, "gdk_pixbuf_get_pixels", gdk_pixbuf_get_pixels)) return false;
if (!load(lib_gtk, "gdk_pixbuf_get_width", gdk_pixbuf_get_width)) return false;
if (!load(lib_gtk, "gdk_pixbuf_get_height", gdk_pixbuf_get_height)) return false;
if (!load(lib_gtk, "gdk_pixbuf_get_rowstride", gdk_pixbuf_get_rowstride)) return false;
if (load(lib_gtk, "gdk_set_allowed_backends", gdk_set_allowed_backends)) {
// We work only with X11 GDK backend.
// Otherwise we get segfault in Ubuntu 17.04 in gtk_init_check() call.
@ -178,23 +174,18 @@ bool setupGtkBase(QLibrary &lib_gtk) {
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
f_gtk_init_check gtk_init_check = nullptr;
f_gtk_settings_get_default gtk_settings_get_default = nullptr;
f_gtk_menu_new gtk_menu_new = nullptr;
f_gtk_menu_get_type gtk_menu_get_type = nullptr;
f_gtk_menu_item_new_with_label gtk_menu_item_new_with_label = nullptr;
f_gtk_menu_item_set_label gtk_menu_item_set_label = nullptr;
f_gtk_menu_shell_append gtk_menu_shell_append = nullptr;
f_gtk_menu_shell_get_type gtk_menu_shell_get_type = nullptr;
f_gtk_widget_show gtk_widget_show = nullptr;
f_gtk_widget_hide gtk_widget_hide = nullptr;
f_gtk_widget_get_toplevel gtk_widget_get_toplevel = nullptr;
f_gtk_widget_get_visible gtk_widget_get_visible = nullptr;
f_gtk_widget_get_window gtk_widget_get_window = nullptr;
f_gtk_widget_set_sensitive gtk_widget_set_sensitive = nullptr;
f_gtk_widget_realize gtk_widget_realize = nullptr;
f_gtk_widget_hide_on_delete gtk_widget_hide_on_delete = nullptr;
f_gtk_widget_destroy gtk_widget_destroy = nullptr;
f_gtk_clipboard_get gtk_clipboard_get = nullptr;
f_gtk_clipboard_store gtk_clipboard_store = nullptr;
f_gtk_clipboard_wait_for_contents gtk_clipboard_wait_for_contents = nullptr;
f_gtk_clipboard_wait_for_image gtk_clipboard_wait_for_image = nullptr;
f_gtk_selection_data_targets_include_image gtk_selection_data_targets_include_image = nullptr;
f_gtk_selection_data_free gtk_selection_data_free = nullptr;
f_gtk_file_chooser_dialog_new gtk_file_chooser_dialog_new = nullptr;
f_gtk_file_chooser_get_type gtk_file_chooser_get_type = nullptr;
f_gtk_image_get_type gtk_image_get_type = nullptr;
@ -232,32 +223,16 @@ f_gtk_dialog_run gtk_dialog_run = nullptr;
f_g_type_check_instance_cast g_type_check_instance_cast = nullptr;
f_g_type_check_instance_is_a g_type_check_instance_is_a = nullptr;
f_g_signal_connect_data g_signal_connect_data = nullptr;
f_g_signal_handler_disconnect g_signal_handler_disconnect = nullptr;
f_gdk_init_check gdk_init_check = nullptr;
f_gdk_pixbuf_new_from_data gdk_pixbuf_new_from_data = nullptr;
f_gdk_pixbuf_new_from_file gdk_pixbuf_new_from_file = nullptr;
f_gdk_atom_intern gdk_atom_intern = nullptr;
f_gdk_pixbuf_new_from_file_at_size gdk_pixbuf_new_from_file_at_size = nullptr;
f_gtk_status_icon_new_from_pixbuf gtk_status_icon_new_from_pixbuf = nullptr;
f_gtk_status_icon_set_from_pixbuf gtk_status_icon_set_from_pixbuf = nullptr;
f_gtk_status_icon_new_from_file gtk_status_icon_new_from_file = nullptr;
f_gtk_status_icon_set_from_file gtk_status_icon_set_from_file = nullptr;
f_gtk_status_icon_set_title gtk_status_icon_set_title = nullptr;
f_gtk_status_icon_set_tooltip_text gtk_status_icon_set_tooltip_text = nullptr;
f_gtk_status_icon_set_visible gtk_status_icon_set_visible = nullptr;
f_gtk_status_icon_is_embedded gtk_status_icon_is_embedded = nullptr;
f_gtk_status_icon_get_geometry gtk_status_icon_get_geometry = nullptr;
f_gtk_status_icon_position_menu gtk_status_icon_position_menu = nullptr;
f_gtk_menu_popup gtk_menu_popup = nullptr;
f_gtk_get_current_event_time gtk_get_current_event_time = nullptr;
f_gdk_pixbuf_get_has_alpha gdk_pixbuf_get_has_alpha = nullptr;
f_gdk_pixbuf_get_pixels gdk_pixbuf_get_pixels = nullptr;
f_gdk_pixbuf_get_width gdk_pixbuf_get_width = nullptr;
f_gdk_pixbuf_get_height gdk_pixbuf_get_height = nullptr;
f_gdk_pixbuf_get_rowstride gdk_pixbuf_get_rowstride = nullptr;
f_g_object_get g_object_get = nullptr;
f_g_object_ref_sink g_object_ref_sink = nullptr;
f_g_object_unref g_object_unref = nullptr;
f_g_idle_add g_idle_add = nullptr;
f_g_free g_free = nullptr;
f_g_list_foreach g_list_foreach = nullptr;
f_g_list_free g_list_free = nullptr;
f_g_list_free_full g_list_free_full = nullptr;
f_g_error_free g_error_free = nullptr;
f_g_slist_free g_slist_free = nullptr;
f_g_log_set_handler g_log_set_handler = nullptr;
f_g_log_default_handler g_log_default_handler = nullptr;
@ -265,6 +240,10 @@ f_g_log_default_handler g_log_default_handler = nullptr;
void start() {
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
if (!UseGtkIntegration()) {
return;
}
DEBUG_LOG(("Loading libraries"));
bool gtkLoaded = false;
@ -279,23 +258,7 @@ void start() {
}
if (gtkLoaded) {
load(lib_gtk, "gdk_init_check", gdk_init_check);
load(lib_gtk, "gdk_pixbuf_new_from_data", gdk_pixbuf_new_from_data);
load(lib_gtk, "gdk_pixbuf_new_from_file", gdk_pixbuf_new_from_file);
load(lib_gtk, "gdk_pixbuf_new_from_file_at_size", gdk_pixbuf_new_from_file_at_size);
load(lib_gtk, "gtk_status_icon_new_from_pixbuf", gtk_status_icon_new_from_pixbuf);
load(lib_gtk, "gtk_status_icon_set_from_pixbuf", gtk_status_icon_set_from_pixbuf);
load(lib_gtk, "gtk_status_icon_new_from_file", gtk_status_icon_new_from_file);
load(lib_gtk, "gtk_status_icon_set_from_file", gtk_status_icon_set_from_file);
load(lib_gtk, "gtk_status_icon_set_title", gtk_status_icon_set_title);
load(lib_gtk, "gtk_status_icon_set_tooltip_text", gtk_status_icon_set_tooltip_text);
load(lib_gtk, "gtk_status_icon_set_visible", gtk_status_icon_set_visible);
load(lib_gtk, "gtk_status_icon_is_embedded", gtk_status_icon_is_embedded);
load(lib_gtk, "gtk_status_icon_get_geometry", gtk_status_icon_get_geometry);
load(lib_gtk, "gtk_status_icon_position_menu", gtk_status_icon_position_menu);
load(lib_gtk, "gtk_menu_popup", gtk_menu_popup);
load(lib_gtk, "gtk_get_current_event_time", gtk_get_current_event_time);
load(lib_gtk, "g_idle_add", g_idle_add);
internal::GdkHelperLoad(lib_gtk);

View File

@ -47,42 +47,15 @@ extern f_gtk_init_check gtk_init_check;
typedef GtkSettings* (*f_gtk_settings_get_default)(void);
extern f_gtk_settings_get_default gtk_settings_get_default;
typedef GtkWidget* (*f_gtk_menu_new)(void);
extern f_gtk_menu_new gtk_menu_new;
typedef GType (*f_gtk_menu_get_type)(void) G_GNUC_CONST;
extern f_gtk_menu_get_type gtk_menu_get_type;
typedef GtkWidget* (*f_gtk_menu_item_new_with_label)(const gchar *label);
extern f_gtk_menu_item_new_with_label gtk_menu_item_new_with_label;
typedef void (*f_gtk_menu_item_set_label)(GtkMenuItem *menu_item, const gchar *label);
extern f_gtk_menu_item_set_label gtk_menu_item_set_label;
typedef void (*f_gtk_menu_shell_append)(GtkMenuShell *menu_shell, GtkWidget *child);
extern f_gtk_menu_shell_append gtk_menu_shell_append;
typedef GType (*f_gtk_menu_shell_get_type)(void) G_GNUC_CONST;
extern f_gtk_menu_shell_get_type gtk_menu_shell_get_type;
typedef void (*f_gtk_widget_show)(GtkWidget *widget);
extern f_gtk_widget_show gtk_widget_show;
typedef void (*f_gtk_widget_hide)(GtkWidget *widget);
extern f_gtk_widget_hide gtk_widget_hide;
typedef GtkWidget* (*f_gtk_widget_get_toplevel)(GtkWidget *widget);
extern f_gtk_widget_get_toplevel gtk_widget_get_toplevel;
typedef gboolean (*f_gtk_widget_get_visible)(GtkWidget *widget);
extern f_gtk_widget_get_visible gtk_widget_get_visible;
typedef GdkWindow* (*f_gtk_widget_get_window)(GtkWidget *widget);
extern f_gtk_widget_get_window gtk_widget_get_window;
typedef void (*f_gtk_widget_set_sensitive)(GtkWidget *widget, gboolean sensitive);
extern f_gtk_widget_set_sensitive gtk_widget_set_sensitive;
typedef void (*f_gtk_widget_realize)(GtkWidget *widget);
extern f_gtk_widget_realize gtk_widget_realize;
@ -98,6 +71,18 @@ extern f_gtk_clipboard_get gtk_clipboard_get;
typedef void (*f_gtk_clipboard_store)(GtkClipboard *clipboard);
extern f_gtk_clipboard_store gtk_clipboard_store;
typedef GtkSelectionData* (*f_gtk_clipboard_wait_for_contents)(GtkClipboard *clipboard, GdkAtom target);
extern f_gtk_clipboard_wait_for_contents gtk_clipboard_wait_for_contents;
typedef GdkPixbuf* (*f_gtk_clipboard_wait_for_image)(GtkClipboard *clipboard);
extern f_gtk_clipboard_wait_for_image gtk_clipboard_wait_for_image;
typedef gboolean (*f_gtk_selection_data_targets_include_image)(const GtkSelectionData *selection_data, gboolean writable);
extern f_gtk_selection_data_targets_include_image gtk_selection_data_targets_include_image;
typedef void (*f_gtk_selection_data_free)(GtkSelectionData *data);
extern f_gtk_selection_data_free gtk_selection_data_free;
typedef GtkWidget* (*f_gtk_file_chooser_dialog_new)(const gchar *title, GtkWindow *parent, GtkFileChooserAction action, const gchar *first_button_text, ...) G_GNUC_NULL_TERMINATED;
extern f_gtk_file_chooser_dialog_new gtk_file_chooser_dialog_new;
@ -190,16 +175,6 @@ inline Result *g_type_cic_helper(Object *instance, GType iface_type) {
return reinterpret_cast<Result*>(g_type_check_instance_cast(reinterpret_cast<GTypeInstance*>(instance), iface_type));
}
template <typename Object>
inline GtkMenu *gtk_menu_cast(Object *obj) {
return g_type_cic_helper<GtkMenu, Object>(obj, gtk_menu_get_type());
}
template <typename Object>
inline GtkMenuShell *gtk_menu_shell_cast(Object *obj) {
return g_type_cic_helper<GtkMenuShell, Object>(obj, gtk_menu_get_type());
}
typedef GType (*f_gtk_dialog_get_type)(void) G_GNUC_CONST;
extern f_gtk_dialog_get_type gtk_dialog_get_type;
@ -273,84 +248,36 @@ inline gulong g_signal_connect_swapped_helper(gpointer instance, const gchar *de
return g_signal_connect_data(instance, detailed_signal, c_handler, data, destroy_data, G_CONNECT_SWAPPED);
}
typedef void (*f_g_signal_handler_disconnect)(gpointer instance, gulong handler_id);
extern f_g_signal_handler_disconnect g_signal_handler_disconnect;
typedef gboolean (*f_gdk_init_check)(gint *argc, gchar ***argv);
extern f_gdk_init_check gdk_init_check;
typedef GdkPixbuf* (*f_gdk_pixbuf_new_from_data)(const guchar *data, GdkColorspace colorspace, gboolean has_alpha, int bits_per_sample, int width, int height, int rowstride, GdkPixbufDestroyNotify destroy_fn, gpointer destroy_fn_data);
extern f_gdk_pixbuf_new_from_data gdk_pixbuf_new_from_data;
typedef GdkPixbuf* (*f_gdk_pixbuf_new_from_file)(const gchar *filename, GError **error);
extern f_gdk_pixbuf_new_from_file gdk_pixbuf_new_from_file;
typedef GdkAtom (*f_gdk_atom_intern)(const gchar *atom_name, gboolean only_if_exists);
extern f_gdk_atom_intern gdk_atom_intern;
typedef GdkPixbuf* (*f_gdk_pixbuf_new_from_file_at_size)(const gchar *filename, int width, int height, GError **error);
extern f_gdk_pixbuf_new_from_file_at_size gdk_pixbuf_new_from_file_at_size;
typedef GtkStatusIcon* (*f_gtk_status_icon_new_from_pixbuf)(GdkPixbuf *pixbuf);
extern f_gtk_status_icon_new_from_pixbuf gtk_status_icon_new_from_pixbuf;
typedef gboolean (*f_gdk_pixbuf_get_has_alpha)(const GdkPixbuf *pixbuf);
extern f_gdk_pixbuf_get_has_alpha gdk_pixbuf_get_has_alpha;
typedef void (*f_gtk_status_icon_set_from_pixbuf)(GtkStatusIcon *status_icon, GdkPixbuf *pixbuf);
extern f_gtk_status_icon_set_from_pixbuf gtk_status_icon_set_from_pixbuf;
typedef guchar* (*f_gdk_pixbuf_get_pixels)(const GdkPixbuf *pixbuf);
extern f_gdk_pixbuf_get_pixels gdk_pixbuf_get_pixels;
typedef GtkStatusIcon* (*f_gtk_status_icon_new_from_file)(const gchar *filename);
extern f_gtk_status_icon_new_from_file gtk_status_icon_new_from_file;
typedef int (*f_gdk_pixbuf_get_width)(const GdkPixbuf *pixbuf);
extern f_gdk_pixbuf_get_width gdk_pixbuf_get_width;
typedef void (*f_gtk_status_icon_set_from_file)(GtkStatusIcon *status_icon, const gchar *filename);
extern f_gtk_status_icon_set_from_file gtk_status_icon_set_from_file;
typedef int (*f_gdk_pixbuf_get_height)(const GdkPixbuf *pixbuf);
extern f_gdk_pixbuf_get_height gdk_pixbuf_get_height;
typedef void (*f_gtk_status_icon_set_title)(GtkStatusIcon *status_icon, const gchar *title);
extern f_gtk_status_icon_set_title gtk_status_icon_set_title;
typedef void (*f_gtk_status_icon_set_tooltip_text)(GtkStatusIcon *status_icon, const gchar *title);
extern f_gtk_status_icon_set_tooltip_text gtk_status_icon_set_tooltip_text;
typedef void (*f_gtk_status_icon_set_visible)(GtkStatusIcon *status_icon, gboolean visible);
extern f_gtk_status_icon_set_visible gtk_status_icon_set_visible;
typedef gboolean (*f_gtk_status_icon_is_embedded)(GtkStatusIcon *status_icon);
extern f_gtk_status_icon_is_embedded gtk_status_icon_is_embedded;
typedef gboolean (*f_gtk_status_icon_get_geometry)(GtkStatusIcon *status_icon, GdkScreen **screen, GdkRectangle *area, GtkOrientation *orientation);
extern f_gtk_status_icon_get_geometry gtk_status_icon_get_geometry;
typedef void (*f_gtk_status_icon_position_menu)(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data);
extern f_gtk_status_icon_position_menu gtk_status_icon_position_menu;
typedef void (*f_gtk_menu_popup)(GtkMenu *menu, GtkWidget *parent_menu_shell, GtkWidget *parent_menu_item, GtkMenuPositionFunc func, gpointer data, guint button, guint32 activate_time);
extern f_gtk_menu_popup gtk_menu_popup;
typedef guint32 (*f_gtk_get_current_event_time)(void);
extern f_gtk_get_current_event_time gtk_get_current_event_time;
typedef int (*f_gdk_pixbuf_get_rowstride)(const GdkPixbuf *pixbuf);
extern f_gdk_pixbuf_get_rowstride gdk_pixbuf_get_rowstride;
typedef void (*f_g_object_get)(gpointer object, const gchar *first_property_name, ...) G_GNUC_NULL_TERMINATED;
extern f_g_object_get g_object_get;
typedef gpointer (*f_g_object_ref_sink)(gpointer object);
extern f_g_object_ref_sink g_object_ref_sink;
typedef void (*f_g_object_unref)(gpointer object);
extern f_g_object_unref g_object_unref;
typedef guint (*f_g_idle_add)(GSourceFunc function, gpointer data);
extern f_g_idle_add g_idle_add;
typedef void (*f_g_free)(gpointer mem);
extern f_g_free g_free;
typedef void (*f_g_list_foreach)(GList *list, GFunc func, gpointer user_data);
extern f_g_list_foreach g_list_foreach;
typedef void (*f_g_list_free)(GList *list);
extern f_g_list_free g_list_free;
typedef void (*f_g_list_free_full)(GList *list, GDestroyNotify free_func);
extern f_g_list_free_full g_list_free_full;
typedef void (*f_g_error_free)(GError *error);
extern f_g_error_free g_error_free;
typedef void (*f_g_slist_free)(GSList *list);
extern f_g_slist_free g_slist_free;

View File

@ -443,6 +443,11 @@ void ForceDisabled(QAction *action, bool disabled) {
MainWindow::MainWindow(not_null<Window::Controller*> controller)
: Window::MainWindow(controller) {
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
if (Libs::gtk_clipboard_get != nullptr) {
_gtkClipboard = Libs::gtk_clipboard_get(Libs::gdk_atom_intern("CLIPBOARD", true));
}
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
}
void MainWindow::initHook() {

View File

@ -18,6 +18,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <dbusmenuexporter.h>
#endif
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
typedef struct _GtkClipboard GtkClipboard;
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
namespace Platform {
class MainWindow : public Window::MainWindow {
@ -70,6 +75,12 @@ public slots:
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
GtkClipboard *gtkClipboard() {
return _gtkClipboard;
}
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
protected:
void initHook() override;
void unreadCounterChangedHook() override;
@ -133,6 +144,10 @@ private:
void attachToSNITrayIcon();
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
GtkClipboard *_gtkClipboard = nullptr;
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
};
} // namespace Platform

View File

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "platform/linux/notifications_manager_linux.h"
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#include "base/platform/base_platform_info.h"
#include "platform/linux/specific_linux.h"
#include "history/history.h"
#include "lang/lang_keys.h"
@ -70,7 +71,7 @@ void GetSupported() {
}
Checked = true;
if (Global::NativeNotifications()) {
if (Global::NativeNotifications() && !Platform::IsWayland()) {
ComputeSupported(true);
} else {
ComputeSupported();
@ -474,7 +475,8 @@ std::unique_ptr<Window::Notifications::Manager> Create(
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
GetSupported();
if (Global::NativeNotifications() && Supported()) {
if ((Global::NativeNotifications() && Supported())
|| Platform::IsWayland()) {
return std::make_unique<Manager>(system);
}
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
@ -488,6 +490,10 @@ Manager::Private::Private(not_null<Manager*> manager, Type type)
, _manager(manager) {
qDBusRegisterMetaType<NotificationData::ImageData>();
if (!Supported()) {
return;
}
const auto serverInformation = GetServerInformation();
const auto capabilities = GetCapabilities();
@ -520,6 +526,8 @@ void Manager::Private::showNotification(
const QString &msg,
bool hideNameAndPhoto,
bool hideReplyButton) {
if (!Supported()) return;
auto notification = std::make_shared<NotificationData>(
_manager,
title,
@ -558,6 +566,8 @@ void Manager::Private::showNotification(
}
void Manager::Private::clearAll() {
if (!Supported()) return;
auto temp = base::take(_notifications);
for_const (auto &notifications, temp) {
for_const (auto notification, notifications) {
@ -567,6 +577,8 @@ void Manager::Private::clearAll() {
}
void Manager::Private::clearFromHistory(not_null<History*> history) {
if (!Supported()) return;
auto i = _notifications.find(history->peer->id);
if (i != _notifications.cend()) {
auto temp = base::take(i.value());
@ -579,6 +591,8 @@ void Manager::Private::clearFromHistory(not_null<History*> history) {
}
void Manager::Private::clearNotification(PeerId peerId, MsgId msgId) {
if (!Supported()) return;
auto i = _notifications.find(peerId);
if (i != _notifications.cend()) {
i.value().remove(msgId);

View File

@ -55,6 +55,8 @@ constexpr auto kXDGDesktopPortalService = "org.freedesktop.portal.Desktop"_cs;
constexpr auto kXDGDesktopPortalObjectPath = "/org/freedesktop/portal/desktop"_cs;
constexpr auto kPropertiesInterface = "org.freedesktop.DBus.Properties"_cs;
QStringList PlatformThemes;
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
void PortalAutostart(bool autostart, bool silent = false) {
QVariantMap options;
@ -295,14 +297,22 @@ bool IsStaticBinary() {
#endif // !DESKTOP_APP_USE_PACKAGED
}
bool UseGtkIntegration() {
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
static const auto Result = !qEnvironmentVariableIsSet(
"TDESKTOP_DISABLE_GTK_INTEGRATION");
return Result;
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
return false;
}
bool IsGtkIntegrationForced() {
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
static const auto Result = [&] {
const auto platformThemes = QString::fromUtf8(qgetenv("QT_QPA_PLATFORMTHEME"))
.split(':', QString::SkipEmptyParts);
return platformThemes.contains(qstr("gtk3"), Qt::CaseInsensitive)
|| platformThemes.contains(qstr("gtk2"), Qt::CaseInsensitive);
return PlatformThemes.contains(qstr("gtk3"), Qt::CaseInsensitive)
|| PlatformThemes.contains(qstr("gtk2"), Qt::CaseInsensitive);
}();
return Result;
@ -346,7 +356,6 @@ bool UseXDGDesktopPortal() {
return (
DesktopEnvironment::IsKDE()
|| InSnap()
|| envVar
) && portalPresent;
}();
@ -510,6 +519,43 @@ QString GetIconName() {
return Result;
}
QImage GetImageFromClipboard() {
QImage data;
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
if (!App::wnd()->gtkClipboard()) {
return data;
}
auto gsel = Libs::gtk_clipboard_wait_for_contents(
App::wnd()->gtkClipboard(),
Libs::gdk_atom_intern("TARGETS", true));
if (gsel) {
if (Libs::gtk_selection_data_targets_include_image(gsel, false)) {
auto img = Libs::gtk_clipboard_wait_for_image(App::wnd()->gtkClipboard());
if (img) {
data = QImage(
Libs::gdk_pixbuf_get_pixels(img),
Libs::gdk_pixbuf_get_width(img),
Libs::gdk_pixbuf_get_height(img),
Libs::gdk_pixbuf_get_rowstride(img),
Libs::gdk_pixbuf_get_has_alpha(img)
? QImage::Format_RGBA8888
: QImage::Format_RGB888).copy();
Libs::g_object_unref(img);
}
}
Libs::gtk_selection_data_free(gsel);
}
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
return data;
}
std::optional<crl::time> LastUserInputTime() {
// TODO: a fallback pure-X11 implementation, this one covers only major DEs on X11 and Wayland
// an example: https://stackoverflow.com/q/9049087
@ -697,6 +743,9 @@ int psFixPrevious() {
namespace Platform {
void start() {
PlatformThemes = QString::fromUtf8(qgetenv("QT_QPA_PLATFORMTHEME"))
.split(':', QString::SkipEmptyParts);
LOG(("Launcher filename: %1").arg(GetLauncherFilename()));
#ifdef TDESKTOP_USE_FONTCONFIG_FALLBACK
@ -706,6 +755,16 @@ void start() {
qputenv("PULSE_PROP_application.name", AppName.utf8());
qputenv("PULSE_PROP_application.icon_name", GetIconName().toLatin1());
// if gtk integration and qgtk3/qgtk2 platformtheme (or qgtk2 style)
// is used at the same time, the app will crash
if (UseGtkIntegration()
&& !IsStaticBinary()
&& !qEnvironmentVariableIsSet(
"TDESKTOP_I_KNOW_ABOUT_GTK_INCOMPATIBILITY")) {
qunsetenv("QT_QPA_PLATFORMTHEME");
qunsetenv("QT_STYLE_OVERRIDE");
}
if(IsStaticBinary()
|| InAppImage()
|| InFlatpak()

View File

@ -24,6 +24,7 @@ bool InFlatpak();
bool InSnap();
bool InAppImage();
bool IsStaticBinary();
bool UseGtkIntegration();
bool IsGtkIntegrationForced();
bool UseGtkFileDialog();
bool IsQtPluginsBundled();
@ -34,10 +35,8 @@ bool CanOpenDirectoryWithPortal();
QString ProcessNameByPID(const QString &pid);
QString RealExecutablePath(int argc, char *argv[]);
QString CurrentExecutablePath(int argc, char *argv[]);
QString AppRuntimeDirectory();
QString SingleInstanceLocalServerName(const QString &hash);
QString GetLauncherBasename();
QString GetLauncherFilename();

View File

@ -16,10 +16,6 @@ class LocationPoint;
namespace Platform {
QString CurrentExecutablePath(int argc, char *argv[]);
QString SingleInstanceLocalServerName(const QString &hash);
void RemoveQuarantine(const QString &path);
inline void FallbackFontConfigCheckBegin() {
@ -28,6 +24,10 @@ inline void FallbackFontConfigCheckBegin() {
inline void FallbackFontConfigCheckEnd() {
}
inline QImage GetImageFromClipboard() {
return {};
}
namespace ThirdParty {
inline void start() {

View File

@ -19,7 +19,9 @@ void DeInit();
// Platform dependent implementations.
#if defined Q_OS_MAC || defined Q_OS_LINUX
#if defined Q_OS_WINRT || defined Q_OS_WIN
#include "platform/win/audio_win.h"
#else // Q_OS_WINRT || Q_OS_WIN
namespace Platform {
namespace Audio {
@ -31,6 +33,4 @@ inline void DeInit() {
} // namespace Audio
} // namespace Platform
#elif defined Q_OS_WINRT || defined Q_OS_WIN // Q_OS_MAC || Q_OS_LINUX
#include "platform/win/audio_win.h"
#endif // Q_OS_MAC || Q_OS_LINUX || Q_OS_WINRT || Q_OS_WIN
#endif // Q_OS_WINRT || Q_OS_WIN

View File

@ -46,8 +46,8 @@ bool Get(
#ifdef Q_OS_MAC
#include "platform/mac/file_utilities_mac.h"
#elif defined Q_OS_LINUX // Q_OS_MAC
#elif defined Q_OS_UNIX // Q_OS_MAC
#include "platform/linux/file_utilities_linux.h"
#elif defined Q_OS_WINRT || defined Q_OS_WIN // Q_OS_MAC || Q_OS_LINUX
#elif defined Q_OS_WINRT || defined Q_OS_WIN // Q_OS_MAC || Q_OS_UNIX
#include "platform/win/file_utilities_win.h"
#endif // Q_OS_MAC || Q_OS_LINUX || Q_OS_WINRT || Q_OS_WIN
#endif // Q_OS_MAC || Q_OS_UNIX || Q_OS_WINRT || Q_OS_WIN

View File

@ -23,8 +23,8 @@ namespace Platform {
#ifdef Q_OS_MAC
#include "platform/mac/launcher_mac.h"
#elif defined Q_OS_LINUX // Q_OS_MAC
#elif defined Q_OS_UNIX // Q_OS_MAC
#include "platform/linux/launcher_linux.h"
#elif defined Q_OS_WINRT || defined Q_OS_WIN // Q_OS_MAC || Q_OS_LINUX
#elif defined Q_OS_WINRT || defined Q_OS_WIN // Q_OS_MAC || Q_OS_UNIX
#include "platform/win/launcher_win.h"
#endif // Q_OS_MAC || Q_OS_LINUX || Q_OS_WINRT || Q_OS_WIN
#endif // Q_OS_MAC || Q_OS_UNIX || Q_OS_WINRT || Q_OS_WIN

View File

@ -19,8 +19,8 @@ class MainWindow;
#ifdef Q_OS_MAC
#include "platform/mac/main_window_mac.h"
#elif defined Q_OS_LINUX // Q_OS_MAC
#elif defined Q_OS_UNIX // Q_OS_MAC
#include "platform/linux/main_window_linux.h"
#elif defined Q_OS_WIN // Q_OS_MAC || Q_OS_LINUX
#elif defined Q_OS_WIN // Q_OS_MAC || Q_OS_UNIX
#include "platform/win/main_window_win.h"
#endif // Q_OS_MAC || Q_OS_LINUX || Q_OS_WIN
#endif // Q_OS_MAC || Q_OS_UNIX || Q_OS_WIN

View File

@ -27,8 +27,8 @@ namespace Notifications {
#ifdef Q_OS_MAC
#include "platform/mac/notifications_manager_mac.h"
#elif defined Q_OS_LINUX // Q_OS_MAC
#elif defined Q_OS_UNIX // Q_OS_MAC
#include "platform/linux/notifications_manager_linux.h"
#elif defined Q_OS_WIN // Q_OS_MAC || Q_OS_LINUX
#elif defined Q_OS_WIN // Q_OS_MAC || Q_OS_UNIX
#include "platform/win/notifications_manager_win.h"
#endif // Q_OS_MAC || Q_OS_LINUX || Q_OS_WIN
#endif // Q_OS_MAC || Q_OS_UNIX || Q_OS_WIN

View File

@ -28,6 +28,8 @@ enum class SystemSettingsType {
void SetWatchingMediaKeys(bool watching);
void SetApplicationIcon(const QIcon &icon);
QString CurrentExecutablePath(int argc, char *argv[]);
QString SingleInstanceLocalServerName(const QString &hash);
void RegisterCustomScheme(bool force = false);
PermissionStatus GetPermissionStatus(PermissionType type);
void RequestPermission(PermissionType type, Fn<void(PermissionStatus)> resultCallback);
@ -41,6 +43,7 @@ bool OpenSystemSettings(SystemSettingsType type);
void IgnoreApplicationActivationRightNow();
bool AutostartSupported();
QImage GetImageFromClipboard();
namespace ThirdParty {
@ -52,8 +55,8 @@ void finish();
#ifdef Q_OS_MAC
#include "platform/mac/specific_mac.h"
#elif defined Q_OS_LINUX // Q_OS_MAC
#elif defined Q_OS_UNIX // Q_OS_MAC
#include "platform/linux/specific_linux.h"
#elif defined Q_OS_WIN // Q_OS_MAC || Q_OS_LINUX
#elif defined Q_OS_WIN // Q_OS_MAC || Q_OS_UNIX
#include "platform/win/specific_win.h"
#endif // Q_OS_MAC || Q_OS_LINUX || Q_OS_WIN
#endif // Q_OS_MAC || Q_OS_UNIX || Q_OS_WIN

View File

@ -26,7 +26,7 @@ void PreviewWindowFramePaint(QImage &preview, const style::palette &palette, QRe
#include "platform/mac/window_title_mac.h"
#elif defined Q_OS_WIN // Q_OS_MAC
#include "platform/win/window_title_win.h"
#elif defined Q_OS_WINRT || defined Q_OS_LINUX // Q_OS_MAC || Q_OS_WIN
#elif defined Q_OS_WINRT || defined Q_OS_UNIX // Q_OS_MAC || Q_OS_WIN
namespace Platform {
@ -44,4 +44,4 @@ inline void PreviewWindowFramePaint(QImage &preview, const style::palette &palet
} // namespace Platform
#endif // Q_OS_MAC || Q_OS_WIN || Q_OS_WINRT || Q_OS_LINUX
#endif // Q_OS_MAC || Q_OS_WIN || Q_OS_WINRT || Q_OS_UNIX

View File

@ -19,10 +19,6 @@ namespace Platform {
inline void SetWatchingMediaKeys(bool watching) {
}
QString CurrentExecutablePath(int argc, char *argv[]);
QString SingleInstanceLocalServerName(const QString &hash);
inline void IgnoreApplicationActivationRightNow() {
}
@ -32,6 +28,10 @@ inline void FallbackFontConfigCheckBegin() {
inline void FallbackFontConfigCheckEnd() {
}
inline QImage GetImageFromClipboard() {
return {};
}
namespace ThirdParty {
void start();

View File

@ -20,7 +20,7 @@ Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)
#elif defined Q_OS_MAC // Q_OS_WIN
Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin)
Q_IMPORT_PLUGIN(QGenericEnginePlugin)
#elif defined Q_OS_LINUX // Q_OS_WIN | Q_OS_MAC
#elif defined Q_OS_UNIX // Q_OS_WIN | Q_OS_MAC
Q_IMPORT_PLUGIN(ShmServerBufferPlugin)
Q_IMPORT_PLUGIN(DmaBufServerBufferPlugin)
Q_IMPORT_PLUGIN(DrmEglServerBufferPlugin)
@ -44,10 +44,10 @@ Q_IMPORT_PLUGIN(QNetworkManagerEnginePlugin)
Q_IMPORT_PLUGIN(QIbusPlatformInputContextPlugin)
Q_IMPORT_PLUGIN(QXdgDesktopPortalThemePlugin)
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // Q_OS_WIN | Q_OS_MAC | Q_OS_LINUX
#endif // Q_OS_WIN | Q_OS_MAC | Q_OS_UNIX
#endif // !DESKTOP_APP_USE_PACKAGED
#ifdef Q_OS_LINUX
#if defined Q_OS_UNIX && !defined Q_OS_MAC
#if !defined DESKTOP_APP_USE_PACKAGED || defined DESKTOP_APP_USE_PACKAGED_LAZY
Q_IMPORT_PLUGIN(QWaylandMaterialDecorationPlugin)
Q_IMPORT_PLUGIN(NimfInputContextPlugin)
@ -69,4 +69,4 @@ Q_IMPORT_PLUGIN(Qt5CTStylePlugin)
Q_IMPORT_PLUGIN(LXQtPlatformThemePlugin)
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#endif // DESKTOP_APP_USE_PACKAGED_LAZY_PLATFORMTHEMES
#endif // Q_OS_LINUX
#endif // Q_OS_UNIX && !Q_OS_MAC

View File

@ -499,11 +499,11 @@ void NotificationsCount::SampleWidget::destroyDelayed() {
_deleted = true;
// Ubuntu has a lag if deleteLater() called immediately.
#if defined Q_OS_LINUX32 || defined Q_OS_LINUX64
#if defined Q_OS_UNIX && !defined Q_OS_MAC
QTimer::singleShot(1000, [this] { delete this; });
#else // Q_OS_LINUX32 || Q_OS_LINUX64
#else // Q_OS_UNIX && !Q_OS_MAC
deleteLater();
#endif // Q_OS_LINUX32 || Q_OS_LINUX64
#endif // Q_OS_UNIX && !Q_OS_MAC
}
void SetupAdvancedNotifications(
@ -633,7 +633,7 @@ void SetupNotificationsContent(
return QString();
} else if (Platform::IsWindows()) {
return tr::lng_settings_use_windows(tr::now);
} else if (Platform::IsLinux()) {
} else if (Platform::IsLinux() && !Platform::IsWayland()) {
return tr::lng_settings_use_native_notifications(tr::now);
}
return QString();
@ -651,6 +651,9 @@ void SetupNotificationsContent(
}();
const auto advancedSlide = !Platform::IsMac10_8OrGreater()
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
&& !Platform::IsWayland()
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
? container->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
container,

View File

@ -79,9 +79,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#endif // OS_MAC_OLD
// Fix Google Breakpad build for Mac App Store and Linux version
#if defined Q_OS_MAC || defined Q_OS_LINUX
#ifdef Q_OS_UNIX
#define __STDC_FORMAT_MACROS
#endif // Q_OS_MAC || Q_OS_LINUX
#endif // Q_OS_UNIX
#include <array>
#include <vector>

View File

@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "media/clip/media_clip_reader.h"
#include "mtproto/facade.h"
#include "lottie/lottie_animation.h"
#include "history/history.h"
#include "history/history_item.h"
#include "boxes/send_files_box.h"
#include "boxes/confirm_box.h"
@ -129,6 +130,7 @@ MTPInputSingleMedia PrepareAlbumItemMedia(
auto caption = item->originalText();
TextUtilities::Trim(caption);
auto sentEntities = Api::EntitiesToMTP(
&item->history()->session(),
caption.entities,
Api::ConvertOption::SkipLocal);
const auto flags = !sentEntities.v.isEmpty()

Some files were not shown because too many files have changed in this diff Show More