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

This commit is contained in:
Eric Kotato 2020-03-14 18:17:17 +03:00
commit 9c7d8cc1e1
56 changed files with 1756 additions and 613 deletions

View file

@ -71,7 +71,7 @@ jobs:
libgtk2.0-dev libice-dev libsm-dev libicu-dev libdrm-dev dh-autoreconf \
autoconf automake build-essential libxml2-dev libass-dev libfreetype6-dev \
libgpac-dev libsdl1.2-dev libtheora-dev libtool libva-dev libvdpau-dev \
libvorbis-dev libenchant-dev libxcb1-dev libxcb-image0-dev libxcb-shm0-dev \
libvorbis-dev libxcb1-dev libxcb-image0-dev libxcb-shm0-dev \
libxcb-xfixes0-dev libxcb-keysyms1-dev libxcb-icccm4-dev libatspi2.0-dev \
libxcb-render-util0-dev libxcb-util0-dev libxcb-xkb-dev libxrender-dev \
libasound-dev libpulse-dev libxcb-sync0-dev libxcb-randr0-dev libegl1-mesa-dev \
@ -323,7 +323,7 @@ jobs:
run: |
cd $LibrariesPath
git clone -b openal-soft-1.19.1 --depth=1 $GIT/kcat/openal-soft.git
git clone -b openal-soft-1.20.1 --depth=1 $GIT/kcat/openal-soft.git
cd openal-soft/build
cmake -D LIBTYPE:STRING=STATIC ..
make -j$(nproc)
@ -342,14 +342,15 @@ jobs:
run: |
cd $LibrariesPath
opensslDir=openssl_${OPENSSL_VER}
git clone -b OpenSSL_${OPENSSL_VER}-stable --depth=1 \
$GIT/openssl/openssl openssl_${OPENSSL_VER}
cd openssl_${OPENSSL_VER}
$GIT/openssl/openssl $opensslDir
cd $opensslDir
./config --prefix=$LibrariesPath/openssl-cache
make -j$(nproc)
sudo make install
sudo make install_sw
cd ..
rm -rf openssl_${OPENSSL_VER}
rm -rf $opensslDir
- name: OpenSSL install.
run: |
cd $LibrariesPath

View file

@ -26,11 +26,11 @@ jobs:
GIT: "https://github.com"
PREFIX: "/usr/local/macos"
MACOSX_DEPLOYMENT_TARGET: "10.12"
XZ: "xz-5.0.5"
XZ: "xz-5.2.4"
QT: "5_12_5"
OPENSSL_VER: "1_1_1"
QT_PREFIX: "/usr/local/desktop-app/Qt-5.12.5"
LIBICONV_VER: "libiconv-1.15"
LIBICONV_VER: "libiconv-1.16"
UPLOAD_ARTIFACT: "false"
ONLY_CACHE: "false"
MANUAL_CACHING: "2"

View file

@ -47,6 +47,10 @@ jobs:
md5cache=$(md5sum CMAKE_CACHE_KEY.txt | cut -c -32)
echo ::set-env name=CMAKE_CACHE_KEY::$md5cache
awk -v RS="" -v ORS="\n\n" '/^ ffmpeg:/' snap/snapcraft.yaml > FFMPEG_CACHE_KEY.txt
md5cache=$(md5sum FFMPEG_CACHE_KEY.txt | cut -c -32)
echo ::set-env name=FFMPEG_CACHE_KEY::$md5cache
- name: CMake cache.
id: cache-cmake
uses: actions/cache@v1
@ -58,6 +62,17 @@ jobs:
if: steps.cache-cmake.outputs.cache-hit != 'true'
run: snapcraft build --destructive-mode cmake
- name: FFmpeg cache.
id: cache-ffmpeg
uses: actions/cache@v1
with:
path: parts/ffmpeg
key: ${{ runner.OS }}-ffmpeg-${{ env.CACHE_KEY }}-${{ env.FFMPEG_CACHE_KEY }}
- name: FFmpeg build.
if: steps.cache-ffmpeg.outputs.cache-hit != 'true'
run: snapcraft build --destructive-mode ffmpeg
- name: Kotatogram Desktop snap build.
if: env.ONLY_CACHE == 'false'
run: snapcraft --destructive-mode
@ -80,5 +95,5 @@ jobs:
- name: Remove unneeded directories for cache.
run: |
rm -rf parts/cmake/{build,src,ubuntu}
rm -rf parts/cmake/state/{stage,prime}
rm -rf parts/{cmake,ffmpeg}/{build,src,ubuntu}
rm -rf parts/{cmake,ffmpeg}/state/{stage,prime}

View file

@ -22,6 +22,9 @@ project(Telegram
)
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT Telegram)
get_filename_component(third_party_loc "Telegram/ThirdParty" REALPATH)
get_filename_component(submodules_loc "Telegram" REALPATH)
include(cmake/variables.cmake)
include(cmake/nice_target_sources.cmake)
include(cmake/target_link_static_libraries.cmake)

View file

@ -39,4 +39,4 @@ Full list of features will rewritten later, for now you can use one of `control-
[flatpak]: https://flathub.org/apps/details/io.github.kotatogram
[changelog]: https://github.com/kotatogram/kotatogram-desktop/blob/dev/kotatogram_changes.txt
[preview_image]: https://github.com/kotatogram/kotatogram-desktop/blob/dev/docs/assets/ktg_preview.png "Preview of Kotatogram Desktop"
[preview_image_url]: https://github.com/kotatogram/kotatogram-desktop/blob/dev/docs/assets/ktg_preview.png
[preview_image_url]: https://github.com/kotatogram/kotatogram-desktop/blob/dev/docs/assets/ktg_preview.png

View file

@ -94,6 +94,7 @@ PRIVATE
desktop-app::external_lz4
desktop-app::external_rlottie
desktop-app::external_zlib
desktop-app::external_minizip
desktop-app::external_qt
desktop-app::external_qr_code_generator
desktop-app::external_crash_reports
@ -1219,14 +1220,15 @@ endif()
if (LINUX AND DESKTOP_APP_USE_PACKAGED)
include(GNUInstallDirs)
configure_file("../lib/xdg/kotatogramdesktop.appdata.xml.in" "${CMAKE_CURRENT_BINARY_DIR}/kotatogramdesktop.appdata.xml" @ONLY)
install(TARGETS Telegram RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" BUNDLE DESTINATION "${CMAKE_INSTALL_BINDIR}")
install(FILES "Resources/art/icon16.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/16x16/apps" RENAME "kotatogram.png")
install(FILES "Resources/art/icon32.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/32x32/apps" RENAME "kotatogram.png")
install(FILES "Resources/art/icon48.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps" RENAME "kotatogram.png")
install(FILES "Resources/art/icon64.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/64x64/apps" RENAME "kotatogram.png")
install(FILES "Resources/art/icon128.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/128x128/apps" RENAME "kotatogram.png")
install(FILES "Resources/art/icon256.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/256x256/apps" RENAME "kotatogram.png")
install(FILES "Resources/art/icon512.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/512x512/apps" RENAME "kotatogram.png")
install(FILES "Resources/art/icon16.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/16x16/apps" RENAME "telegram.png")
install(FILES "Resources/art/icon32.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/32x32/apps" RENAME "telegram.png")
install(FILES "Resources/art/icon48.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps" RENAME "telegram.png")
install(FILES "Resources/art/icon64.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/64x64/apps" RENAME "telegram.png")
install(FILES "Resources/art/icon128.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/128x128/apps" RENAME "telegram.png")
install(FILES "Resources/art/icon256.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/256x256/apps" RENAME "telegram.png")
install(FILES "Resources/art/icon512.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/512x512/apps" RENAME "telegram.png")
install(FILES "../lib/xdg/kotatogramdesktop.desktop" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications" RENAME "${TDESKTOP_LAUNCHER_BASENAME}.desktop")
install(FILES "../lib/xdg/kotatogramdesktop.appdata.xml" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/metainfo" RENAME "${TDESKTOP_LAUNCHER_BASENAME}.appdata.xml")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/kotatogramdesktop.appdata.xml" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/metainfo" RENAME "${TDESKTOP_LAUNCHER_BASENAME}.appdata.xml")
endif()

View file

@ -0,0 +1,225 @@
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

@ -2239,6 +2239,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_linux_menu_undo" = "Undo";
"lng_linux_menu_redo" = "Redo";
"lng_linux_menu_tools" = "Tools";
"lng_linux_menu_help" = "Help";
"lng_linux_no_audio_prefs" = "You don't have any audio configuration applications installed.";

View file

@ -9,7 +9,7 @@
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
ProcessorArchitecture="ARCHITECTURE"
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
Version="1.9.19.0" />
Version="1.9.20.0" />
<Properties>
<DisplayName>Telegram Desktop</DisplayName>
<PublisherDisplayName>Telegram FZ-LLC</PublisherDisplayName>

View file

@ -1503,7 +1503,8 @@ void ApiWrap::applyLastParticipantsList(
channel->mgInfo->lastAdmins.clear();
channel->mgInfo->lastRestricted.clear();
channel->mgInfo->lastParticipants.clear();
channel->mgInfo->lastParticipantsStatus = MegagroupInfo::LastParticipantsUpToDate;
channel->mgInfo->lastParticipantsStatus = MegagroupInfo::LastParticipantsUpToDate
| MegagroupInfo::LastParticipantsOnceReceived;
auto botStatus = channel->mgInfo->botStatus;
const auto emptyAdminRights = MTP_chatAdminRights(MTP_flags(0));

View file

@ -206,8 +206,7 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) {
if (_chat) {
maxListSize += (_chat->participants.empty() ? _chat->lastAuthors.size() : _chat->participants.size());
} else if (_channel && _channel->isMegagroup()) {
if (_channel->mgInfo->lastParticipants.empty() || _channel->lastParticipantsCountOutdated()) {
} else {
if (!_channel->lastParticipantsRequestNeeded()) {
maxListSize += _channel->mgInfo->lastParticipants.size();
}
}
@ -274,7 +273,7 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) {
}
} else if (_channel && _channel->isMegagroup()) {
QMultiMap<int32, UserData*> ordered;
if (_channel->mgInfo->lastParticipants.empty() || _channel->lastParticipantsCountOutdated()) {
if (_channel->lastParticipantsRequestNeeded()) {
Auth().api().requestLastParticipants(_channel);
} else {
mrows.reserve(mrows.size() + _channel->mgInfo->lastParticipants.size());

View file

@ -133,27 +133,22 @@ void DownloadDictionaryInBackground(
const auto id = langs[counter];
counter++;
const auto destroyer = [=] {
// This is a temporary workaround.
const auto copyId = id;
const auto copyLangs = langs;
const auto copySession = session;
const auto copyCounter = counter;
BackgroundLoader = nullptr;
BackgroundLoaderChanged.fire(0);
if (DictionaryExists(copyId)) {
auto dicts = copySession->settings().dictionariesEnabled();
if (!ranges::contains(dicts, copyId)) {
dicts.push_back(copyId);
copySession->settings().setDictionariesEnabled(std::move(dicts));
copySession->saveSettingsDelayed();
if (DictionaryExists(id)) {
auto dicts = session->settings().dictionariesEnabled();
if (!ranges::contains(dicts, id)) {
dicts.push_back(id);
session->settings().setDictionariesEnabled(std::move(dicts));
session->saveSettingsDelayed();
}
}
if (copyCounter >= copyLangs.size()) {
if (counter >= langs.size()) {
return;
}
DownloadDictionaryInBackground(copySession, copyCounter, copyLangs);
DownloadDictionaryInBackground(session, counter, langs);
};
if (DictionaryExists(id)) {
destroyer();
@ -194,20 +189,21 @@ DictLoader::DictLoader(
}
void DictLoader::unpack(const QString &path) {
Expects(_destroyCallback);
crl::async([=] {
const auto success = Spellchecker::UnpackDictionary(path, id());
if (success) {
QFile(path).remove();
destroy();
return;
}
crl::on_main(success ? _destroyCallback : [=] { fail(); });
crl::on_main([=] { fail(); });
});
}
void DictLoader::destroy() {
Expects(_destroyCallback);
_destroyCallback();
crl::on_main(_destroyCallback);
}
void DictLoader::fail() {

View file

@ -60,6 +60,7 @@ private:
void unpack(const QString &path) override;
void fail() override;
// Be sure to always call it in the main thread.
Fn<void()> _destroyCallback;
rpl::lifetime _lifetime;

View file

@ -18,33 +18,6 @@ namespace {
std::map<int, const char*> BetaLogs() {
return {
{
1008005,
"\xE2\x80\xA2 Create new themes based on your color "
"and wallpaper choices.\n"
"\xE2\x80\xA2 Share your themes with other users via links.\n"
"\xE2\x80\xA2 Update your theme for all its users "
"when you change something.\n"
},
{
1009000,
"\xE2\x80\xA2 System spell checker on Windows 8+ and macOS 10.12+.\n"
},
{
1009002,
"\xE2\x80\xA2 Videos in chats start playing automatically.\n"
"\xE2\x80\xA2 Resume playback from where you left off "
"when watching long videos.\n"
"\xE2\x80\xA2 Control videos, GIFs and round video messages "
"automatic playback in "
"Settings > Advanced > Automatic media download.\n"
"\xE2\x80\xA2 Spell checker on Linux using Enchant.\n"
},
{
1009010,
"\xE2\x80\xA2 Switch to the Picture-in-Picture mode "
@ -63,12 +36,19 @@ std::map<int, const char*> BetaLogs() {
"\xE2\x80\xA2 Bug fixes and other minor improvements."
},
{
1009017,
"\xE2\x80\xA2 Spell checker on Windows 7.\n"
"\xE2\x80\xA2 Bug fixes and other minor improvements."
},
{
1009020,
"\xE2\x80\xA2 Fix crash in shared links search.\n"
"\xE2\x80\xA2 Fix blurred thumbnails in albums with video files.\n"
"\xE2\x80\xA2 Fix a possible crash in animated stickers rendering."
}
};
};

View file

@ -247,6 +247,7 @@ void Launcher::init() {
prepareSettings();
QApplication::setApplicationName(qsl("KotatogramDesktop"));
QApplication::setApplicationDisplayName(AppName.utf16());
#if defined(Q_OS_LINUX) && QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
QApplication::setDesktopFileName(Platform::GetLauncherFilename());

View file

@ -274,7 +274,7 @@ void Sandbox::socketError(QLocalSocket::LocalSocketError e) {
psCheckLocalSocket(_localServerName);
if (!_localServer.listen(_localServerName)) {
LOG(("Failed to start listening to %1 server, error %2").arg(_localServerName).arg(int(_localServer.serverError())));
LOG(("Failed to start listening to %1 server: %2").arg(_localServerName).arg(_localServer.errorString()));
return App::quit();
}
#endif // !Q_OS_WINRT

View file

@ -341,6 +341,20 @@ bool ChannelData::isGroupAdmin(not_null<UserData*> user) const {
return false;
}
bool ChannelData::lastParticipantsRequestNeeded() const {
if (!mgInfo) {
return false;
} else if (mgInfo->lastParticipantsCount == membersCount()) {
mgInfo->lastParticipantsStatus
&= ~MegagroupInfo::LastParticipantsCountOutdated;
}
return mgInfo->lastParticipants.empty()
|| !(mgInfo->lastParticipantsStatus
& MegagroupInfo::LastParticipantsOnceReceived)
|| (mgInfo->lastParticipantsStatus
& MegagroupInfo::LastParticipantsCountOutdated);
}
QString ChannelData::adminRank(not_null<UserData*> user) const {
if (!isGroupAdmin(user)) {
return QString();

View file

@ -73,6 +73,7 @@ public:
enum LastParticipantsStatus {
LastParticipantsUpToDate = 0x00,
LastParticipantsOnceReceived = 0x01,
LastParticipantsCountOutdated = 0x02,
};
mutable int lastParticipantsStatus = LastParticipantsUpToDate;
@ -219,21 +220,8 @@ public:
void markForbidden();
[[nodiscard]] bool isGroupAdmin(not_null<UserData*> user) const;
[[nodiscard]] bool lastParticipantsRequestNeeded() const;
[[nodiscard]] QString adminRank(not_null<UserData*> user) const;
[[nodiscard]] bool lastParticipantsCountOutdated() const {
if (!mgInfo
|| !(mgInfo->lastParticipantsStatus
& MegagroupInfo::LastParticipantsCountOutdated)) {
return false;
}
if (mgInfo->lastParticipantsCount == membersCount()) {
mgInfo->lastParticipantsStatus
&= ~MegagroupInfo::LastParticipantsCountOutdated;
return false;
}
return true;
}
[[nodiscard]] bool isMegagroup() const {
return flags() & MTPDchannel::Flag::f_megagroup;
}

View file

@ -42,7 +42,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace {
constexpr auto kMemoryForCache = 32 * 1024 * 1024;
// Updated Mar 3, 2020: Increase the size of the memory cache for media, to prevent items still being displayed from being unloaded.
constexpr auto kMemoryForCache = 128 * 1024 * 1024; // was 32, updated to 128
const auto kAnimatedStickerDimensions = QSize(512, 512);
using FilePathResolve = DocumentData::FilePathResolve;

View file

@ -5171,6 +5171,8 @@ int HistoryWidget::countInitialScrollTop() {
}
void HistoryWidget::createUnreadBarIfBelowVisibleArea(int withScrollTop) {
Expects(_history != nullptr);
if (_history->unreadBar()) {
return;
}
@ -5292,7 +5294,7 @@ void HistoryWidget::updateHistoryGeometry(
newScrollTop = countInitialScrollTop();
_historyInited = true;
_scrollToAnimation.stop();
} else if (wasAtBottom && !loadedDown) {
} else if (wasAtBottom && !loadedDown && !_history->unreadBar()) {
newScrollTop = countAutomaticScrollTop();
} else {
newScrollTop = std::min(

View file

@ -280,6 +280,16 @@ bool Element::isUnderCursor() const {
return _delegate->elementUnderCursor(this);
}
bool Element::isLastAndSelfMessage() const {
if (!hasOutLayout()) {
return false;
}
if (const auto last = data()->_history->lastMessage()) {
return last == data();
}
return false;
}
void Element::setPendingResize() {
_flags |= Flag::NeedsResize;
if (_context == Context::History) {

View file

@ -158,6 +158,8 @@ public:
bool pendingResize() const;
bool isUnderCursor() const;
bool isLastAndSelfMessage() const;
bool isAttachedToPrevious() const;
bool isAttachedToNext() const;

View file

@ -896,7 +896,7 @@ void TopBarWidget::updateOnlineDisplay() {
}
} else if (const auto channel = _activeChat.peer()->asChannel()) {
if (channel->isMegagroup() && channel->membersCount() > 0 && channel->membersCount() <= Global::ChatSizeMax()) {
if (channel->mgInfo->lastParticipants.empty() || channel->lastParticipantsCountOutdated()) {
if (channel->lastParticipantsRequestNeeded()) {
session().api().requestLastParticipants(channel);
}
const auto self = session().user();

View file

@ -1180,7 +1180,7 @@ void Gif::validateGroupedCache(
const auto height = geometry.height();
const auto options = Option::Smooth
| Option::RoundedLarge
| (blur ? Option(0) : Option::Blurred)
| (blur ? Option::Blurred : Option(0))
| ((corners & RectPart::TopLeft) ? Option::RoundedTopLeft : Option::None)
| ((corners & RectPart::TopRight) ? Option::RoundedTopRight : Option::None)
| ((corners & RectPart::BottomLeft) ? Option::RoundedBottomLeft : Option::None)
@ -1494,7 +1494,8 @@ bool Gif::dataLoaded() const {
bool Gif::needInfoDisplay() const {
return _parent->data()->isSending()
|| _data->uploading()
|| _parent->isUnderCursor();
|| _parent->isUnderCursor()
|| _parent->isLastAndSelfMessage();
}
bool Gif::needCornerStatusDisplay() const {

View file

@ -464,7 +464,9 @@ bool GroupedMedia::computeNeedBubble() const {
}
bool GroupedMedia::needInfoDisplay() const {
return (_parent->data()->id < 0 || _parent->isUnderCursor());
return (_parent->data()->id < 0
|| _parent->isUnderCursor()
|| _parent->isLastAndSelfMessage());
}
} // namespace HistoryView

View file

@ -435,6 +435,7 @@ bool UnwrappedMedia::needInfoDisplay() const {
return (_parent->data()->id < 0)
|| (_parent->isUnderCursor())
|| (_parent->displayRightAction())
|| (_parent->isLastAndSelfMessage())
|| (_parent->hasOutLayout()
&& !Adaptive::ChatWide()
&& _content->alwaysShowOutTimestamp());

View file

@ -523,7 +523,9 @@ bool Photo::dataLoaded() const {
}
bool Photo::needInfoDisplay() const {
return (_parent->data()->id < 0 || _parent->isUnderCursor());
return (_parent->data()->id < 0
|| _parent->isUnderCursor()
|| _parent->isLastAndSelfMessage());
}
void Photo::validateGroupedCache(

View file

@ -82,7 +82,7 @@ bool PlaybackErrorHappened() {
void EnumeratePlaybackDevices() {
auto deviceNames = QStringList();
auto devices = alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
auto devices = alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER);
Assert(devices != nullptr);
while (*devices != 0) {
auto deviceName8Bit = QByteArray(devices);
@ -92,7 +92,7 @@ void EnumeratePlaybackDevices() {
}
LOG(("Audio Playback Devices: %1").arg(deviceNames.join(';')));
if (auto device = alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER)) {
if (auto device = alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER)) {
LOG(("Audio Playback Default Device: %1").arg(QString::fromLocal8Bit(device)));
} else {
LOG(("Audio Playback Default Device: (null)"));

View file

@ -62,16 +62,12 @@ Instance::Instance() : _inner(new Inner(&_thread)) {
void Instance::check() {
_available = false;
if (auto defaultDevice = alcGetString(0, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER)) {
if (auto device = alcCaptureOpenDevice(defaultDevice, kCaptureFrequency, AL_FORMAT_MONO16, kCaptureFrequency / 5)) {
auto error = ErrorHappened(device);
alcCaptureCloseDevice(device);
_available = !error;
} else {
LOG(("Audio Error: Could not open capture device!"));
}
if (auto device = alcCaptureOpenDevice(nullptr, kCaptureFrequency, AL_FORMAT_MONO16, kCaptureFrequency / 5)) {
auto error = ErrorHappened(device);
alcCaptureCloseDevice(device);
_available = !error;
} else {
LOG(("Audio Error: No capture device found!"));
LOG(("Audio Error: Could not open capture device!"));
}
}
@ -177,9 +173,7 @@ void Instance::Inner::onInit() {
void Instance::Inner::onStart() {
// Start OpenAL Capture
const ALCchar *dName = alcGetString(0, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
DEBUG_LOG(("Audio Info: Capture device name '%1'").arg(dName));
d->device = alcCaptureOpenDevice(dName, kCaptureFrequency, AL_FORMAT_MONO16, kCaptureFrequency / 5);
d->device = alcCaptureOpenDevice(nullptr, kCaptureFrequency, AL_FORMAT_MONO16, kCaptureFrequency / 5);
if (!d->device) {
LOG(("Audio Error: capture device not present!"));
emit error();

View file

@ -7,10 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "mtproto/details/mtproto_dump_to_text.h"
#include "base/zlib_help.h"
#include "scheme-dump_to_text.h"
#include "scheme.h"
#include "zlib.h"
namespace MTP::details {
bool DumpToTextCore(DumpToTextBuffer &to, const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons, uint32 level, mtpPrime vcons) {

File diff suppressed because it is too large Load diff

View file

@ -14,6 +14,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#include "statusnotifieritem.h"
#include <QtCore/QTemporaryFile>
#include <QtDBus/QDBusObjectPath>
#include <dbusmenuexporter.h>
#endif
namespace Platform {
@ -38,13 +40,41 @@ public:
public slots:
void psShowTrayMenu();
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
void onSNIOwnerChanged(
const QString &service,
const QString &oldOwner,
const QString &newOwner);
void psLinuxUndo();
void psLinuxRedo();
void psLinuxCut();
void psLinuxCopy();
void psLinuxPaste();
void psLinuxDelete();
void psLinuxSelectAll();
void psLinuxBold();
void psLinuxItalic();
void psLinuxUnderline();
void psLinuxStrikeOut();
void psLinuxMonospace();
void psLinuxClearFormat();
void onVisibleChanged(bool visible);
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
protected:
void initHook() override;
void unreadCounterChangedHook() override;
void updateGlobalMenuHook() override;
void initTrayMenuHook() override;
bool hasTrayIcon() const override;
void workmodeUpdated(DBIWorkMode mode) override;
void createGlobalMenu() override;
QSystemTrayIcon *trayIcon = nullptr;
QMenu *trayIconMenu = nullptr;
@ -68,9 +98,32 @@ private:
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
StatusNotifierItem *_sniTrayIcon = nullptr;
std::unique_ptr<QTemporaryFile> _trayIconFile = nullptr;
std::unique_ptr<QTemporaryFile> _trayToolTipIconFile = nullptr;
void setSNITrayIcon(const QIcon &icon);
DBusMenuExporter *_mainMenuExporter = nullptr;
QDBusObjectPath _mainMenuPath;
QMenu *psMainMenu = nullptr;
QAction *psLogout = nullptr;
QAction *psUndo = nullptr;
QAction *psRedo = nullptr;
QAction *psCut = nullptr;
QAction *psCopy = nullptr;
QAction *psPaste = nullptr;
QAction *psDelete = nullptr;
QAction *psSelectAll = nullptr;
QAction *psContacts = nullptr;
QAction *psAddContact = nullptr;
QAction *psNewGroup = nullptr;
QAction *psNewChannel = nullptr;
QAction *psBold = nullptr;
QAction *psItalic = nullptr;
QAction *psUnderline = nullptr;
QAction *psStrikeOut = nullptr;
QAction *psMonospace = nullptr;
QAction *psClearFormat = nullptr;
void setSNITrayIcon(int counter, bool muted, bool firstShow = false);
void attachToSNITrayIcon();
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION

View file

@ -7,18 +7,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "platform/linux/notifications_manager_linux.h"
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#include "platform/linux/specific_linux.h"
#include "history/history.h"
#include "lang/lang_keys.h"
#include "mainwindow.h"
#include "facades.h"
#include <QtWidgets/QApplication>
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#include <QtCore/QVersionNumber>
#include <QtDBus/QDBusMessage>
#include <QtDBus/QDBusReply>
#include <QtDBus/QDBusError>
#include <QtDBus/QDBusMetaType>
#endif
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#include <QtWidgets/QApplication>
namespace Platform {
namespace Notifications {
@ -38,50 +40,101 @@ namespace {
constexpr auto kService = "org.freedesktop.Notifications"_cs;
constexpr auto kObjectPath = "/org/freedesktop/Notifications"_cs;
constexpr auto kInterface = kService;
constexpr auto kPropertiesInterface = "org.freedesktop.DBus.Properties"_cs;
std::vector<QString> GetServerInformation(
const std::shared_ptr<QDBusInterface> &notificationInterface) {
bool InhibitedNotSupported = false;
std::vector<QString> ComputeServerInformation() {
std::vector<QString> serverInformation;
const auto serverInformationReply = notificationInterface
->call(qsl("GetServerInformation"));
if (serverInformationReply.type() == QDBusMessage::ReplyMessage) {
for (const auto &arg : serverInformationReply.arguments()) {
if (static_cast<QMetaType::Type>(arg.type())
== QMetaType::QString) {
serverInformation.push_back(arg.toString());
} else {
LOG(("Native notification error: "
"all elements in GetServerInformation "
"should be strings"));
}
}
} else if (serverInformationReply.type() == QDBusMessage::ErrorMessage) {
LOG(("Native notification error: %1")
.arg(serverInformationReply.errorMessage()));
const auto message = QDBusMessage::createMethodCall(
kService.utf16(),
kObjectPath.utf16(),
kInterface.utf16(),
qsl("GetServerInformation"));
const auto reply = QDBusConnection::sessionBus().call(message);
if (reply.type() == QDBusMessage::ReplyMessage) {
ranges::transform(
reply.arguments(),
ranges::back_inserter(serverInformation),
&QVariant::toString
);
} else if (reply.type() == QDBusMessage::ErrorMessage) {
LOG(("Native notification error: %1").arg(reply.errorMessage()));
} else {
LOG(("Native notification error: "
"error while getting information about notification daemon"));
"invalid reply from GetServerInformation"));
}
return serverInformation;
}
QStringList GetCapabilities(
const std::shared_ptr<QDBusInterface> &notificationInterface) {
const QDBusReply<QStringList> capabilitiesReply = notificationInterface
->call(qsl("GetCapabilities"));
std::vector<QString> GetServerInformation() {
static const auto ServerInformation = ComputeServerInformation();
return ServerInformation;
}
if (capabilitiesReply.isValid()) {
return capabilitiesReply.value();
QStringList ComputeCapabilities() {
const auto message = QDBusMessage::createMethodCall(
kService.utf16(),
kObjectPath.utf16(),
kInterface.utf16(),
qsl("GetCapabilities"));
const QDBusReply<QStringList> reply = QDBusConnection::sessionBus().call(
message);
if (reply.isValid()) {
return reply.value();
} else {
LOG(("Native notification error: %1")
.arg(capabilitiesReply.error().message()));
LOG(("Native notification error: %1").arg(reply.error().message()));
}
return {};
}
QStringList GetCapabilities() {
static const auto Capabilities = ComputeCapabilities();
return Capabilities;
}
bool Inhibited() {
auto message = QDBusMessage::createMethodCall(
kService.utf16(),
kObjectPath.utf16(),
kPropertiesInterface.utf16(),
qsl("Get"));
message.setArguments({
qsl("org.freedesktop.Notifications"),
qsl("Inhibited")
});
const QDBusReply<QVariant> reply = QDBusConnection::sessionBus().call(
message);
constexpr auto notSupportedErrors = {
QDBusError::ServiceUnknown,
QDBusError::InvalidArgs,
};
if (reply.isValid()) {
return reply.value().toBool();
} else if (ranges::contains(notSupportedErrors, reply.error().type())) {
InhibitedNotSupported = true;
} else {
if (reply.error().type() == QDBusError::AccessDenied) {
InhibitedNotSupported = true;
}
LOG(("Native notification error: %1").arg(reply.error().message()));
}
return false;
}
QVersionNumber ParseSpecificationVersion(
const std::vector<QString> &serverInformation) {
if (serverInformation.size() >= 4) {
@ -94,10 +147,31 @@ QVersionNumber ParseSpecificationVersion(
return QVersionNumber();
}
QString GetImageKey(const QVersionNumber &specificationVersion) {
if (!specificationVersion.isNull()) {
const auto majorVersion = specificationVersion.majorVersion();
const auto minorVersion = specificationVersion.minorVersion();
if ((majorVersion == 1 && minorVersion >= 2) || majorVersion > 1) {
return qsl("image-data");
} else if (majorVersion == 1 && minorVersion == 1) {
return qsl("image_data");
} else if ((majorVersion == 1 && minorVersion < 1)
|| majorVersion < 1) {
return qsl("icon_data");
} else {
LOG(("Native notification error: unknown specification version"));
}
} else {
LOG(("Native notification error: specification version is null"));
}
return QString();
}
}
NotificationData::NotificationData(
const std::shared_ptr<QDBusInterface> &notificationInterface,
const base::weak_ptr<Manager> &manager,
const QString &title,
const QString &subtitle,
@ -105,12 +179,14 @@ NotificationData::NotificationData(
PeerId peerId,
MsgId msgId,
bool hideReplyButton)
: _notificationInterface(notificationInterface)
: _dbusConnection(QDBusConnection::sessionBus())
, _manager(manager)
, _title(title)
, _imageKey(GetImageKey(ParseSpecificationVersion(
GetServerInformation())))
, _peerId(peerId)
, _msgId(msgId) {
const auto capabilities = GetCapabilities(_notificationInterface);
const auto capabilities = GetCapabilities();
if (capabilities.contains(qsl("body-markup"))) {
_body = subtitle.isEmpty()
@ -127,19 +203,16 @@ NotificationData::NotificationData(
if (capabilities.contains(qsl("actions"))) {
_actions << qsl("default") << QString();
_notificationInterface->connection().connect(
kService.utf16(),
kObjectPath.utf16(),
kInterface.utf16(),
qsl("ActionInvoked"),
this,
SLOT(notificationClicked(uint,QString)));
_actions
<< qsl("mail-mark-read")
<< tr::lng_context_mark_read(tr::now);
if (capabilities.contains(qsl("inline-reply")) && !hideReplyButton) {
_actions << qsl("inline-reply")
_actions
<< qsl("inline-reply")
<< tr::lng_notification_reply(tr::now);
_notificationInterface->connection().connect(
_dbusConnection.connect(
kService.utf16(),
kObjectPath.utf16(),
kInterface.utf16(),
@ -148,9 +221,18 @@ NotificationData::NotificationData(
SLOT(notificationReplied(uint,QString)));
} else {
// icon name according to https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html
_actions << qsl("mail-reply-sender")
_actions
<< qsl("mail-reply-sender")
<< tr::lng_notification_reply(tr::now);
}
_dbusConnection.connect(
kService.utf16(),
kObjectPath.utf16(),
kInterface.utf16(),
qsl("ActionInvoked"),
this,
SLOT(actionInvoked(uint,QString)));
}
if (capabilities.contains(qsl("action-icons"))) {
@ -172,10 +254,9 @@ NotificationData::NotificationData(
}
_hints["category"] = qsl("im.received");
_hints["desktop-entry"] = GetLauncherBasename();
_notificationInterface->connection().connect(
_dbusConnection.connect(
kService.utf16(),
kObjectPath.utf16(),
kInterface.utf16(),
@ -184,65 +265,56 @@ NotificationData::NotificationData(
SLOT(notificationClosed(uint)));
}
bool NotificationData::show(bool hideNameAndPhoto) {
const QDBusReply<uint> notifyReply = _notificationInterface->call(
qsl("Notify"),
bool NotificationData::show() {
const auto iconName = _imageKey.isEmpty() || !_hints.contains(_imageKey)
? GetIconName()
: QString();
auto message = QDBusMessage::createMethodCall(
kService.utf16(),
kObjectPath.utf16(),
kInterface.utf16(),
qsl("Notify"));
message.setArguments({
AppName.utf16(),
uint(0),
hideNameAndPhoto
? qsl("telegram")
: QString(),
iconName,
_title,
_body,
_actions,
_hints,
-1);
-1
});
if (notifyReply.isValid()) {
_notificationId = notifyReply.value();
const QDBusReply<uint> reply = _dbusConnection.call(
message);
if (reply.isValid()) {
_notificationId = reply.value();
} else {
LOG(("Native notification error: %1")
.arg(notifyReply.error().message()));
LOG(("Native notification error: %1").arg(reply.error().message()));
}
return notifyReply.isValid();
return reply.isValid();
}
bool NotificationData::close() {
const QDBusReply<void> closeReply = _notificationInterface
->call(qsl("CloseNotification"), _notificationId);
void NotificationData::close() {
auto message = QDBusMessage::createMethodCall(
kService.utf16(),
kObjectPath.utf16(),
kInterface.utf16(),
qsl("CloseNotification"));
if (!closeReply.isValid()) {
LOG(("Native notification error: %1")
.arg(closeReply.error().message()));
}
message.setArguments({
_notificationId
});
return closeReply.isValid();
_dbusConnection.send(message);
}
void NotificationData::setImage(const QString &imagePath) {
const auto specificationVersion = ParseSpecificationVersion(
GetServerInformation(_notificationInterface));
QString imageKey;
if (!specificationVersion.isNull()) {
const auto majorVersion = specificationVersion.majorVersion();
const auto minorVersion = specificationVersion.minorVersion();
if ((majorVersion == 1 && minorVersion >= 2) || majorVersion > 1) {
imageKey = qsl("image-data");
} else if (majorVersion == 1 && minorVersion == 1) {
imageKey = qsl("image_data");
} else if ((majorVersion == 1 && minorVersion < 1)
|| majorVersion < 1) {
imageKey = qsl("icon_data");
} else {
LOG(("Native notification error: unknown specification version"));
return;
}
} else {
LOG(("Native notification error: specification version is null"));
if (_imageKey.isEmpty()) {
return;
}
@ -253,20 +325,21 @@ void NotificationData::setImage(const QString &imagePath) {
(const char*)image.constBits(),
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
image.byteCount());
#else
#else // Qt < 5.10.0
image.sizeInBytes());
#endif
#endif // Qt >= 5.10.0
ImageData imageData;
imageData.width = image.width();
imageData.height = image.height();
imageData.rowStride = image.bytesPerLine();
imageData.hasAlpha = true;
imageData.bitsPerSample = 8;
imageData.channels = 4;
imageData.data = imageBytes;
const auto imageData = ImageData{
image.width(),
image.height(),
image.bytesPerLine(),
true,
8,
4,
imageBytes
};
_hints[imageKey] = QVariant::fromValue(imageData);
_hints[_imageKey] = QVariant::fromValue(imageData);
}
void NotificationData::notificationClosed(uint id) {
@ -278,19 +351,23 @@ void NotificationData::notificationClosed(uint id) {
}
}
void NotificationData::notificationClicked(uint id, const QString &actionId) {
void NotificationData::actionInvoked(uint id, const QString &actionName) {
if (id != _notificationId) {
return;
}
if (actionId != qsl("default") && actionId != qsl("mail-reply-sender")) {
return;
if (actionName == qsl("default")
|| actionName == qsl("mail-reply-sender")) {
const auto manager = _manager;
crl::on_main(manager, [=] {
manager->notificationActivated(_peerId, _msgId);
});
} else if (actionName == qsl("mail-mark-read")) {
const auto manager = _manager;
crl::on_main(manager, [=] {
manager->notificationReplied(_peerId, _msgId, {});
});
}
const auto manager = _manager;
crl::on_main(manager, [=] {
manager->notificationActivated(_peerId, _msgId);
});
}
void NotificationData::notificationReplied(uint id, const QString &text) {
@ -306,7 +383,8 @@ QDBusArgument &operator<<(
QDBusArgument &argument,
const NotificationData::ImageData &imageData) {
argument.beginStructure();
argument << imageData.width
argument
<< imageData.width
<< imageData.height
<< imageData.rowStride
<< imageData.hasAlpha
@ -321,7 +399,8 @@ const QDBusArgument &operator>>(
const QDBusArgument &argument,
NotificationData::ImageData &imageData) {
argument.beginStructure();
argument >> imageData.width
argument
>> imageData.width
>> imageData.height
>> imageData.rowStride
>> imageData.hasAlpha
@ -331,20 +410,39 @@ const QDBusArgument &operator>>(
argument.endStructure();
return argument;
}
#endif
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
bool SkipAudio() {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
if (Supported()
&& GetCapabilities().contains(qsl("inhibitions"))
&& !InhibitedNotSupported) {
return Inhibited();
}
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
return false;
}
bool SkipToast() {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
if (Supported()
&& GetCapabilities().contains(qsl("inhibitions"))
&& !InhibitedNotSupported) {
return Inhibited();
}
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
return false;
}
bool Supported() {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
static const auto Available = QDBusInterface(
kService.utf16(),
kObjectPath.utf16(),
kInterface.utf16()
).isValid();
static const auto Available = !GetServerInformation().empty();
return Available;
#else
#else // !TDESKTOP_DISABLE_DBUS_INTEGRATION
return false;
#endif
#endif // TDESKTOP_DISABLE_DBUS_INTEGRATION
}
std::unique_ptr<Window::Notifications::Manager> Create(
@ -353,34 +451,36 @@ std::unique_ptr<Window::Notifications::Manager> Create(
if (Global::NativeNotifications() && Supported()) {
return std::make_unique<Manager>(system);
}
#endif
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
return nullptr;
}
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
Manager::Private::Private(Manager *manager, Type type)
Manager::Private::Private(not_null<Manager*> manager, Type type)
: _cachedUserpics(type)
, _manager(manager)
, _notificationInterface(
std::make_shared<QDBusInterface>(
kService.utf16(),
kObjectPath.utf16(),
kInterface.utf16())) {
, _manager(manager) {
qDBusRegisterMetaType<NotificationData::ImageData>();
const auto specificationVersion = ParseSpecificationVersion(
GetServerInformation(_notificationInterface));
const auto serverInformation = GetServerInformation();
const auto capabilities = GetCapabilities();
const auto capabilities = GetCapabilities(_notificationInterface);
if (!serverInformation.empty()) {
LOG(("Notification daemon product name: %1")
.arg(serverInformation[0]));
LOG(("Notification daemon vendor name: %1")
.arg(serverInformation[1]));
LOG(("Notification daemon version: %1")
.arg(serverInformation[2]));
if (!specificationVersion.isNull()) {
LOG(("Notification daemon specification version: %1")
.arg(specificationVersion.toString()));
.arg(serverInformation[3]));
}
if (!capabilities.empty()) {
const auto capabilitiesString = capabilities.join(", ");
LOG(("Notification daemon capabilities: %1").arg(capabilitiesString));
if (!capabilities.isEmpty()) {
LOG(("Notification daemon capabilities: %1")
.arg(capabilities.join(", ")));
}
}
@ -393,7 +493,6 @@ void Manager::Private::showNotification(
bool hideNameAndPhoto,
bool hideReplyButton) {
auto notification = std::make_shared<NotificationData>(
_notificationInterface,
_manager,
title,
subtitle,
@ -421,7 +520,7 @@ void Manager::Private::showNotification(
i = _notifications.insert(peer->id, QMap<MsgId, Notification>());
}
_notifications[peer->id].insert(msgId, notification);
if (!notification->show(hideNameAndPhoto)) {
if (!notification->show()) {
i = _notifications.find(peer->id);
if (i != _notifications.cend()) {
i->remove(msgId);
@ -465,7 +564,7 @@ Manager::Private::~Private() {
clearAll();
}
Manager::Manager(Window::Notifications::System *system)
Manager::Manager(not_null<Window::Notifications::System*> system)
: NativeManager(system)
, _private(std::make_unique<Private>(this, Private::Type::Rounded)) {
}
@ -501,7 +600,7 @@ void Manager::doClearAllFast() {
void Manager::doClearFromHistory(not_null<History*> history) {
_private->clearFromHistory(history);
}
#endif
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
} // namespace Notifications
} // namespace Platform

View file

@ -12,28 +12,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/weak_ptr.h"
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusArgument>
#endif
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
namespace Platform {
namespace Notifications {
inline bool SkipAudio() {
return false;
}
inline bool SkipToast() {
return false;
}
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
class NotificationData : public QObject {
Q_OBJECT
public:
NotificationData(
const std::shared_ptr<QDBusInterface> &notificationInterface,
const base::weak_ptr<Manager> &manager,
const QString &title,
const QString &subtitle,
@ -47,8 +38,8 @@ public:
NotificationData(NotificationData &&other) = delete;
NotificationData &operator=(NotificationData &&other) = delete;
bool show(bool hideNameAndPhoto);
bool close();
bool show();
void close();
void setImage(const QString &imagePath);
struct ImageData {
@ -59,13 +50,14 @@ public:
};
private:
std::shared_ptr<QDBusInterface> _notificationInterface;
QDBusConnection _dbusConnection;
base::weak_ptr<Manager> _manager;
QString _title;
QString _body;
QStringList _actions;
QVariantMap _hints;
QString _imageKey;
uint _notificationId;
PeerId _peerId;
@ -73,7 +65,7 @@ private:
private slots:
void notificationClosed(uint id);
void notificationClicked(uint id, const QString &actionId);
void actionInvoked(uint id, const QString &actionName);
void notificationReplied(uint id, const QString &text);
};
@ -91,7 +83,7 @@ class Manager
: public Window::Notifications::NativeManager
, public base::has_weak_ptr {
public:
Manager(Window::Notifications::System *system);
Manager(not_null<Window::Notifications::System*> system);
void clearNotification(PeerId peerId, MsgId msgId);
~Manager();
@ -116,7 +108,7 @@ private:
class Manager::Private {
public:
using Type = Window::Notifications::CachedUserpics::Type;
explicit Private(Manager *manager, Type type);
explicit Private(not_null<Manager*> manager, Type type);
void showNotification(
not_null<PeerData*> peer,
@ -138,13 +130,12 @@ private:
Window::Notifications::CachedUserpics _cachedUserpics;
base::weak_ptr<Manager> _manager;
std::shared_ptr<QDBusInterface> _notificationInterface;
};
#endif
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
} // namespace Notifications
} // namespace Platform
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
Q_DECLARE_METATYPE(Platform::Notifications::NotificationData::ImageData)
#endif
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION

View file

@ -26,7 +26,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
#include <QtDBus/QDBusInterface>
#endif
#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusMessage>
#include <QtDBus/QDBusReply>
#include <QtDBus/QDBusError>
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
#include <sys/stat.h>
#include <sys/types.h>
@ -44,9 +48,10 @@ namespace {
constexpr auto kDesktopFile = ":/misc/kotatogramdesktop.desktop"_cs;
constexpr auto kSnapLauncherDir = "/var/lib/snapd/desktop/applications/"_cs;
constexpr auto kIconName = "telegram"_cs;
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
void SandboxAutostart(bool autostart) {
void SandboxAutostart(bool autostart, bool silent = false) {
QVariantMap options;
options["reason"] = tr::lng_settings_auto_start(tr::now);
options["autostart"] = autostart;
@ -56,20 +61,29 @@ void SandboxAutostart(bool autostart) {
});
options["dbus-activatable"] = false;
const auto requestBackgroundReply = QDBusInterface(
auto message = QDBusMessage::createMethodCall(
qsl("org.freedesktop.portal.Desktop"),
qsl("/org/freedesktop/portal/desktop"),
qsl("org.freedesktop.portal.Background")
).call(qsl("RequestBackground"), QString(), options);
qsl("org.freedesktop.portal.Background"),
qsl("RequestBackground"));
if (requestBackgroundReply.type() == QDBusMessage::ErrorMessage) {
LOG(("Flatpak autostart error: %1")
.arg(requestBackgroundReply.errorMessage()));
} else if (requestBackgroundReply.type() != QDBusMessage::ReplyMessage) {
LOG(("Flatpak autostart error: invalid reply"));
message.setArguments({
QString(),
options
});
if (silent) {
QDBusConnection::sessionBus().send(message);
} else {
const QDBusReply<void> reply = QDBusConnection::sessionBus().call(
message);
if (!reply.isValid()) {
LOG(("Flatpak autostart error: %1").arg(reply.error().message()));
}
}
}
#endif
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
bool RunShellCommand(const QByteArray &command) {
auto result = system(command.constData());
@ -120,7 +134,10 @@ void FallbackFontConfig() {
#endif // TDESKTOP_USE_FONT_CONFIG_FALLBACK
}
bool GenerateDesktopFile(const QString &targetPath, const QString &args) {
bool GenerateDesktopFile(
const QString &targetPath,
const QString &args,
bool silent = false) {
DEBUG_LOG(("App Info: placing .desktop file to %1").arg(targetPath));
if (!QDir(targetPath).exists()) QDir().mkpath(targetPath);
@ -142,7 +159,9 @@ bool GenerateDesktopFile(const QString &targetPath, const QString &args) {
fileText = s.readAll();
source.close();
} else {
LOG(("App Error: Could not open '%1' for read").arg(sourceFile));
if (!silent) {
LOG(("App Error: Could not open '%1' for read").arg(sourceFile));
}
return false;
}
@ -150,23 +169,28 @@ bool GenerateDesktopFile(const QString &targetPath, const QString &args) {
if (target.open(QIODevice::WriteOnly)) {
#ifdef DESKTOP_APP_USE_PACKAGED
fileText = fileText.replace(
QRegularExpression(qsl("^Exec=(.*) -- %u$"),
QRegularExpression(
qsl("^Exec=(.*) -- %u$"),
QRegularExpression::MultilineOption),
qsl("Exec=\\1")
+ (args.isEmpty() ? QString() : ' ' + args));
#else
#else // DESKTOP_APP_USE_PACKAGED
fileText = fileText.replace(
QRegularExpression(qsl("^TryExec=.*$"),
QRegularExpression(
qsl("^TryExec=.*$"),
QRegularExpression::MultilineOption),
qsl("TryExec=")
+ EscapeShell(QFile::encodeName(cExeDir() + cExeName())));
+ QFile::encodeName(cExeDir() + cExeName())
.replace('\\', qsl("\\\\")));
fileText = fileText.replace(
QRegularExpression(qsl("^Exec=.*$"),
QRegularExpression(
qsl("^Exec=.*$"),
QRegularExpression::MultilineOption),
qsl("Exec=")
+ EscapeShell(QFile::encodeName(cExeDir() + cExeName()))
.replace('\\', qsl("\\\\"))
+ (args.isEmpty() ? QString() : ' ' + args));
#endif
#endif // !DESKTOP_APP_USE_PACKAGED
target.write(fileText.toUtf8());
target.close();
@ -175,7 +199,9 @@ bool GenerateDesktopFile(const QString &targetPath, const QString &args) {
return true;
} else {
LOG(("App Error: Could not open '%1' for write").arg(targetFile));
if (!silent) {
LOG(("App Error: Could not open '%1' for write").arg(targetFile));
}
return false;
}
}
@ -189,9 +215,7 @@ void SetApplicationIcon(const QIcon &icon) {
}
bool InSandbox() {
static const auto Sandbox = QFileInfo::exists(
QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation)
+ qsl("/flatpak-info"));
static const auto Sandbox = QFileInfo::exists(qsl("/.flatpak-info"));
return Sandbox;
}
@ -208,12 +232,18 @@ bool IsXDGDesktopPortalPresent() {
"org.freedesktop.portal.Desktop",
"/org/freedesktop/portal/desktop").isValid();
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
return XDGDesktopPortalPresent;
}
bool UseXDGDesktopPortal() {
static const auto UsePortal = qEnvironmentVariableIsSet("TDESKTOP_USE_PORTAL")
&& IsXDGDesktopPortalPresent();
static const auto UsePortal = [&] {
const auto envVar = qEnvironmentVariableIsSet("TDESKTOP_USE_PORTAL");
const auto portalPresent = IsXDGDesktopPortalPresent();
return envVar && portalPresent;
}();
return UsePortal;
}
@ -309,7 +339,6 @@ QString GetLauncherBasename() {
return possibleBasenames[0];
}();
LOG(("Launcher filename is %1.desktop").arg(LauncherBasename));
return LauncherBasename;
}
@ -319,6 +348,55 @@ QString GetLauncherFilename() {
return LauncherFilename;
}
QString GetIconName() {
static const auto IconName = InSandbox()
? GetLauncherBasename()
: kIconName.utf16();
return IconName;
}
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
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
static auto NotSupported = false;
if (NotSupported) {
return std::nullopt;
}
static const auto message = QDBusMessage::createMethodCall(
qsl("org.freedesktop.ScreenSaver"),
qsl("/org/freedesktop/ScreenSaver"),
qsl("org.freedesktop.ScreenSaver"),
qsl("GetSessionIdleTime"));
const QDBusReply<uint> reply = QDBusConnection::sessionBus().call(
message);
constexpr auto notSupportedErrors = {
QDBusError::ServiceUnknown,
QDBusError::NotSupported,
};
if (reply.isValid()) {
return (crl::now() - static_cast<crl::time>(reply.value()));
} else if (ranges::contains(notSupportedErrors, reply.error().type())) {
NotSupported = true;
} else {
if (reply.error().type() == QDBusError::AccessDenied) {
NotSupported = true;
}
LOG(("Unable to get last user input time: %1: %2")
.arg(reply.error().name())
.arg(reply.error().message()));
}
#endif // !TDESKTOP_DISABLE_DBUS_INTEGRATION
return std::nullopt;
}
} // namespace Platform
namespace {
@ -395,15 +473,18 @@ QString getHomeDir() {
QString psAppDataPath() {
// We should not use ~/.TelegramDesktop, since it's a fork.
// auto home = getHomeDir();
// if (!home.isEmpty()) {
// auto oldPath = home + qsl(".TelegramDesktop/");
// auto oldSettingsBase = oldPath + qsl("tdata/settings");
// if (QFile(oldSettingsBase + '0').exists() || QFile(oldSettingsBase + '1').exists()) {
// return oldPath;
// }
// }
/*
auto home = getHomeDir();
if (!home.isEmpty()) {
auto oldPath = home + qsl(".TelegramDesktop/");
auto oldSettingsBase = oldPath + qsl("tdata/settings");
if (QFile(oldSettingsBase + '0').exists()
|| QFile(oldSettingsBase + '1').exists()
|| QFile(oldSettingsBase + 's').exists()) {
return oldPath;
}
}
*/
return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + '/';
}
@ -432,8 +513,12 @@ int psFixPrevious() {
namespace Platform {
void start() {
LOG(("Launcher filename: %1").arg(GetLauncherFilename()));
FallbackFontConfig();
qputenv("PULSE_PROP_application.name", AppName.utf8());
qputenv("PULSE_PROP_application.icon_name", GetIconName().toLatin1());
#ifdef TDESKTOP_FORCE_GTK_FILE_DIALOG
LOG(("Checking for XDG Desktop Portal..."));
// this can give us a chance to use a proper file dialog for current session
@ -454,24 +539,29 @@ void start() {
void finish() {
}
void RegisterCustomScheme() {
void RegisterCustomScheme(bool force) {
#ifndef TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME
auto home = getHomeDir();
if (home.isEmpty() || cAlphaVersion() || cExeName().isEmpty())
return; // don't update desktop file for alpha version
if (Core::UpdaterDisabled())
const auto home = getHomeDir();
if (home.isEmpty() || cExeName().isEmpty())
return;
static const auto disabledByEnv = qEnvironmentVariableIsSet(
"TDESKTOP_DISABLE_DESKTOP_FILE_GENERATION");
// don't update desktop file for alpha version or if updater is disabled
if ((cAlphaVersion() || Core::UpdaterDisabled() || disabledByEnv)
&& !force)
return;
const auto applicationsPath = QStandardPaths::writableLocation(
QStandardPaths::ApplicationsLocation) + '/';
#ifndef TDESKTOP_DISABLE_DESKTOP_FILE_GENERATION
GenerateDesktopFile(applicationsPath, qsl("-- %u"));
const auto icons =
QStandardPaths::writableLocation(
QStandardPaths::GenericDataLocation)
+ qsl("/icons/");
+ qsl("/icons/");
if (!QDir(icons).exists()) QDir().mkpath(icons);
@ -485,10 +575,9 @@ void RegisterCustomScheme() {
}
if (!iconExists) {
if (QFile(qsl(":/gui/art/logo_256.png")).copy(icon)) {
DEBUG_LOG(("App Info: Icon copied to 'tdata'"));
DEBUG_LOG(("App Info: Icon copied to '%1'").arg(icon));
}
}
#endif // !TDESKTOP_DISABLE_DESKTOP_FILE_GENERATION
RunShellCommand("update-desktop-database "
+ EscapeShell(QFile::encodeName(applicationsPath)));
@ -559,14 +648,14 @@ bool psShowOpenWithMenu(int x, int y, const QString &file) {
}
void psAutoStart(bool start, bool silent) {
auto home = getHomeDir();
if (home.isEmpty() || cAlphaVersion() || cExeName().isEmpty())
const auto home = getHomeDir();
if (home.isEmpty() || cExeName().isEmpty())
return;
if (InSandbox()) {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
SandboxAutostart(start);
#endif
SandboxAutostart(start, silent);
#endif // !DESKTOP_APP_USE_PACKAGED
} else {
const auto autostart = [&] {
if (InSnap()) {
@ -578,12 +667,12 @@ void psAutoStart(bool start, bool silent) {
} else {
return QStandardPaths::writableLocation(
QStandardPaths::GenericConfigLocation)
+ qsl("/autostart/");
+ qsl("/autostart/");
}
}();
if (start) {
GenerateDesktopFile(autostart, qsl("-autostart"));
GenerateDesktopFile(autostart, qsl("-autostart"), silent);
} else {
QFile::remove(autostart + GetLauncherFilename());
}

View file

@ -35,9 +35,7 @@ QString SingleInstanceLocalServerName(const QString &hash);
QString GetLauncherBasename();
QString GetLauncherFilename();
inline std::optional<crl::time> LastUserInputTime() {
return std::nullopt;
}
QString GetIconName();
inline void IgnoreApplicationActivationRightNow() {
}

View file

@ -481,6 +481,8 @@ void AppendEmojiPacks(std::vector<PickerScrubberItem> &to) {
@implementation PinnedDialogButton {
rpl::lifetime _lifetime;
rpl::lifetime _peerChangedLifetime;
base::has_weak_ptr _guard;
bool isWaitingUserpicLoad;
}
@ -518,7 +520,7 @@ void AppendEmojiPacks(std::vector<PickerScrubberItem> &to) {
) | rpl::filter([](const Window::Theme::BackgroundUpdate &update) {
return update.paletteChanged();
}) | rpl::start_with_next([=] {
crl::on_main([=] {
crl::on_main(&_guard, [=] {
if (_number <= kSavedMessagesId || UseEmptyUserpic(_peer)) {
[self updateUserpic];
} else if (_peer

View file

@ -136,7 +136,7 @@ void RemoveQuarantine(const QString &path) {
removexattr(local.data(), kQuarantineAttribute, 0);
}
void RegisterCustomScheme() {
void RegisterCustomScheme(bool force) {
#ifndef TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME
OSStatus result = LSSetDefaultHandlerForURLScheme(CFSTR("tg"), (CFStringRef)[[NSBundle mainBundle] bundleIdentifier]);
DEBUG_LOG(("App Info: set default handler for 'tg' scheme result: %1").arg(result));

View file

@ -28,7 +28,7 @@ enum class SystemSettingsType {
void SetWatchingMediaKeys(bool watching);
void SetApplicationIcon(const QIcon &icon);
void RegisterCustomScheme();
void RegisterCustomScheme(bool force = false);
PermissionStatus GetPermissionStatus(PermissionType type);
void RequestPermission(PermissionType type, Fn<void(PermissionStatus)> resultCallback);
void OpenSystemSettingsForPermission(PermissionType type);

View file

@ -404,7 +404,7 @@ namespace {
namespace Platform {
void RegisterCustomScheme() {
void RegisterCustomScheme(bool force) {
if (cExeName().isEmpty()) {
return;
}

View file

@ -192,7 +192,7 @@ void GroupMembersWidget::refreshMembers() {
fillChatMembers(chat);
} else if (const auto megagroup = peer()->asMegagroup()) {
auto &megagroupInfo = megagroup->mgInfo;
if (megagroupInfo->lastParticipants.empty() || megagroup->lastParticipantsCountOutdated()) {
if (megagroup->lastParticipantsRequestNeeded()) {
Auth().api().requestLastParticipants(megagroup);
}
fillMegagroupMembers(megagroup);

View file

@ -112,10 +112,12 @@ auto GenerateCodes() {
}
});
});
#ifndef TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME
codes.emplace(qsl("registertg"), [](::Main::Session *session) {
Platform::RegisterCustomScheme();
Platform::RegisterCustomScheme(true);
Ui::Toast::Show("Forced custom scheme register.");
});
#endif // !TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME
codes.emplace(qsl("export"), [](::Main::Session *session) {
session->data().startExport();
});

View file

@ -3167,7 +3167,7 @@ void writeFileLocation(MediaKey location, const FileLocation &local) {
return;
}
if (i.value().first != location) {
for (FileLocations::iterator j = _fileLocations.find(i.value().first), e = _fileLocations.end(); (j != e) && (j.key() == i.value().first);) {
for (FileLocations::iterator j = _fileLocations.find(i.value().first), e = _fileLocations.end(); (j != e) && (j.key() == i.value().first); ++j) {
if (j.value() == i.value().second) {
_fileLocations.erase(j);
break;
@ -3682,7 +3682,21 @@ void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr,
// Read orders of installed and featured stickers.
if (outOrder) {
stickers.stream >> *outOrder;
auto outOrderCount = quint32();
stickers.stream >> outOrderCount;
if (!_checkStreamStatus(stickers.stream) || outOrderCount > 1000) {
return failed();
}
outOrder->reserve(outOrderCount);
for (auto i = 0; i != outOrderCount; ++i) {
auto value = uint64();
stickers.stream >> value;
if (!_checkStreamStatus(stickers.stream)) {
outOrder->clear();
return failed();
}
outOrder->push_back(value);
}
}
if (!_checkStreamStatus(stickers.stream)) {
return failed();

View file

@ -117,9 +117,9 @@ QIcon CreateOfficialIcon(Main::Account *account) {
QIcon CreateIcon(Main::Account *account) {
auto result = CreateOfficialIcon(account);
if (Platform::IsLinux()) {
return QIcon::fromTheme("kotatogram", result);
}
#ifdef Q_OS_LINUX
return QIcon::fromTheme(Platform::GetIconName(), result);
#endif
return result;
}

View file

@ -1,7 +1,7 @@
AppVersion 1009019
AppVersion 1009020
AppVersionStrMajor 1.9
AppVersionStrSmall 1.9.19
AppVersionStr 1.9.19
AppVersionStrSmall 1.9.20
AppVersionStr 1.9.20
BetaChannel 1
AlphaVersion 0
AppVersionOriginal 1.9.19.beta
AppVersionOriginal 1.9.20.beta

View file

@ -7,8 +7,6 @@
option(TDESKTOP_FORCE_GTK_FILE_DIALOG "Force using GTK file dialog (Linux only)." OFF)
option(TDESKTOP_DISABLE_REGISTER_CUSTOM_SCHEME "Disable automatic 'tg://' URL scheme handler registration." ${DESKTOP_APP_USE_PACKAGED})
option(TDESKTOP_DISABLE_NETWORK_PROXY "Disable all code for working through Socks5 or MTProxy." OFF)
option(TDESKTOP_DISABLE_DESKTOP_FILE_GENERATION "Disable automatic '.desktop' file generation (Linux only)." ${DESKTOP_APP_USE_PACKAGED})
option(TDESKTOP_DISABLE_GTK_INTEGRATION "Disable all code for GTK integration (Linux only)." ON)
option(TDESKTOP_USE_PACKAGED_TGVOIP "Find libtgvoip using CMake instead of bundled one." ${DESKTOP_APP_USE_PACKAGED})
option(TDESKTOP_API_TEST "Use test API credentials." OFF)
set(TDESKTOP_API_ID "0" CACHE STRING "Provide 'api_id' for the Telegram API access.")
@ -43,12 +41,12 @@ if (TDESKTOP_API_ID STREQUAL "0" OR TDESKTOP_API_HASH STREQUAL "")
" ")
endif()
if (NOT DESKTOP_APP_SPECIAL_TARGET STREQUAL "")
if (NOT DESKTOP_APP_USE_PACKAGED)
set(TDESKTOP_FORCE_GTK_FILE_DIALOG ON)
endif()
if (TDESKTOP_FORCE_GTK_FILE_DIALOG)
set(TDESKTOP_DISABLE_GTK_INTEGRATION OFF)
if (NOT TDESKTOP_FORCE_GTK_FILE_DIALOG)
set(TDESKTOP_DISABLE_GTK_INTEGRATION ON)
endif()
if (DESKTOP_APP_DISABLE_SPELLCHECK)
@ -77,10 +75,6 @@ if (TDESKTOP_DISABLE_NETWORK_PROXY)
target_compile_definitions(Telegram PRIVATE TDESKTOP_DISABLE_NETWORK_PROXY)
endif()
if (TDESKTOP_DISABLE_DESKTOP_FILE_GENERATION)
target_compile_definitions(Telegram PRIVATE TDESKTOP_DISABLE_DESKTOP_FILE_GENERATION)
endif()
if (TDESKTOP_DISABLE_GTK_INTEGRATION)
target_compile_definitions(Telegram PRIVATE TDESKTOP_DISABLE_GTK_INTEGRATION)
endif()

@ -1 +1 @@
Subproject commit 17b6a6d53252b3e3ff02b113e352c152bd697896
Subproject commit 0f6c9f4acbdc2412a1a941b4ee96b150589b8369

@ -1 +1 @@
Subproject commit dbb92ddbef82988d426ef7a0ffa40a698cdc3fd3
Subproject commit 25f44d99915101e7a832cb38bd9b2cee47508c94

View file

@ -1,3 +1,9 @@
1.9.20 beta (14.03.20)
- Fix crash in shared links search.
- Fix blurred thumbnails in albums with video files.
- Fix a possible crash in animated stickers rendering.
1.9.19 beta (25.02.20)
- Bug fixes and other minor improvements.

2
cmake

@ -1 +1 @@
Subproject commit 81e27ccc0e7bf27405569ce98582860dfc9ea9bb
Subproject commit 9280064cc8a5e8f8acc4cdda3a6a905379d3df0d

View file

@ -1,4 +1,4 @@
## Build instructions for GYP/CMake under Ubuntu 14.04
## Build instructions for CMake under Ubuntu 14.04
### Prepare folder
@ -17,7 +17,7 @@ You will need GCC 8 installed. To install them and all the required dependencies
libgtk2.0-dev libice-dev libsm-dev libicu-dev libdrm-dev dh-autoreconf \
autoconf automake build-essential libxml2-dev libass-dev libfreetype6-dev \
libgpac-dev libsdl1.2-dev libtheora-dev libtool libva-dev libvdpau-dev \
libvorbis-dev libenchant-dev libxcb1-dev libxcb-image0-dev libxcb-shm0-dev \
libvorbis-dev libxcb1-dev libxcb-image0-dev libxcb-shm0-dev \
libxcb-xfixes0-dev libxcb-keysyms1-dev libxcb-icccm4-dev libatspi2.0-dev \
libxcb-render-util0-dev libxcb-util0-dev libxcb-xkb-dev libxrender-dev \
libasound-dev libpulse-dev libxcb-sync0-dev libxcb-randr0-dev libegl1-mesa-dev \
@ -198,7 +198,7 @@ Go to ***BuildPath*** and run
git clone git://repo.or.cz/openal-soft.git
cd openal-soft
git checkout openal-soft-1.19.1
git checkout openal-soft-1.20.1
cd build
if [ `uname -p` == "i686" ]; then
cmake -D LIBTYPE:STRING=STATIC -D ALSOFT_UTILS:BOOL=OFF ..
@ -214,7 +214,7 @@ Go to ***BuildPath*** and run
git checkout OpenSSL_1_1_1-stable
./config --prefix=/usr/local/desktop-app/openssl-1.1.1
make $MAKE_THREADS_CNT
sudo make install
sudo make install_sw
cd ..
git clone https://github.com/xkbcommon/libxkbcommon.git

View file

@ -18,7 +18,6 @@ You will require **api_id** and **api_hash** to access the Telegram API servers.
## Install third party software
Strawberry
* Download **Strawberry Perl** installer from [http://strawberryperl.com/](http://strawberryperl.com/) and install to ***BuildPath*\\ThirdParty\\Strawberry**
* Download **NASM** installer from [http://www.nasm.us](http://www.nasm.us) and install to ***BuildPath*\\ThirdParty\\NASM**
* Download **Yasm** executable from [http://yasm.tortall.net/Download.html](http://yasm.tortall.net/Download.html), rename to *yasm.exe* and put to ***BuildPath*\\ThirdParty\\yasm**

View file

@ -30,7 +30,7 @@ By git in Terminal go to **/home/user/TBuild** and run
Install dev libraries
sudo apt-get install libexif-dev liblzma-dev libz-dev libssl-dev libappindicator-dev libunity-dev libenchant-dev
sudo apt-get install libexif-dev liblzma-dev libz-dev libssl-dev libappindicator-dev libunity-dev
#### zlib 1.2.8

View file

@ -1,4 +1,4 @@
## Build instructions for Xcode 10.1
## Build instructions for Xcode 11
### Prepare folder
@ -8,18 +8,14 @@ Choose a folder for the future build, for example **/Users/user/TBuild**. It wil
You will require **api_id** and **api_hash** to access the Telegram API servers. To learn how to obtain them [click here][api_credentials].
### Download libraries
Download [**xz-5.0.5**](http://tukaani.org/xz/xz-5.0.5.tar.gz) and unpack to ***BuildPath*/Libraries/macos/xz-5.0.5**
Download [**libiconv-1.15**](http://www.gnu.org/software/libiconv/#downloading) and unpack to ***BuildPath*/Libraries/macos/libiconv-1.15**
### Clone source code and prepare libraries
Go to ***BuildPath*** and run
MAKE_THREADS_CNT=-j8
MACOSX_DEPLOYMENT_TARGET=10.12
UNGUARDED="-Werror=unguarded-availability-new"
MIN_VER="-mmacosx-version-min=10.12"
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install automake cmake fdk-aac git lame libass libtool libvorbis libvpx ninja opus sdl shtool texi2html theora wget x264 xvid yasm pkg-config gnu-tar
@ -45,24 +41,29 @@ Go to ***BuildPath*** and run
sudo ./setup.py install
cd ../..
mkdir -p Libraries/macos
cd Libraries/macos
LibrariesPath=`pwd`
git clone https://github.com/desktop-app/patches.git
cd patches
git checkout 4f1cffb
cd ../
cd ..
git clone --branch 0.10.0 https://github.com/ericniebler/range-v3
cd xz-5.0.5
CFLAGS="-mmacosx-version-min=10.12" LDFLAGS="-mmacosx-version-min=10.12" ./configure --prefix=/usr/local/macos
xz_ver=5.2.4
wget https://tukaani.org/xz/xz-$xz_ver.tar.gz
tar -xvzf xz-$xz_ver.tar.gz
rm xz-$xz_ver.tar.gz
cd xz-$xz_ver
CFLAGS="$MIN_VER" LDFLAGS="$MIN_VER" ./configure --prefix=/usr/local/macos
make $MAKE_THREADS_CNT
sudo make install
cd ..
git clone https://github.com/desktop-app/zlib.git
cd zlib
CFLAGS="-mmacosx-version-min=10.12 -Werror=unguarded-availability-new" LDFLAGS="-mmacosx-version-min=10.12" ./configure --prefix=/usr/local/macos
CFLAGS="$MIN_VER $UNGUARDED" LDFLAGS="$MIN_VER" ./configure --prefix=/usr/local/macos
make $MAKE_THREADS_CNT
sudo make install
cd ..
@ -70,7 +71,7 @@ Go to ***BuildPath*** and run
git clone https://github.com/openssl/openssl openssl_1_1_1
cd openssl_1_1_1
git checkout OpenSSL_1_1_1-stable
./Configure --prefix=/usr/local/macos darwin64-x86_64-cc -static -mmacosx-version-min=10.12
./Configure --prefix=/usr/local/macos darwin64-x86_64-cc -static $MIN_VER
make build_libs $MAKE_THREADS_CNT
cd ..
@ -78,13 +79,17 @@ Go to ***BuildPath*** and run
cd opus
git checkout v1.3
./autogen.sh
CFLAGS="-mmacosx-version-min=10.12 -Werror=unguarded-availability-new" CPPFLAGS="-mmacosx-version-min=10.12 -Werror=unguarded-availability-new" LDFLAGS="-mmacosx-version-min=10.12" ./configure --prefix=/usr/local/macos
CFLAGS="$MIN_VER $UNGUARDED" CPPFLAGS="$MIN_VER $UNGUARDED" LDFLAGS="$MIN_VER" ./configure --prefix=/usr/local/macos
make $MAKE_THREADS_CNT
sudo make install
cd ..
cd libiconv-1.15
CFLAGS="-mmacosx-version-min=10.12 -Werror=unguarded-availability-new" CPPFLAGS="-mmacosx-version-min=10.12 -Werror=unguarded-availability-new" LDFLAGS="-mmacosx-version-min=10.12" ./configure --enable-static --prefix=/usr/local/macos
libiconv_ver=1.16
wget https://ftp.gnu.org/pub/gnu/libiconv/libiconv-$libiconv_ver.tar.gz
tar -xvzf libiconv-$libiconv_ver.tar.gz
rm libiconv-$libiconv_ver.tar.gz
cd libiconv-$libiconv_ver
CFLAGS="$MIN_VER $UNGUARDED" CPPFLAGS="$MIN_VER $UNGUARDED" LDFLAGS="$MIN_VER" ./configure --enable-static --prefix=/usr/local/macos
make $MAKE_THREADS_CNT
sudo make install
cd ..
@ -97,9 +102,9 @@ Go to ***BuildPath*** and run
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/lib/pkgconfig:/usr/X11/lib/pkgconfig
./configure --prefix=/usr/local/macos \
--extra-cflags="-mmacosx-version-min=10.12 -Werror=unguarded-availability-new" \
--extra-cxxflags="-mmacosx-version-min=10.12 -Werror=unguarded-availability-new" \
--extra-ldflags="-mmacosx-version-min=10.12" \
--extra-cflags="$MIN_VER $UNGUARDED" \
--extra-cxxflags="$MIN_VER $UNGUARDED" \
--extra-ldflags="$MIN_VER" \
--enable-protocol=file --enable-libopus \
--disable-programs \
--disable-doc \
@ -205,7 +210,7 @@ Go to ***BuildPath*** and run
cd openal-soft
git checkout v1.19
cd build
CFLAGS='-Werror=unguarded-availability-new' CPPFLAGS='-Werror=unguarded-availability-new' cmake -D CMAKE_INSTALL_PREFIX:PATH=/usr/local/macos -D ALSOFT_EXAMPLES=OFF -D LIBTYPE:STRING=STATIC -D CMAKE_OSX_DEPLOYMENT_TARGET:STRING=10.12 ..
CFLAGS=$UNGUARDED CPPFLAGS=$UNGUARDED cmake -D CMAKE_INSTALL_PREFIX:PATH=/usr/local/macos -D ALSOFT_EXAMPLES=OFF -D LIBTYPE:STRING=STATIC -D CMAKE_OSX_DEPLOYMENT_TARGET:STRING=10.12 ..
make $MAKE_THREADS_CNT
sudo make install
cd ../..
@ -241,7 +246,19 @@ Go to ***BuildPath*** and run
git apply ../../patches/qtbase_5_12_5.diff
cd ..
./configure -prefix "/usr/local/desktop-app/Qt-5.12.5" -debug-and-release -force-debug-info -opensource -confirm-license -static -opengl desktop -no-openssl -securetransport -nomake examples -nomake tests -platform macx-clang
./configure -prefix "/usr/local/desktop-app/Qt-5.12.5" \
-debug-and-release \
-force-debug-info \
-opensource \
-confirm-license \
-static \
-opengl desktop \
-no-openssl \
-securetransport \
-nomake examples \
-nomake tests \
-platform macx-clang
make $MAKE_THREADS_CNT
sudo make install
cd ..

View file

@ -20,7 +20,7 @@
<url type="help">https://github.com/kotatogram/kotatogram-desktop/issues</url>
<screenshots>
<screenshot type="default">
<image>https://raw.githubusercontent.com/telegramdesktop/tdesktop/dev/docs/assets/preview.png</image>
<image>https://github.com/kotatogram/kotatogram-desktop/blob/dev/docs/assets/ktg_preview.png</image>
</screenshot>
</screenshots>
<keywords>
@ -98,6 +98,7 @@
<content_attribute id="money-purchasing">none</content_attribute>
<content_attribute id="money-gambling">none</content_attribute>
</content_rating>
<launchable type="desktop-id">@TDESKTOP_LAUNCHER_BASENAME@.desktop</launchable>
<provides>
<binary>kotatogram-desktop</binary>
</provides>

View file

@ -6,6 +6,13 @@ base: core18
grade: stable
confinement: strict
architectures:
- build-on: amd64
- build-on: i386
- build-on: arm64
- build-on: armhf
- build-on: ppc64el
apps:
kotatogram-desktop:
command: bin/desktop-launch kotatogram-desktop
@ -14,9 +21,12 @@ apps:
environment:
# Use GTK3 cursor theme, icon theme and open/save file dialogs.
QT_QPA_PLATFORMTHEME: gtk3
# Wayland support is still too bad.
# The blocker is https://github.com/ubuntu/snapcraft-desktop-helpers/issues/172
DISABLE_WAYLAND: 1
plugs:
- alsa
- audio-playback
- audio-record
- desktop
- desktop-legacy
- home
@ -44,6 +54,10 @@ plugs:
target: $SNAP/data-dir/sounds
default-provider: gtk-common-themes
layout:
/usr/share/alsa:
bind: $SNAP/usr/share/alsa
parts:
kotatogram:
plugin: cmake
@ -56,17 +70,11 @@ parts:
- qtbase5-private-dev
- libmapbox-variant-dev
- libasound2-dev
- libavcodec-dev
- libavformat-dev
- libavutil-dev
- libswscale-dev
- libswresample-dev
- libdbusmenu-qt5-dev
- libhunspell-dev
- liblz4-dev
- liblzma-dev
- libminizip-dev
- libopenal-dev
- libopus-dev
- libpulse-dev
- libssl-dev
@ -74,17 +82,11 @@ parts:
stage-packages:
- qt5-image-formats-plugins
- libasound2
- libavcodec57
- libavformat57
- libavutil55
- libswscale4
- libswresample2
- libdbusmenu-qt5-2
- libhunspell-1.6-0
- liblz4-1
- liblzma5
- libminizip1
- libopenal1
- libopus0
- libpulse0
- libssl1.1
@ -119,9 +121,16 @@ parts:
after:
- cmake
- desktop-qt5
- ffmpeg
- openal
- range-v3
- xxhash
patches:
plugin: dump
source: Telegram/Patches
prime: [-./*]
desktop-qt5:
source: https://github.com/ubuntu/snapcraft-desktop-helpers.git
source-subdir: qt
@ -176,6 +185,138 @@ parts:
- libtinfo5
prime: [-./*]
ffmpeg:
source: https://github.com/FFmpeg/FFmpeg.git
source-depth: 1
source-branch: release/4.2
plugin: autotools
build-packages:
- libtool
- pkg-config
- texi2html
- yasm
- libass-dev
- libfreetype6-dev
- libgpac-dev
- liblzma-dev
- libopus-dev
- libsdl1.2-dev
- libtheora-dev
- libva-dev
- libvdpau-dev
- libvorbis-dev
- libxcb1-dev
- libxcb-shm0-dev
- libxcb-xfixes0-dev
- zlib1g-dev
stage-packages:
- freeglut3
- libass9
- libfreetype6
- libgpac4
- liblzma5
- libopus0
- libslang2
- libsdl1.2debian
- libtheora0
- libva2
- libva-drm2
- libvdpau1
- libvorbis0a
- libxcb1
- libxcb-shm0
- libxcb-xfixes0
- zlib1g
configflags:
- --prefix=/usr
- --disable-debug
- --disable-programs
- --disable-doc
- --disable-everything
- --disable-neon
- --enable-gpl
- --enable-version3
- --enable-libopus
- --enable-decoder=aac
- --enable-decoder=aac_latm
- --enable-decoder=aasc
- --enable-decoder=flac
- --enable-decoder=gif
- --enable-decoder=h264
- --enable-decoder=h264_vdpau
- --enable-decoder=mp1
- --enable-decoder=mp1float
- --enable-decoder=mp2
- --enable-decoder=mp2float
- --enable-decoder=mp3
- --enable-decoder=mp3adu
- --enable-decoder=mp3adufloat
- --enable-decoder=mp3float
- --enable-decoder=mp3on4
- --enable-decoder=mp3on4float
- --enable-decoder=mpeg4
- --enable-decoder=mpeg4_vdpau
- --enable-decoder=msmpeg4v2
- --enable-decoder=msmpeg4v3
- --enable-decoder=opus
- --enable-decoder=vorbis
- --enable-decoder=wavpack
- --enable-decoder=wmalossless
- --enable-decoder=wmapro
- --enable-decoder=wmav1
- --enable-decoder=wmav2
- --enable-decoder=wmavoice
- --enable-encoder=libopus
- --enable-hwaccel=h264_vaapi
- --enable-hwaccel=h264_vdpau
- --enable-hwaccel=mpeg4_vaapi
- --enable-hwaccel=mpeg4_vdpau
- --enable-parser=aac
- --enable-parser=aac_latm
- --enable-parser=flac
- --enable-parser=h264
- --enable-parser=mpeg4video
- --enable-parser=mpegaudio
- --enable-parser=opus
- --enable-parser=vorbis
- --enable-demuxer=aac
- --enable-demuxer=flac
- --enable-demuxer=gif
- --enable-demuxer=h264
- --enable-demuxer=mov
- --enable-demuxer=mp3
- --enable-demuxer=ogg
- --enable-demuxer=wav
- --enable-muxer=ogg
- --enable-muxer=opus
override-pull: |
snapcraftctl pull
patch -p1 < "$SNAPCRAFT_STAGE/ffmpeg.diff"
after:
- patches
openal:
source: https://github.com/kcat/openal-soft.git
source-depth: 1
source-tag: openal-soft-1.20.1
plugin: cmake
build-packages:
- libasound2-dev
- libpulse-dev
- libsndio-dev
- portaudio19-dev
stage-packages:
- libasound2
- libpulse0
- libportaudio2
- libsndio6.1
configflags:
- -DCMAKE_BUILD_TYPE=Release
- -DALSOFT_EXAMPLES=OFF
- -DALSOFT_TESTS=OFF
- -DALSOFT_UTILS=OFF
- -DALSOFT_CONFIG=OFF
range-v3:
source: https://github.com/ericniebler/range-v3.git
source-depth: 1