Compare commits
213 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7aeffa242e | ||
|
|
3136c0586e | ||
|
|
fb0fcbca7f | ||
|
|
0d449c037b | ||
|
|
4d98230694 | ||
|
|
3d36e501a1 | ||
|
|
b4eb9a0827 | ||
|
|
aaf0015be4 | ||
|
|
1e8e163bb1 | ||
|
|
f3f741e1eb | ||
|
|
44f52ca6cd | ||
|
|
2b6e04bca3 | ||
|
|
784d57a2bc | ||
|
|
f4fdadd3b0 | ||
|
|
1cc9a52461 | ||
|
|
cd52982752 | ||
|
|
4dd58b79e9 | ||
|
|
c5c94276c2 | ||
|
|
8e0b9b685c | ||
|
|
1792bed721 | ||
|
|
a502cbc06e | ||
|
|
ddda7b8c52 | ||
|
|
0f19ba3231 | ||
|
|
36486a3d73 | ||
|
|
02f48a7781 | ||
|
|
c77f4dd794 | ||
|
|
ca31a08182 | ||
|
|
33936195a1 | ||
|
|
67bafa02fe | ||
|
|
1ef0046002 | ||
|
|
f2f19b14eb | ||
|
|
662966ba31 | ||
|
|
5383ae3d96 | ||
|
|
d80b25944e | ||
|
|
76813db3ad | ||
|
|
c3595f2e31 | ||
|
|
5a882d1fdc | ||
|
|
ce6f9f580f | ||
|
|
52b9a1fceb | ||
|
|
1209b2692a | ||
|
|
2abcb51dda | ||
|
|
7a06eccaec | ||
|
|
a1f81e4de8 | ||
|
|
689378ee04 | ||
|
|
b239506150 | ||
|
|
3dadcd9352 | ||
|
|
b9a9520ef5 | ||
|
|
2b46f87d7b | ||
|
|
2667bb3568 | ||
|
|
1bc5277d51 | ||
|
|
436d7b9d82 | ||
|
|
ba7e976fe2 | ||
|
|
c2b1187948 | ||
|
|
1fd28d5cfb | ||
|
|
eec58137e9 | ||
|
|
e7d39e6046 | ||
|
|
63a92cb90a | ||
|
|
85cc3b30a0 | ||
|
|
474a6a71d9 | ||
|
|
393173c1da | ||
|
|
badc27eda4 | ||
|
|
920f3b245b | ||
|
|
f189ffc6ac | ||
|
|
840bb447ba | ||
|
|
414456d003 | ||
|
|
ea3191badf | ||
|
|
4452edcaad | ||
|
|
76eb00cea9 | ||
|
|
b3622b413e | ||
|
|
b55383efe7 | ||
|
|
852e46f0c9 | ||
|
|
84fef1f045 | ||
|
|
6cadf54874 | ||
|
|
e8fc874456 | ||
|
|
c79cd0b692 | ||
|
|
b150ab8ef5 | ||
|
|
8b7b0fa570 | ||
|
|
a3ee1e4ed5 | ||
|
|
349446e6b0 | ||
|
|
97262a99c7 | ||
|
|
1d2e34f5e9 | ||
|
|
bc2fc94e25 | ||
|
|
6f0e94a04a | ||
|
|
60e43cfa3f | ||
|
|
46885b7f9f | ||
|
|
fff42a664c | ||
|
|
437d35d8c4 | ||
|
|
36a5dd8d8b | ||
|
|
d8e99b4860 | ||
|
|
3cddcaa039 | ||
|
|
49078e5679 | ||
|
|
1dec054766 | ||
|
|
91ef6f13c8 | ||
|
|
73c8f16340 | ||
|
|
cbad2469db | ||
|
|
0ae260c6e1 | ||
|
|
221ded6d54 | ||
|
|
6f80811ecd | ||
|
|
5bd73bab9b | ||
|
|
ac86f3e5bd | ||
|
|
bae6a29326 | ||
|
|
dcf86f55af | ||
|
|
2d223b3a2d | ||
|
|
f3ab01604c | ||
|
|
66bcc20f58 | ||
|
|
d69a1d3cd9 | ||
|
|
ccc5aeb8f7 | ||
|
|
5899d60363 | ||
|
|
4f89216db0 | ||
|
|
bd78bac4bf | ||
|
|
b2e829904f | ||
|
|
256546071b | ||
|
|
c100055fac | ||
|
|
ae30366cbf | ||
|
|
663c99cc2d | ||
|
|
d986e70a89 | ||
|
|
1ebf27bfa1 | ||
|
|
4ef2d3b957 | ||
|
|
868c494299 | ||
|
|
4a86b172d4 | ||
|
|
f71ce9afdf | ||
|
|
c170a86189 | ||
|
|
116a768fde | ||
|
|
22e77bf3af | ||
|
|
bbbcd37b8f | ||
|
|
bc707320f8 | ||
|
|
000911ecfa | ||
|
|
479611f6df | ||
|
|
dcc8a64d37 | ||
|
|
a030907598 | ||
|
|
34cac3092f | ||
|
|
05f1caf944 | ||
|
|
93bcd90fd4 | ||
|
|
7c8b1cd5b1 | ||
|
|
82165bec5e | ||
|
|
65aecf16a6 | ||
|
|
ca83b8a8c6 | ||
|
|
024bb5e54f | ||
|
|
a14f2144e1 | ||
|
|
c6071d1148 | ||
|
|
6e2f8eb9a7 | ||
|
|
793f748d2e | ||
|
|
bb404a38d3 | ||
|
|
c82006c6f8 | ||
|
|
2256482ae0 | ||
|
|
d11e756381 | ||
|
|
a128c16f59 | ||
|
|
48207102ce | ||
|
|
2d354f8777 | ||
|
|
b27dc4ef8d | ||
|
|
99505b4ee2 | ||
|
|
245909e381 | ||
|
|
0a545589ce | ||
|
|
4ec764bb57 | ||
|
|
9b6ab6e137 | ||
|
|
73bb1382b1 | ||
|
|
a153059b38 | ||
|
|
039ffd3d34 | ||
|
|
abdd2fa99b | ||
|
|
b366c27a0c | ||
|
|
1fa71b6569 | ||
|
|
81c39af122 | ||
|
|
9699aeb1cd | ||
|
|
85ce179f58 | ||
|
|
c4d8d52aed | ||
|
|
812f5d4311 | ||
|
|
34d2d7bcba | ||
|
|
842a89d2c7 | ||
|
|
565877630f | ||
|
|
8f478b86ee | ||
|
|
9943f8a093 | ||
|
|
c0f8e68f5d | ||
|
|
92d9ebc9f3 | ||
|
|
530aae4bdb | ||
|
|
e1ff230547 | ||
|
|
95a896004f | ||
|
|
87ca2c891a | ||
|
|
3a26644fa2 | ||
|
|
7e11966766 | ||
|
|
c1c4314e52 | ||
|
|
a6dbcdad54 | ||
|
|
3dc73417e9 | ||
|
|
1ce66e5198 | ||
|
|
6e90d6ae53 | ||
|
|
5910c0ae30 | ||
|
|
2de0b79b4e | ||
|
|
cba0ebce6e | ||
|
|
773912f586 | ||
|
|
c789349b24 | ||
|
|
7bbc4b7191 | ||
|
|
551732738b | ||
|
|
c5867e2293 | ||
|
|
46d5fc1fa0 | ||
|
|
b922839490 | ||
|
|
4b82a56270 | ||
|
|
b2c762e974 | ||
|
|
0a4b8fc7f6 | ||
|
|
087fbe89ce | ||
|
|
3e8912a53f | ||
|
|
dc81f9eeaf | ||
|
|
49fed41dfa | ||
|
|
9b1d967967 | ||
|
|
4ea065fdf1 | ||
|
|
a094fa42a0 | ||
|
|
6f151f20e9 | ||
|
|
ae70dfb1f4 | ||
|
|
d9ea4f31ca | ||
|
|
ba9b72e038 | ||
|
|
3d1a049405 | ||
|
|
df9e9a9d75 | ||
|
|
77d8c7ce01 | ||
|
|
de0897343b | ||
|
|
e27399baa6 |
10
.github/workflows/linux.yml
vendored
@@ -5,7 +5,7 @@ on:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**.md'
|
||||
- '!docs/building-cmake.md'
|
||||
- '!docs/building-linux.md'
|
||||
- 'changelog.txt'
|
||||
- 'LEGAL'
|
||||
- 'LICENSE'
|
||||
@@ -13,7 +13,6 @@ on:
|
||||
- '!.github/workflows/linux.yml'
|
||||
- 'snap/**'
|
||||
- 'Telegram/build/**'
|
||||
- 'Telegram/Patches/**'
|
||||
- 'Telegram/Resources/uwp/**'
|
||||
- 'Telegram/Resources/winrc/**'
|
||||
- 'Telegram/SourceFiles/platform/win/**'
|
||||
@@ -25,7 +24,7 @@ on:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**.md'
|
||||
- '!docs/building-cmake.md'
|
||||
- '!docs/building-linux.md'
|
||||
- 'changelog.txt'
|
||||
- 'LEGAL'
|
||||
- 'LICENSE'
|
||||
@@ -33,7 +32,6 @@ on:
|
||||
- '!.github/workflows/linux.yml'
|
||||
- 'snap/**'
|
||||
- 'Telegram/build/**'
|
||||
- 'Telegram/Patches/**'
|
||||
- 'Telegram/Resources/uwp/**'
|
||||
- 'Telegram/Resources/winrc/**'
|
||||
- 'Telegram/SourceFiles/platform/win/**'
|
||||
@@ -65,8 +63,6 @@ jobs:
|
||||
- "DESKTOP_APP_DISABLE_X11_INTEGRATION"
|
||||
- "DESKTOP_APP_DISABLE_WAYLAND_INTEGRATION"
|
||||
- "DESKTOP_APP_DISABLE_GTK_INTEGRATION"
|
||||
- "LIBTGVOIP_DISABLE_ALSA"
|
||||
- "LIBTGVOIP_DISABLE_PULSEAUDIO"
|
||||
|
||||
env:
|
||||
UPLOAD_ARTIFACT: "false"
|
||||
@@ -94,7 +90,7 @@ jobs:
|
||||
if [ -n "${{ matrix.defines }}" ]; then
|
||||
DEFINE="-D ${{ matrix.defines }}=ON"
|
||||
if [ "${{ matrix.defines }}" == "DESKTOP_APP_DISABLE_DBUS_INTEGRATION" ]; then
|
||||
DEFINE="$DEFINE -D DESKTOP_APP_DISABLE_GTK_INTEGRATION=ON"
|
||||
DEFINE="$DEFINE -D DESKTOP_APP_DISABLE_GTK_INTEGRATION=ON -D DESKTOP_APP_DISABLE_WEBKITGTK=ON"
|
||||
fi
|
||||
echo Define from matrix: $DEFINE
|
||||
echo "ARTIFACT_NAME=Telegram_${{ matrix.defines }}" >> $GITHUB_ENV
|
||||
|
||||
2
.github/workflows/lock.yml
vendored
@@ -2,7 +2,7 @@ name: 'Lock Threads'
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 * * * *'
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
lock:
|
||||
|
||||
11
.github/workflows/mac.yml
vendored
@@ -5,7 +5,7 @@ on:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**.md'
|
||||
- '!docs/building-xcode.md'
|
||||
- '!docs/building-mac.md'
|
||||
- 'changelog.txt'
|
||||
- 'LEGAL'
|
||||
- 'LICENSE'
|
||||
@@ -14,7 +14,6 @@ on:
|
||||
- 'lib/xdg/**'
|
||||
- 'snap/**'
|
||||
- 'Telegram/build/**'
|
||||
- 'Telegram/Patches/**'
|
||||
- 'Telegram/Resources/uwp/**'
|
||||
- 'Telegram/Resources/winrc/**'
|
||||
- 'Telegram/SourceFiles/platform/win/**'
|
||||
@@ -24,7 +23,7 @@ on:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**.md'
|
||||
- '!docs/building-xcode.md'
|
||||
- '!docs/building-mac.md'
|
||||
- 'changelog.txt'
|
||||
- 'LEGAL'
|
||||
- 'LICENSE'
|
||||
@@ -33,7 +32,6 @@ on:
|
||||
- 'lib/xdg/**'
|
||||
- 'snap/**'
|
||||
- 'Telegram/build/**'
|
||||
- 'Telegram/Patches/**'
|
||||
- 'Telegram/Resources/uwp/**'
|
||||
- 'Telegram/Resources/winrc/**'
|
||||
- 'Telegram/SourceFiles/platform/win/**'
|
||||
@@ -64,7 +62,7 @@ jobs:
|
||||
UPLOAD_ARTIFACT: "false"
|
||||
ONLY_CACHE: "false"
|
||||
MANUAL_CACHING: "2"
|
||||
DOC_PATH: "docs/building-xcode.md"
|
||||
DOC_PATH: "docs/building-mac.md"
|
||||
AUTO_CACHING: "1"
|
||||
|
||||
steps:
|
||||
@@ -451,10 +449,11 @@ jobs:
|
||||
|
||||
git clone git://code.qt.io/qt/qt5.git qt_$QT
|
||||
cd qt_$QT
|
||||
perl init-repository --module-subset=qtbase,qtimageformats
|
||||
perl init-repository --module-subset=qtbase,qtimageformats,qtsvg
|
||||
git checkout v5.15.2
|
||||
git submodule update qtbase
|
||||
git submodule update qtimageformats
|
||||
git submodule update qtsvg
|
||||
cd qtbase
|
||||
find ../../patches/qtbase_$QT -type f -print0 | sort -z | xargs -0 git apply
|
||||
cd ..
|
||||
|
||||
2
.github/workflows/snap.yml
vendored
@@ -11,7 +11,6 @@ on:
|
||||
- '.github/**'
|
||||
- '!.github/workflows/snap.yml'
|
||||
- 'Telegram/build/**'
|
||||
- 'Telegram/Patches/**'
|
||||
- 'Telegram/Resources/uwp/**'
|
||||
- 'Telegram/Resources/winrc/**'
|
||||
- 'Telegram/SourceFiles/platform/win/**'
|
||||
@@ -29,7 +28,6 @@ on:
|
||||
- '.github/**'
|
||||
- '!.github/workflows/snap.yml'
|
||||
- 'Telegram/build/**'
|
||||
- 'Telegram/Patches/**'
|
||||
- 'Telegram/Resources/uwp/**'
|
||||
- 'Telegram/Resources/winrc/**'
|
||||
- 'Telegram/SourceFiles/platform/win/**'
|
||||
|
||||
63
.github/workflows/win.yml
vendored
@@ -5,7 +5,7 @@ on:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**.md'
|
||||
- '!docs/building-msvc.md'
|
||||
- '!docs/building-win.md'
|
||||
- 'changelog.txt'
|
||||
- 'LEGAL'
|
||||
- 'LICENSE'
|
||||
@@ -14,8 +14,6 @@ on:
|
||||
- 'lib/xdg/**'
|
||||
- 'snap/**'
|
||||
- 'Telegram/build/**'
|
||||
- 'Telegram/Patches/**'
|
||||
- '!Telegram/Patches/build_ffmpeg_win.sh'
|
||||
- 'Telegram/Resources/uwp/**'
|
||||
- 'Telegram/SourceFiles/platform/linux/**'
|
||||
- 'Telegram/SourceFiles/platform/mac/**'
|
||||
@@ -26,7 +24,7 @@ on:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**.md'
|
||||
- '!docs/building-msvc.md'
|
||||
- '!docs/building-win.md'
|
||||
- 'changelog.txt'
|
||||
- 'LEGAL'
|
||||
- 'LICENSE'
|
||||
@@ -35,12 +33,9 @@ on:
|
||||
- 'lib/xdg/**'
|
||||
- 'snap/**'
|
||||
- 'Telegram/build/**'
|
||||
- 'Telegram/Patches/**'
|
||||
- '!Telegram/Patches/build_ffmpeg_win.sh'
|
||||
- 'Telegram/Resources/uwp/**'
|
||||
- 'Telegram/SourceFiles/platform/linux/**'
|
||||
- 'Telegram/SourceFiles/platform/mac/**'
|
||||
- '!Telegram/Patches/breakpad.diff'
|
||||
- 'Telegram/Telegram/**'
|
||||
- 'Telegram/configure.sh'
|
||||
- 'Telegram/Telegram.plist'
|
||||
@@ -57,28 +52,34 @@ jobs:
|
||||
- ""
|
||||
env:
|
||||
SDK: "10.0.18362.0"
|
||||
VC: "call vcvars32.bat && cd Libraries"
|
||||
GIT: "https://github.com"
|
||||
QT: "5_15_2"
|
||||
QT_VER: "5.15.2"
|
||||
OPENSSL_VER: "1_1_1"
|
||||
UPLOAD_ARTIFACT: "false"
|
||||
ONLY_CACHE: "false"
|
||||
MANUAL_CACHING: "2"
|
||||
DOC_PATH: "docs/building-msvc.md"
|
||||
MANUAL_CACHING: "0"
|
||||
DOC_PATH: "docs/building-win.md"
|
||||
AUTO_CACHING: "1"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: cmd
|
||||
working-directory: Libraries
|
||||
|
||||
steps:
|
||||
- name: Get repository name.
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
|
||||
|
||||
- uses: ilammy/msvc-dev-cmd@v1.9.0
|
||||
name: x86 Native Tools Command Prompt.
|
||||
with:
|
||||
arch: win32
|
||||
|
||||
- name: Set up environment paths.
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
echo "C:\\Strawberry\\perl\\bin\\" >> $GITHUB_PATH
|
||||
echo "C:\\Program Files\\NASM\\" >> $GITHUB_PATH
|
||||
@@ -89,6 +90,8 @@ jobs:
|
||||
p=`pwd | sed 's#^/[d]#d:#g' |sed 's#/#\\\\#g'`
|
||||
echo "LibrariesPath=$p" >> $GITHUB_ENV
|
||||
|
||||
echo "QT=${QT_VER//./_}" >> $GITHUB_ENV
|
||||
|
||||
- name: Save msbuild version.
|
||||
run: |
|
||||
call vcvars32.bat
|
||||
@@ -102,6 +105,7 @@ jobs:
|
||||
|
||||
- name: Generate cache key.
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
curl -o $LibrariesPath/tg_owt-version.json https://api.github.com/repos/desktop-app/tg_owt/git/refs/heads/master
|
||||
curl -o $LibrariesPath/tg_angle-version.json https://api.github.com/repos/desktop-app/tg_angle/git/refs/heads/master
|
||||
@@ -113,7 +117,10 @@ jobs:
|
||||
echo "CACHE_KEY=`md5sum CACHE_KEY.txt | awk '{ print $1 }'`" >> $GITHUB_ENV
|
||||
|
||||
- name: Choco installs.
|
||||
run: choco install --no-progress -y nasm yasm jom ninja
|
||||
run: |
|
||||
choco install --allow-empty-checksums --no-progress -y yasm
|
||||
choco install --no-progress -y nasm jom ninja
|
||||
python -m pip install pywin32
|
||||
|
||||
- name: NuGet sources.
|
||||
run: |
|
||||
@@ -122,6 +129,7 @@ jobs:
|
||||
|
||||
- name: Patches.
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
echo "Find necessary commit from doc."
|
||||
checkoutCommit=$(grep -A 1 "cd patches" $REPO_NAME/$DOC_PATH | sed -n 2p)
|
||||
@@ -144,8 +152,6 @@ jobs:
|
||||
|
||||
- name: LZMA.
|
||||
run: |
|
||||
%VC%
|
||||
|
||||
git clone %GIT%/telegramdesktop/lzma.git
|
||||
cd lzma
|
||||
cd C\Util\LzmaLib
|
||||
@@ -160,8 +166,6 @@ jobs:
|
||||
- name: OpenSSL.
|
||||
if: steps.cache-openssl.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
%VC%
|
||||
|
||||
git clone %GIT%/openssl/openssl.git openssl_%OPENSSL_VER%
|
||||
cd openssl_%OPENSSL_VER%
|
||||
git checkout OpenSSL_%OPENSSL_VER%-stable
|
||||
@@ -185,8 +189,6 @@ jobs:
|
||||
|
||||
- name: Zlib.
|
||||
run: |
|
||||
%VC%
|
||||
|
||||
git clone %GIT%/telegramdesktop/zlib.git
|
||||
cd zlib
|
||||
git checkout tdesktop
|
||||
@@ -196,8 +198,6 @@ jobs:
|
||||
- name: MozJPEG.
|
||||
shell: cmd
|
||||
run: |
|
||||
%VC%
|
||||
|
||||
git clone -b v4.0.1-rc2 %GIT%/mozilla/mozjpeg.git
|
||||
cd mozjpeg
|
||||
cmake . ^
|
||||
@@ -216,8 +216,6 @@ jobs:
|
||||
- name: OpenAL Soft.
|
||||
if: steps.cache-openal.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
%VC%
|
||||
|
||||
git clone -b openal-soft-1.21.0 --depth=1 %GIT%/kcat/openal-soft.git
|
||||
cd openal-soft\build
|
||||
cmake .. ^
|
||||
@@ -241,8 +239,6 @@ jobs:
|
||||
GYP_MSVS_VERSION: 2019
|
||||
if: steps.cache-breakpad.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd %LibrariesPath%
|
||||
|
||||
git clone %GIT%/telegramdesktop/gyp.git
|
||||
cd gyp
|
||||
SET PATH=%PY2%;%cd%;%PATH%
|
||||
@@ -276,8 +272,6 @@ jobs:
|
||||
- name: Opus.
|
||||
if: steps.cache-opus.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
%VC%
|
||||
|
||||
git clone %GIT%/telegramdesktop/opus.git
|
||||
cd opus
|
||||
git checkout tdesktop
|
||||
@@ -286,10 +280,7 @@ jobs:
|
||||
msbuild -m opus.sln /property:Configuration=Release /property:Platform="Win32"
|
||||
|
||||
- name: Rnnoise.
|
||||
shell: cmd
|
||||
run: |
|
||||
%VC%
|
||||
|
||||
git clone %GIT%/desktop-app/rnnoise.git
|
||||
mkdir rnnoise\out
|
||||
cd rnnoise\out
|
||||
@@ -305,7 +296,6 @@ jobs:
|
||||
- name: FFmpeg.
|
||||
if: steps.cache-ffmpeg.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
%VC%
|
||||
choco install --no-progress -y msys2
|
||||
|
||||
git clone %GIT%/FFmpeg/FFmpeg.git ffmpeg
|
||||
@@ -326,8 +316,6 @@ jobs:
|
||||
- name: Angle.
|
||||
if: steps.cache-angle.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
%VC%
|
||||
|
||||
git clone --recursive %GIT%/desktop-app/tg_angle.git
|
||||
mkdir tg_angle\out\Debug
|
||||
cd tg_angle\out\Debug
|
||||
@@ -353,14 +341,13 @@ jobs:
|
||||
- name: Configure Qt 5.15.2.
|
||||
if: steps.cache-qt.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
%VC%
|
||||
|
||||
git clone git://code.qt.io/qt/qt5.git qt_%QT%
|
||||
cd qt_%QT%
|
||||
perl init-repository --module-subset=qtbase,qtimageformats
|
||||
perl init-repository --module-subset=qtbase,qtimageformats,qtsvg
|
||||
git checkout v%QT_VER%
|
||||
git submodule update qtbase
|
||||
git submodule update qtimageformats
|
||||
git submodule update qtsvg
|
||||
cd qtbase
|
||||
for /r %%i in (..\..\patches\qtbase_%QT%\*) do git apply %%i
|
||||
cd ..
|
||||
@@ -406,7 +393,6 @@ jobs:
|
||||
- name: Qt 5.15.2 build.
|
||||
if: steps.cache-qt.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
%VC%
|
||||
cd qt_%QT%
|
||||
|
||||
jom -j%NUMBER_OF_PROCESSORS%
|
||||
@@ -424,8 +410,6 @@ jobs:
|
||||
- name: WebRTC.
|
||||
if: steps.cache-webrtc.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
%VC%
|
||||
|
||||
git clone --recursive %GIT%/desktop-app/tg_owt.git
|
||||
mkdir tg_owt\out\Debug
|
||||
cd tg_owt\out\Debug
|
||||
@@ -462,10 +446,12 @@ jobs:
|
||||
echo "TDESKTOP_BUILD_DEFINE=$DEFINE" >> $GITHUB_ENV
|
||||
|
||||
- name: Free up some disk space.
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: del /S *.pdb
|
||||
|
||||
- name: Telegram Desktop build.
|
||||
if: env.ONLY_CACHE == 'false'
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
cd %REPO_NAME%\Telegram
|
||||
|
||||
@@ -483,6 +469,7 @@ jobs:
|
||||
|
||||
- name: Move artifact.
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
cd %REPO_NAME%\out\Debug
|
||||
mkdir artifact
|
||||
|
||||
3
.gitmodules
vendored
@@ -91,3 +91,6 @@
|
||||
[submodule "Telegram/lib_waylandshells"]
|
||||
path = Telegram/lib_waylandshells
|
||||
url = https://github.com/desktop-app/lib_waylandshells.git
|
||||
[submodule "Telegram/ThirdParty/jemalloc"]
|
||||
path = Telegram/ThirdParty/jemalloc
|
||||
url = https://github.com/jemalloc/jemalloc
|
||||
|
||||
@@ -14,8 +14,13 @@ include(cmake/validate_special_target.cmake)
|
||||
include(cmake/version.cmake)
|
||||
desktop_app_parse_version(Telegram/build/version)
|
||||
|
||||
set(project_langs C CXX)
|
||||
if (APPLE)
|
||||
set(project_langs C CXX OBJC OBJCXX)
|
||||
endif()
|
||||
|
||||
project(Telegram
|
||||
LANGUAGES C CXX
|
||||
LANGUAGES ${project_langs}
|
||||
VERSION ${desktop_app_version_cmake}
|
||||
DESCRIPTION "Official Telegram Desktop messenger"
|
||||
HOMEPAGE_URL "https://desktop.telegram.org"
|
||||
@@ -24,6 +29,7 @@ set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT T
|
||||
|
||||
get_filename_component(third_party_loc "Telegram/ThirdParty" REALPATH)
|
||||
get_filename_component(submodules_loc "Telegram" REALPATH)
|
||||
get_filename_component(cmake_helpers_loc "cmake" REALPATH)
|
||||
|
||||
include(cmake/variables.cmake)
|
||||
include(cmake/nice_target_sources.cmake)
|
||||
@@ -32,6 +38,7 @@ include(cmake/target_link_frameworks.cmake)
|
||||
include(cmake/init_target.cmake)
|
||||
include(cmake/generate_target.cmake)
|
||||
include(cmake/nuget.cmake)
|
||||
include(cmake/validate_d3d_compiler.cmake)
|
||||
|
||||
include(cmake/options.cmake)
|
||||
|
||||
|
||||
15
README.md
@@ -63,9 +63,9 @@ Version **1.8.15** was the last that supports older systems
|
||||
|
||||
## Build instructions
|
||||
|
||||
* Visual Studio 2019 [(32 bits)][msvc32] [(64 bits)][msvc64]
|
||||
* [Xcode 12][xcode]
|
||||
* [CMake on GNU/Linux][cmake]
|
||||
* Windows [(32-bit)][win32] [(64-bit)][win64]
|
||||
* [macOS][mac]
|
||||
* [GNU/Linux using Docker][linux]
|
||||
|
||||
[//]: # (LINKS)
|
||||
[telegram]: https://telegram.org
|
||||
@@ -73,10 +73,9 @@ Version **1.8.15** was the last that supports older systems
|
||||
[telegram_api]: https://core.telegram.org
|
||||
[telegram_proto]: https://core.telegram.org/mtproto
|
||||
[license]: LICENSE
|
||||
[msvc32]: docs/building-msvc.md
|
||||
[msvc64]: docs/building-msvc-x64.md
|
||||
[xcode]: docs/building-xcode.md
|
||||
[xcode_old]: docs/building-xcode-old.md
|
||||
[cmake]: docs/building-cmake.md
|
||||
[win32]: docs/building-win.md
|
||||
[win64]: docs/building-win-x64.md
|
||||
[mac]: docs/building-mac.md
|
||||
[linux]: docs/building-linux.md
|
||||
[preview_image]: https://github.com/telegramdesktop/tdesktop/blob/dev/docs/assets/preview.png "Preview of Telegram Desktop"
|
||||
[preview_image_url]: https://raw.githubusercontent.com/telegramdesktop/tdesktop/dev/docs/assets/preview.png
|
||||
|
||||
@@ -82,59 +82,6 @@ PRIVATE
|
||||
desktop-app::external_xxhash
|
||||
)
|
||||
|
||||
if (LINUX)
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
desktop-app::external_glibmm
|
||||
desktop-app::external_glib
|
||||
)
|
||||
|
||||
if (NOT DESKTOP_APP_DISABLE_DBUS_INTEGRATION)
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
desktop-app::external_statusnotifieritem
|
||||
desktop-app::external_dbusmenu_qt
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT DESKTOP_APP_DISABLE_X11_INTEGRATION)
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
desktop-app::external_xcb
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT DESKTOP_APP_DISABLE_WAYLAND_INTEGRATION)
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
desktop-app::lib_waylandshells
|
||||
desktop-app::external_kwayland
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT DESKTOP_APP_DISABLE_GTK_INTEGRATION)
|
||||
target_link_libraries(Telegram PRIVATE rt)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
if (DESKTOP_APP_USE_PACKAGED AND NOT DESKTOP_APP_USE_PACKAGED_LAZY)
|
||||
pkg_check_modules(GTK3 REQUIRED IMPORTED_TARGET gtk+-3.0)
|
||||
target_link_libraries(Telegram PRIVATE PkgConfig::GTK3)
|
||||
|
||||
if (NOT DESKTOP_APP_DISABLE_X11_INTEGRATION)
|
||||
pkg_check_modules(X11 REQUIRED IMPORTED_TARGET x11)
|
||||
target_link_libraries(Telegram PRIVATE PkgConfig::X11)
|
||||
endif()
|
||||
else()
|
||||
pkg_check_modules(GTK REQUIRED gtk+-3.0)
|
||||
target_include_directories(Telegram PRIVATE ${GTK_INCLUDE_DIRS})
|
||||
|
||||
if (NOT DESKTOP_APP_DISABLE_X11_INTEGRATION)
|
||||
target_link_libraries(Telegram PRIVATE X11)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_precompile_headers(Telegram PRIVATE ${src_loc}/stdafx.h)
|
||||
nice_target_sources(Telegram ${src_loc}
|
||||
PRIVATE
|
||||
@@ -144,12 +91,16 @@ PRIVATE
|
||||
api/api_attached_stickers.h
|
||||
api/api_authorizations.cpp
|
||||
api/api_authorizations.h
|
||||
api/api_blocked_peers.cpp
|
||||
api/api_blocked_peers.h
|
||||
api/api_bot.cpp
|
||||
api/api_bot.h
|
||||
api/api_chat_filters.cpp
|
||||
api/api_chat_filters.h
|
||||
api/api_chat_invite.cpp
|
||||
api/api_chat_invite.h
|
||||
api/api_cloud_password.cpp
|
||||
api/api_cloud_password.h
|
||||
api/api_common.h
|
||||
api/api_editing.cpp
|
||||
api/api_editing.h
|
||||
@@ -177,6 +128,8 @@ PRIVATE
|
||||
api/api_toggling_media.h
|
||||
api/api_updates.cpp
|
||||
api/api_updates.h
|
||||
api/api_user_privacy.cpp
|
||||
api/api_user_privacy.h
|
||||
boxes/filters/edit_filter_box.cpp
|
||||
boxes/filters/edit_filter_box.h
|
||||
boxes/filters/edit_filter_chats_list.cpp
|
||||
@@ -273,6 +226,7 @@ PRIVATE
|
||||
calls/group/calls_choose_join_as.h
|
||||
calls/group/calls_group_call.cpp
|
||||
calls/group/calls_group_call.h
|
||||
calls/group/calls_group_common.cpp
|
||||
calls/group/calls_group_common.h
|
||||
calls/group/calls_group_invite_controller.cpp
|
||||
calls/group/calls_group_invite_controller.h
|
||||
@@ -318,6 +272,8 @@ PRIVATE
|
||||
calls/calls_video_bubble.h
|
||||
calls/calls_video_incoming.cpp
|
||||
calls/calls_video_incoming.h
|
||||
chat_helpers/bot_command.cpp
|
||||
chat_helpers/bot_command.h
|
||||
chat_helpers/bot_keyboard.cpp
|
||||
chat_helpers/bot_keyboard.h
|
||||
chat_helpers/emoji_keywords.cpp
|
||||
@@ -617,6 +573,8 @@ PRIVATE
|
||||
history/view/history_view_cursor_state.h
|
||||
history/view/history_view_element.cpp
|
||||
history/view/history_view_element.h
|
||||
history/view/history_view_empty_list_bubble.cpp
|
||||
history/view/history_view_empty_list_bubble.h
|
||||
history/view/history_view_group_call_tracker.cpp
|
||||
history/view/history_view_group_call_tracker.h
|
||||
history/view/history_view_list_widget.cpp
|
||||
@@ -753,6 +711,10 @@ PRIVATE
|
||||
lang/lang_numbers_animation.h
|
||||
lang/lang_translator.cpp
|
||||
lang/lang_translator.h
|
||||
layout/layout_document_generic_preview.cpp
|
||||
layout/layout_document_generic_preview.h
|
||||
layout/layout_item_base.cpp
|
||||
layout/layout_item_base.h
|
||||
main/main_account.cpp
|
||||
main/main_account.h
|
||||
main/main_app_config.cpp
|
||||
@@ -894,16 +856,12 @@ PRIVATE
|
||||
platform/linux/linux_desktop_environment.h
|
||||
platform/linux/linux_gdk_helper.cpp
|
||||
platform/linux/linux_gdk_helper.h
|
||||
platform/linux/linux_gsd_media_keys.cpp
|
||||
platform/linux/linux_gsd_media_keys.h
|
||||
platform/linux/linux_gtk_integration_dummy.cpp
|
||||
platform/linux/linux_gtk_integration_p.h
|
||||
platform/linux/linux_gtk_integration.cpp
|
||||
platform/linux/linux_gtk_integration.h
|
||||
platform/linux/linux_gtk_open_with_dialog.cpp
|
||||
platform/linux/linux_gtk_open_with_dialog.h
|
||||
platform/linux/linux_notification_service_watcher.cpp
|
||||
platform/linux/linux_notification_service_watcher.h
|
||||
platform/linux/linux_wayland_integration_dummy.cpp
|
||||
platform/linux/linux_wayland_integration.cpp
|
||||
platform/linux/linux_wayland_integration.h
|
||||
@@ -922,7 +880,6 @@ PRIVATE
|
||||
platform/linux/notifications_manager_linux.h
|
||||
platform/linux/specific_linux.cpp
|
||||
platform/linux/specific_linux.h
|
||||
platform/linux/window_title_linux.h
|
||||
platform/mac/file_utilities_mac.mm
|
||||
platform/mac/file_utilities_mac.h
|
||||
platform/mac/launcher_mac.mm
|
||||
@@ -937,7 +894,6 @@ PRIVATE
|
||||
platform/mac/specific_mac_p.mm
|
||||
platform/mac/specific_mac_p.h
|
||||
platform/mac/window_title_mac.mm
|
||||
platform/mac/window_title_mac.h
|
||||
platform/mac/touchbar/items/mac_formatter_item.h
|
||||
platform/mac/touchbar/items/mac_formatter_item.mm
|
||||
platform/mac/touchbar/items/mac_pinned_chats_item.h
|
||||
@@ -968,8 +924,6 @@ PRIVATE
|
||||
platform/win/notifications_manager_win.h
|
||||
platform/win/specific_win.cpp
|
||||
platform/win/specific_win.h
|
||||
platform/win/window_title_win.cpp
|
||||
platform/win/window_title_win.h
|
||||
platform/win/windows_app_user_model_id.cpp
|
||||
platform/win/windows_app_user_model_id.h
|
||||
platform/win/windows_dlls.cpp
|
||||
@@ -1143,13 +1097,11 @@ PRIVATE
|
||||
window/window_outdated_bar.h
|
||||
window/window_peer_menu.cpp
|
||||
window/window_peer_menu.h
|
||||
window/window_section_common.h
|
||||
window/window_session_controller.cpp
|
||||
window/window_session_controller.h
|
||||
window/window_slide_animation.cpp
|
||||
window/window_slide_animation.h
|
||||
window/window_title_qt.cpp
|
||||
window/window_title_qt.h
|
||||
window/window_title.h
|
||||
window/window_top_bar_wrap.h
|
||||
window/themes/window_theme.cpp
|
||||
window/themes/window_theme.h
|
||||
@@ -1176,8 +1128,6 @@ PRIVATE
|
||||
config.h
|
||||
facades.cpp
|
||||
facades.h
|
||||
layout.cpp
|
||||
layout.h
|
||||
logs.cpp
|
||||
logs.h
|
||||
main.cpp
|
||||
@@ -1190,21 +1140,8 @@ PRIVATE
|
||||
stdafx.h
|
||||
)
|
||||
|
||||
if (NOT LINUX)
|
||||
remove_target_sources(Telegram ${src_loc}
|
||||
window/window_title_qt.cpp
|
||||
window/window_title_qt.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if (DESKTOP_APP_DISABLE_DBUS_INTEGRATION)
|
||||
remove_target_sources(Telegram ${src_loc}
|
||||
platform/linux/linux_gsd_media_keys.cpp
|
||||
platform/linux/linux_gsd_media_keys.h
|
||||
platform/linux/linux_mpris_support.cpp
|
||||
platform/linux/linux_mpris_support.h
|
||||
platform/linux/linux_notification_service_watcher.cpp
|
||||
platform/linux/linux_notification_service_watcher.h
|
||||
platform/linux/linux_xdp_file_dialog.cpp
|
||||
platform/linux/linux_xdp_file_dialog.h
|
||||
platform/linux/linux_xdp_open_with_dialog.cpp
|
||||
@@ -1322,6 +1259,46 @@ elseif (APPLE)
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
desktop-app::external_glibmm
|
||||
desktop-app::external_glib
|
||||
)
|
||||
|
||||
if (NOT DESKTOP_APP_DISABLE_DBUS_INTEGRATION)
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
desktop-app::external_statusnotifieritem
|
||||
desktop-app::external_dbusmenu_qt
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT DESKTOP_APP_DISABLE_X11_INTEGRATION)
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
desktop-app::external_xcb
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT DESKTOP_APP_DISABLE_WAYLAND_INTEGRATION)
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
desktop-app::lib_waylandshells
|
||||
desktop-app::external_kwayland
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT DESKTOP_APP_DISABLE_GTK_INTEGRATION)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
pkg_check_modules(GTK REQUIRED gtk+-3.0)
|
||||
target_include_directories(Telegram SYSTEM PRIVATE ${GTK_INCLUDE_DIRS})
|
||||
|
||||
if (NOT DESKTOP_APP_DISABLE_X11_INTEGRATION)
|
||||
target_link_libraries(Telegram PRIVATE X11)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (build_macstore)
|
||||
@@ -1338,10 +1315,6 @@ if (build_macstore)
|
||||
COMMAND mkdir -p $<TARGET_FILE_DIR:Telegram>/../Frameworks
|
||||
COMMAND cp -a ${libs_loc}/breakpad/src/client/mac/build/Release/Breakpad.framework $<TARGET_FILE_DIR:Telegram>/../Frameworks/Breakpad.framework
|
||||
)
|
||||
elseif (build_osx)
|
||||
set(bundle_identifier "com.tdesktop.Telegram$<$<CONFIG:Debug>:DebugOsx>")
|
||||
set(bundle_entitlements "Telegram.entitlements")
|
||||
set(output_name "Telegram")
|
||||
else()
|
||||
set(bundle_identifier "com.tdesktop.Telegram$<$<CONFIG:Debug>:Debug>")
|
||||
set(bundle_entitlements "Telegram.entitlements")
|
||||
@@ -1459,12 +1432,8 @@ if ((NOT DESKTOP_APP_DISABLE_AUTOUPDATE OR APPLE) AND NOT build_macstore AND NOT
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (LINUX)
|
||||
target_link_options(Updater PRIVATE -static-libstdc++)
|
||||
endif()
|
||||
|
||||
if (DESKTOP_APP_SPECIAL_TARGET)
|
||||
add_executable(Packer WIN32)
|
||||
add_executable(Packer)
|
||||
init_target(Packer)
|
||||
|
||||
add_dependencies(Telegram Packer)
|
||||
|
||||
@@ -1,651 +0,0 @@
|
||||
diff --git a/src/build/common.gypi b/src/build/common.gypi
|
||||
index 29990c65..53e99d44 100644
|
||||
--- a/src/build/common.gypi
|
||||
+++ b/src/build/common.gypi
|
||||
@@ -330,6 +330,7 @@
|
||||
'VCCLCompilerTool': {
|
||||
'WarnAsError': 'true',
|
||||
'Detect64BitPortabilityProblems': 'false',
|
||||
+ 'TreatWChar_tAsBuiltInType': 'false',
|
||||
},
|
||||
},
|
||||
}],
|
||||
diff --git a/src/client/mac/Breakpad.xcodeproj/project.pbxproj b/src/client/mac/Breakpad.xcodeproj/project.pbxproj
|
||||
index 1a93ce6d..b5986e33 100644
|
||||
--- a/src/client/mac/Breakpad.xcodeproj/project.pbxproj
|
||||
+++ b/src/client/mac/Breakpad.xcodeproj/project.pbxproj
|
||||
@@ -35,6 +35,19 @@
|
||||
/* End PBXAggregateTarget section */
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
+ 0748C0431C63C409004489BF /* MachIPC.mm in Sources */ = {isa = PBXBuildFile; fileRef = F92C53790ECCE635009BE4BA /* MachIPC.mm */; };
|
||||
+ 0748C0441C63C43C004489BF /* minidump_generator.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C536F0ECCE3FD009BE4BA /* minidump_generator.cc */; };
|
||||
+ 0748C0451C63C46C004489BF /* string_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53820ECCE635009BE4BA /* string_utilities.cc */; };
|
||||
+ 0748C0461C63C484004489BF /* minidump_file_writer.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C538F0ECCE70A009BE4BA /* minidump_file_writer.cc */; };
|
||||
+ 0748C0471C63C4A1004489BF /* dynamic_images.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C536B0ECCE3FD009BE4BA /* dynamic_images.cc */; };
|
||||
+ 0748C0491C63C4CF004489BF /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C537A0ECCE635009BE4BA /* macho_id.cc */; };
|
||||
+ 0748C04A1C63C4D4004489BF /* string_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53850ECCE6AD009BE4BA /* string_conversion.cc */; };
|
||||
+ 0748C04B1C63C4DB004489BF /* convert_UTF.c in Sources */ = {isa = PBXBuildFile; fileRef = F92C53870ECCE6C0009BE4BA /* convert_UTF.c */; };
|
||||
+ 0748C04C1C63C4EA004489BF /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C537C0ECCE635009BE4BA /* macho_utilities.cc */; };
|
||||
+ 0748C04D1C63C50F004489BF /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53740ECCE635009BE4BA /* file_id.cc */; };
|
||||
+ 0748C04E1C63C51C004489BF /* md5.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D72CA0D13DFAD5C006CABE3 /* md5.cc */; };
|
||||
+ 0748C04F1C63C523004489BF /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C537E0ECCE635009BE4BA /* macho_walker.cc */; };
|
||||
+ 0748C0501C63C52D004489BF /* bootstrap_compat.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D61A25D14F43CFC002D5862 /* bootstrap_compat.cc */; };
|
||||
162F64F2161C577500CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64F0161C577500CD68D5 /* arch_utilities.cc */; };
|
||||
162F64F3161C577500CD68D5 /* arch_utilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 162F64F1161C577500CD68D5 /* arch_utilities.h */; };
|
||||
162F64F4161C579B00CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64F0161C577500CD68D5 /* arch_utilities.cc */; };
|
||||
@@ -67,6 +80,7 @@
|
||||
4DBE49A7134A4F280072546A /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DBE4769134A4F080072546A /* CoreServices.framework */; };
|
||||
4DBE49A8134A4F380072546A /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DBE4769134A4F080072546A /* CoreServices.framework */; };
|
||||
4DBE49A9134A4F460072546A /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DBE4769134A4F080072546A /* CoreServices.framework */; };
|
||||
+ 5A8B220921E0C5740045F83C /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53690ECCE3FD009BE4BA /* breakpad_nlist_64.cc */; };
|
||||
8B3101C611F0CD9F00FCF3E4 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0867D6A5FE840307C02AAC07 /* AppKit.framework */; };
|
||||
8B3101C711F0CD9F00FCF3E4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0867D69BFE84028FC02AAC07 /* Foundation.framework */; };
|
||||
8B3101CA11F0CDB000FCF3E4 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0867D6A5FE840307C02AAC07 /* AppKit.framework */; };
|
||||
@@ -170,11 +184,8 @@
|
||||
F92C564A0ECD10CA009BE4BA /* string_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53850ECCE6AD009BE4BA /* string_conversion.cc */; };
|
||||
F92C564C0ECD10DD009BE4BA /* breakpadUtilities.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F92C563C0ECD10B3009BE4BA /* breakpadUtilities.dylib */; };
|
||||
F92C56570ECD113E009BE4BA /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F92C554A0ECCF530009BE4BA /* Carbon.framework */; };
|
||||
- F92C565C0ECD1158009BE4BA /* breakpadUtilities.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F92C563C0ECD10B3009BE4BA /* breakpadUtilities.dylib */; };
|
||||
F92C565F0ECD116B009BE4BA /* protected_memory_allocator.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53720ECCE3FD009BE4BA /* protected_memory_allocator.cc */; };
|
||||
F92C56630ECD1179009BE4BA /* exception_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C536D0ECCE3FD009BE4BA /* exception_handler.cc */; };
|
||||
- F92C56650ECD1185009BE4BA /* breakpadUtilities.dylib in Resources */ = {isa = PBXBuildFile; fileRef = F92C563C0ECD10B3009BE4BA /* breakpadUtilities.dylib */; };
|
||||
- F92C568A0ECD15F9009BE4BA /* Inspector in Resources */ = {isa = PBXBuildFile; fileRef = F92C53540ECCE349009BE4BA /* Inspector */; };
|
||||
F92C56A90ECE04C5009BE4BA /* crash_report_sender.m in Sources */ = {isa = PBXBuildFile; fileRef = F92C56A80ECE04C5009BE4BA /* crash_report_sender.m */; };
|
||||
F93803CD0F8083B7004D428B /* dynamic_images.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C536B0ECCE3FD009BE4BA /* dynamic_images.cc */; };
|
||||
F93803CE0F8083B7004D428B /* exception_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C536D0ECCE3FD009BE4BA /* exception_handler.cc */; };
|
||||
@@ -213,7 +224,6 @@
|
||||
F9C44DBD0EF072A0003AEBAA /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F9C44DBA0EF072A0003AEBAA /* MainMenu.xib */; };
|
||||
F9C44E000EF077CD003AEBAA /* Breakpad.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Breakpad.framework */; };
|
||||
F9C44E3C0EF08B12003AEBAA /* Breakpad.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Breakpad.framework */; };
|
||||
- F9C44E980EF09F56003AEBAA /* crash_report_sender.app in Resources */ = {isa = PBXBuildFile; fileRef = F92C56A00ECE04A7009BE4BA /* crash_report_sender.app */; };
|
||||
F9C44EA20EF09F93003AEBAA /* HTTPMultipartUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = F92C53770ECCE635009BE4BA /* HTTPMultipartUpload.m */; };
|
||||
F9C44EE50EF0A006003AEBAA /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9C44EE40EF0A006003AEBAA /* SystemConfiguration.framework */; };
|
||||
F9C44EE90EF0A3C1003AEBAA /* GTMLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = F9C44EE80EF0A3C1003AEBAA /* GTMLogger.m */; };
|
||||
@@ -410,20 +420,6 @@
|
||||
remoteGlobalIDString = F92C563B0ECD10B3009BE4BA;
|
||||
remoteInfo = breakpadUtilities;
|
||||
};
|
||||
- F92C56850ECD15EF009BE4BA /* PBXContainerItemProxy */ = {
|
||||
- isa = PBXContainerItemProxy;
|
||||
- containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
|
||||
- proxyType = 1;
|
||||
- remoteGlobalIDString = F92C563B0ECD10B3009BE4BA;
|
||||
- remoteInfo = breakpadUtilities;
|
||||
- };
|
||||
- F92C56870ECD15F1009BE4BA /* PBXContainerItemProxy */ = {
|
||||
- isa = PBXContainerItemProxy;
|
||||
- containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
|
||||
- proxyType = 1;
|
||||
- remoteGlobalIDString = F92C53530ECCE349009BE4BA;
|
||||
- remoteInfo = Inspector;
|
||||
- };
|
||||
F93DE2FB0F82C3C600608B94 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
|
||||
@@ -536,13 +532,6 @@
|
||||
remoteGlobalIDString = 8DC2EF4F0486A6940098B216;
|
||||
remoteInfo = Breakpad;
|
||||
};
|
||||
- F9C44E960EF09F4B003AEBAA /* PBXContainerItemProxy */ = {
|
||||
- isa = PBXContainerItemProxy;
|
||||
- containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
|
||||
- proxyType = 1;
|
||||
- remoteGlobalIDString = F92C569F0ECE04A7009BE4BA;
|
||||
- remoteInfo = crash_report_sender;
|
||||
- };
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@@ -714,7 +703,6 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
- F92C565C0ECD1158009BE4BA /* breakpadUtilities.dylib in Frameworks */,
|
||||
8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -1181,18 +1169,13 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "Breakpad" */;
|
||||
buildPhases = (
|
||||
- F97A0E850ED4EC15008784D3 /* Change install name of breakpadUtilities */,
|
||||
8DC2EF500486A6940098B216 /* Headers */,
|
||||
- 8DC2EF520486A6940098B216 /* Resources */,
|
||||
8DC2EF540486A6940098B216 /* Sources */,
|
||||
8DC2EF560486A6940098B216 /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
- F92C56860ECD15EF009BE4BA /* PBXTargetDependency */,
|
||||
- F92C56880ECD15F1009BE4BA /* PBXTargetDependency */,
|
||||
- F9C44E970EF09F4B003AEBAA /* PBXTargetDependency */,
|
||||
);
|
||||
name = Breakpad;
|
||||
productInstallPath = "$(HOME)/Library/Frameworks";
|
||||
@@ -1399,6 +1382,8 @@
|
||||
/* Begin PBXProject section */
|
||||
0867D690FE84028FC02AAC07 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
+ attributes = {
|
||||
+ };
|
||||
buildConfigurationList = 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "Breakpad" */;
|
||||
compatibilityVersion = "Xcode 3.1";
|
||||
developmentRegion = English;
|
||||
@@ -1583,16 +1568,6 @@
|
||||
/* End PBXReferenceProxy section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
- 8DC2EF520486A6940098B216 /* Resources */ = {
|
||||
- isa = PBXResourcesBuildPhase;
|
||||
- buildActionMask = 2147483647;
|
||||
- files = (
|
||||
- F9C44E980EF09F56003AEBAA /* crash_report_sender.app in Resources */,
|
||||
- F92C568A0ECD15F9009BE4BA /* Inspector in Resources */,
|
||||
- F92C56650ECD1185009BE4BA /* breakpadUtilities.dylib in Resources */,
|
||||
- );
|
||||
- runOnlyForDeploymentPostprocessing = 0;
|
||||
- };
|
||||
F92C569C0ECE04A7009BE4BA /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -1640,20 +1615,6 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "install_name_tool -id \"@executable_path/../Resources/breakpadUtilities.dylib\" \"${BUILT_PRODUCTS_DIR}/breakpadUtilities.dylib\"\n";
|
||||
};
|
||||
- F97A0E850ED4EC15008784D3 /* Change install name of breakpadUtilities */ = {
|
||||
- isa = PBXShellScriptBuildPhase;
|
||||
- buildActionMask = 2147483647;
|
||||
- files = (
|
||||
- );
|
||||
- inputPaths = (
|
||||
- );
|
||||
- name = "Change install name of breakpadUtilities";
|
||||
- outputPaths = (
|
||||
- );
|
||||
- runOnlyForDeploymentPostprocessing = 0;
|
||||
- shellPath = /bin/sh;
|
||||
- shellScript = "#!/bin/bash\ninstall_name_tool -id \"@executable_path/../Frameworks/Breakpad.framework/Resources/breakpadUtilities.dylib\" \"${BUILT_PRODUCTS_DIR}/breakpadUtilities.dylib\"\n";
|
||||
- };
|
||||
F9C77DD80F7DD5CF0045F7DB /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -1674,6 +1635,20 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
+ 5A8B220921E0C5740045F83C /* breakpad_nlist_64.cc in Sources */,
|
||||
+ 0748C0501C63C52D004489BF /* bootstrap_compat.cc in Sources */,
|
||||
+ 0748C04F1C63C523004489BF /* macho_walker.cc in Sources */,
|
||||
+ 0748C04E1C63C51C004489BF /* md5.cc in Sources */,
|
||||
+ 0748C04D1C63C50F004489BF /* file_id.cc in Sources */,
|
||||
+ 0748C04C1C63C4EA004489BF /* macho_utilities.cc in Sources */,
|
||||
+ 0748C04B1C63C4DB004489BF /* convert_UTF.c in Sources */,
|
||||
+ 0748C04A1C63C4D4004489BF /* string_conversion.cc in Sources */,
|
||||
+ 0748C0491C63C4CF004489BF /* macho_id.cc in Sources */,
|
||||
+ 0748C0471C63C4A1004489BF /* dynamic_images.cc in Sources */,
|
||||
+ 0748C0461C63C484004489BF /* minidump_file_writer.cc in Sources */,
|
||||
+ 0748C0451C63C46C004489BF /* string_utilities.cc in Sources */,
|
||||
+ 0748C0441C63C43C004489BF /* minidump_generator.cc in Sources */,
|
||||
+ 0748C0431C63C409004489BF /* MachIPC.mm in Sources */,
|
||||
F92C565F0ECD116B009BE4BA /* protected_memory_allocator.cc in Sources */,
|
||||
F92C56630ECD1179009BE4BA /* exception_handler.cc in Sources */,
|
||||
F92C55D10ECD0064009BE4BA /* Breakpad.mm in Sources */,
|
||||
@@ -1955,16 +1930,6 @@
|
||||
target = F92C563B0ECD10B3009BE4BA /* breakpadUtilities */;
|
||||
targetProxy = F92C564D0ECD10E5009BE4BA /* PBXContainerItemProxy */;
|
||||
};
|
||||
- F92C56860ECD15EF009BE4BA /* PBXTargetDependency */ = {
|
||||
- isa = PBXTargetDependency;
|
||||
- target = F92C563B0ECD10B3009BE4BA /* breakpadUtilities */;
|
||||
- targetProxy = F92C56850ECD15EF009BE4BA /* PBXContainerItemProxy */;
|
||||
- };
|
||||
- F92C56880ECD15F1009BE4BA /* PBXTargetDependency */ = {
|
||||
- isa = PBXTargetDependency;
|
||||
- target = F92C53530ECCE349009BE4BA /* Inspector */;
|
||||
- targetProxy = F92C56870ECD15F1009BE4BA /* PBXContainerItemProxy */;
|
||||
- };
|
||||
F93DE2FC0F82C3C600608B94 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = F93803BD0F80820F004D428B /* generator_test */;
|
||||
@@ -2025,11 +1990,6 @@
|
||||
target = 8DC2EF4F0486A6940098B216 /* Breakpad */;
|
||||
targetProxy = F9C44E190EF0790F003AEBAA /* PBXContainerItemProxy */;
|
||||
};
|
||||
- F9C44E970EF09F4B003AEBAA /* PBXTargetDependency */ = {
|
||||
- isa = PBXTargetDependency;
|
||||
- target = F92C569F0ECE04A7009BE4BA /* crash_report_sender */;
|
||||
- targetProxy = F9C44E960EF09F4B003AEBAA /* PBXContainerItemProxy */;
|
||||
- };
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
@@ -2126,8 +2086,12 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 8B31027711F0D3AF00FCF3E4 /* BreakpadDebug.xcconfig */;
|
||||
buildSettings = {
|
||||
+ CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
|
||||
+ CLANG_CXX_LIBRARY = "libc++";
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
|
||||
- SDKROOT = macosx10.5;
|
||||
+ GCC_VERSION = "";
|
||||
+ MACOSX_DEPLOYMENT_TARGET = 10.8;
|
||||
+ SDKROOT = macosx;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -2135,7 +2099,12 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 8B31027811F0D3AF00FCF3E4 /* BreakpadRelease.xcconfig */;
|
||||
buildSettings = {
|
||||
+ CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
|
||||
+ CLANG_CXX_LIBRARY = "libc++";
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
|
||||
+ GCC_VERSION = "";
|
||||
+ MACOSX_DEPLOYMENT_TARGET = 10.8;
|
||||
+ SDKROOT = macosx;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -2454,7 +2423,12 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 8B31027711F0D3AF00FCF3E4 /* BreakpadDebug.xcconfig */;
|
||||
buildSettings = {
|
||||
+ CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
|
||||
+ CLANG_CXX_LIBRARY = "libc++";
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
|
||||
+ GCC_VERSION = "";
|
||||
+ MACOSX_DEPLOYMENT_TARGET = 10.8;
|
||||
+ SDKROOT = macosx;
|
||||
};
|
||||
name = "Debug With Code Coverage";
|
||||
};
|
||||
diff --git a/src/client/mac/Framework/Breakpad.mm b/src/client/mac/Framework/Breakpad.mm
|
||||
index 1d2e519b..943310fa 100644
|
||||
--- a/src/client/mac/Framework/Breakpad.mm
|
||||
+++ b/src/client/mac/Framework/Breakpad.mm
|
||||
@@ -355,10 +355,10 @@ bool Breakpad::Initialize(NSDictionary *parameters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
- if ([[parameters objectForKey:@BREAKPAD_IN_PROCESS] boolValue])
|
||||
+// if ([[parameters objectForKey:@BREAKPAD_IN_PROCESS] boolValue])
|
||||
return InitializeInProcess(parameters);
|
||||
- else
|
||||
- return InitializeOutOfProcess(parameters);
|
||||
+// else
|
||||
+// return InitializeOutOfProcess(parameters);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
@@ -373,52 +373,52 @@ bool Breakpad::InitializeInProcess(NSDictionary* parameters) {
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
-bool Breakpad::InitializeOutOfProcess(NSDictionary* parameters) {
|
||||
- // Get path to Inspector executable.
|
||||
- NSString *inspectorPathString = KeyValue(@BREAKPAD_INSPECTOR_LOCATION);
|
||||
-
|
||||
- // Standardize path (resolve symlinkes, etc.) and escape spaces
|
||||
- inspectorPathString = [inspectorPathString stringByStandardizingPath];
|
||||
- inspectorPathString = [[inspectorPathString componentsSeparatedByString:@" "]
|
||||
- componentsJoinedByString:@"\\ "];
|
||||
-
|
||||
- // Create an on-demand server object representing the Inspector.
|
||||
- // In case of a crash, we simply need to call the LaunchOnDemand()
|
||||
- // method on it, then send a mach message to its service port.
|
||||
- // It will then launch and perform a process inspection of our crashed state.
|
||||
- // See the HandleException() method for the details.
|
||||
-#define RECEIVE_PORT_NAME "com.Breakpad.Inspector"
|
||||
-
|
||||
- name_t portName;
|
||||
- snprintf(portName, sizeof(name_t), "%s%d", RECEIVE_PORT_NAME, getpid());
|
||||
-
|
||||
- // Save the location of the Inspector
|
||||
- strlcpy(inspector_path_, [inspectorPathString fileSystemRepresentation],
|
||||
- sizeof(inspector_path_));
|
||||
-
|
||||
- // Append a single command-line argument to the Inspector path
|
||||
- // representing the bootstrap name of the launch-on-demand receive port.
|
||||
- // When the Inspector is launched, it can use this to lookup the port
|
||||
- // by calling bootstrap_check_in().
|
||||
- strlcat(inspector_path_, " ", sizeof(inspector_path_));
|
||||
- strlcat(inspector_path_, portName, sizeof(inspector_path_));
|
||||
-
|
||||
- kern_return_t kr = inspector_.Initialize(inspector_path_,
|
||||
- portName,
|
||||
- true); // shutdown on exit
|
||||
-
|
||||
- if (kr != KERN_SUCCESS) {
|
||||
- return false;
|
||||
- }
|
||||
-
|
||||
- // Create the handler (allocating it in our special protected pool)
|
||||
- handler_ =
|
||||
- new (gBreakpadAllocator->Allocate(
|
||||
- sizeof(google_breakpad::ExceptionHandler)))
|
||||
- google_breakpad::ExceptionHandler(
|
||||
- Breakpad::ExceptionHandlerDirectCallback, this, true);
|
||||
- return true;
|
||||
-}
|
||||
+//bool Breakpad::InitializeOutOfProcess(NSDictionary* parameters) {
|
||||
+// // Get path to Inspector executable.
|
||||
+// NSString *inspectorPathString = KeyValue(@BREAKPAD_INSPECTOR_LOCATION);
|
||||
+//
|
||||
+// // Standardize path (resolve symlinkes, etc.) and escape spaces
|
||||
+// inspectorPathString = [inspectorPathString stringByStandardizingPath];
|
||||
+// inspectorPathString = [[inspectorPathString componentsSeparatedByString:@" "]
|
||||
+// componentsJoinedByString:@"\\ "];
|
||||
+//
|
||||
+// // Create an on-demand server object representing the Inspector.
|
||||
+// // In case of a crash, we simply need to call the LaunchOnDemand()
|
||||
+// // method on it, then send a mach message to its service port.
|
||||
+// // It will then launch and perform a process inspection of our crashed state.
|
||||
+// // See the HandleException() method for the details.
|
||||
+//#define RECEIVE_PORT_NAME "com.Breakpad.Inspector"
|
||||
+//
|
||||
+// name_t portName;
|
||||
+// snprintf(portName, sizeof(name_t), "%s%d", RECEIVE_PORT_NAME, getpid());
|
||||
+//
|
||||
+// // Save the location of the Inspector
|
||||
+// strlcpy(inspector_path_, [inspectorPathString fileSystemRepresentation],
|
||||
+// sizeof(inspector_path_));
|
||||
+//
|
||||
+// // Append a single command-line argument to the Inspector path
|
||||
+// // representing the bootstrap name of the launch-on-demand receive port.
|
||||
+// // When the Inspector is launched, it can use this to lookup the port
|
||||
+// // by calling bootstrap_check_in().
|
||||
+// strlcat(inspector_path_, " ", sizeof(inspector_path_));
|
||||
+// strlcat(inspector_path_, portName, sizeof(inspector_path_));
|
||||
+//
|
||||
+// kern_return_t kr = inspector_.Initialize(inspector_path_,
|
||||
+// portName,
|
||||
+// true); // shutdown on exit
|
||||
+//
|
||||
+// if (kr != KERN_SUCCESS) {
|
||||
+// return false;
|
||||
+// }
|
||||
+//
|
||||
+// // Create the handler (allocating it in our special protected pool)
|
||||
+// handler_ =
|
||||
+// new (gBreakpadAllocator->Allocate(
|
||||
+// sizeof(google_breakpad::ExceptionHandler)))
|
||||
+// google_breakpad::ExceptionHandler(
|
||||
+// Breakpad::ExceptionHandlerDirectCallback, this, true);
|
||||
+// return true;
|
||||
+//}
|
||||
|
||||
//=============================================================================
|
||||
Breakpad::~Breakpad() {
|
||||
@@ -445,10 +445,10 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) {
|
||||
NSString *version = [parameters objectForKey:@BREAKPAD_VERSION];
|
||||
NSString *urlStr = [parameters objectForKey:@BREAKPAD_URL];
|
||||
NSString *interval = [parameters objectForKey:@BREAKPAD_REPORT_INTERVAL];
|
||||
- NSString *inspectorPathString =
|
||||
- [parameters objectForKey:@BREAKPAD_INSPECTOR_LOCATION];
|
||||
- NSString *reporterPathString =
|
||||
- [parameters objectForKey:@BREAKPAD_REPORTER_EXE_LOCATION];
|
||||
+// NSString *inspectorPathString =
|
||||
+// [parameters objectForKey:@BREAKPAD_INSPECTOR_LOCATION];
|
||||
+// NSString *reporterPathString =
|
||||
+// [parameters objectForKey:@BREAKPAD_REPORTER_EXE_LOCATION];
|
||||
NSString *timeout = [parameters objectForKey:@BREAKPAD_CONFIRM_TIMEOUT];
|
||||
NSArray *logFilePaths = [parameters objectForKey:@BREAKPAD_LOGFILES];
|
||||
NSString *logFileTailSize =
|
||||
@@ -536,39 +536,39 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) {
|
||||
}
|
||||
|
||||
// Find the helper applications if not specified in user config.
|
||||
- NSString *resourcePath = nil;
|
||||
- if (!inspectorPathString || !reporterPathString) {
|
||||
- resourcePath = GetResourcePath();
|
||||
- if (!resourcePath) {
|
||||
- return false;
|
||||
- }
|
||||
- }
|
||||
+// NSString *resourcePath = nil;
|
||||
+// if (!inspectorPathString || !reporterPathString) {
|
||||
+// resourcePath = GetResourcePath();
|
||||
+// if (!resourcePath) {
|
||||
+// return false;
|
||||
+// }
|
||||
+// }
|
||||
|
||||
// Find Inspector.
|
||||
- if (!inspectorPathString) {
|
||||
- inspectorPathString =
|
||||
- [resourcePath stringByAppendingPathComponent:@"Inspector"];
|
||||
- }
|
||||
-
|
||||
- // Verify that there is an Inspector tool.
|
||||
- if (![[NSFileManager defaultManager] fileExistsAtPath:inspectorPathString]) {
|
||||
- return false;
|
||||
- }
|
||||
+// if (!inspectorPathString) {
|
||||
+// inspectorPathString =
|
||||
+// [resourcePath stringByAppendingPathComponent:@"Inspector"];
|
||||
+// }
|
||||
+//
|
||||
+// // Verify that there is an Inspector tool.
|
||||
+// if (![[NSFileManager defaultManager] fileExistsAtPath:inspectorPathString]) {
|
||||
+// return false;
|
||||
+// }
|
||||
|
||||
// Find Reporter.
|
||||
- if (!reporterPathString) {
|
||||
- reporterPathString =
|
||||
- [resourcePath
|
||||
- stringByAppendingPathComponent:@"crash_report_sender.app"];
|
||||
- reporterPathString =
|
||||
- [[NSBundle bundleWithPath:reporterPathString] executablePath];
|
||||
- }
|
||||
+// if (!reporterPathString) {
|
||||
+// reporterPathString =
|
||||
+// [resourcePath
|
||||
+// stringByAppendingPathComponent:@"crash_report_sender.app"];
|
||||
+// reporterPathString =
|
||||
+// [[NSBundle bundleWithPath:reporterPathString] executablePath];
|
||||
+// }
|
||||
|
||||
// Verify that there is a Reporter application.
|
||||
- if (![[NSFileManager defaultManager]
|
||||
- fileExistsAtPath:reporterPathString]) {
|
||||
- return false;
|
||||
- }
|
||||
+// if (![[NSFileManager defaultManager]
|
||||
+// fileExistsAtPath:reporterPathString]) {
|
||||
+// return false;
|
||||
+// }
|
||||
|
||||
if (!dumpSubdirectory) {
|
||||
dumpSubdirectory = @"";
|
||||
@@ -601,10 +601,10 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) {
|
||||
dictionary.SetKeyValue(BREAKPAD_REPORT_INTERVAL, [interval UTF8String]);
|
||||
dictionary.SetKeyValue(BREAKPAD_SKIP_CONFIRM, [skipConfirm UTF8String]);
|
||||
dictionary.SetKeyValue(BREAKPAD_CONFIRM_TIMEOUT, [timeout UTF8String]);
|
||||
- dictionary.SetKeyValue(BREAKPAD_INSPECTOR_LOCATION,
|
||||
- [inspectorPathString fileSystemRepresentation]);
|
||||
- dictionary.SetKeyValue(BREAKPAD_REPORTER_EXE_LOCATION,
|
||||
- [reporterPathString fileSystemRepresentation]);
|
||||
+// dictionary.SetKeyValue(BREAKPAD_INSPECTOR_LOCATION,
|
||||
+// [inspectorPathString fileSystemRepresentation]);
|
||||
+// dictionary.SetKeyValue(BREAKPAD_REPORTER_EXE_LOCATION,
|
||||
+// [reporterPathString fileSystemRepresentation]);
|
||||
dictionary.SetKeyValue(BREAKPAD_LOGFILE_UPLOAD_SIZE,
|
||||
[logFileTailSize UTF8String]);
|
||||
dictionary.SetKeyValue(BREAKPAD_REQUEST_COMMENTS,
|
||||
@@ -762,9 +762,9 @@ bool Breakpad::HandleException(int exception_type,
|
||||
bool Breakpad::HandleMinidump(const char *dump_dir, const char *minidump_id) {
|
||||
google_breakpad::ConfigFile config_file;
|
||||
config_file.WriteFile(dump_dir, config_params_, dump_dir, minidump_id);
|
||||
- google_breakpad::LaunchReporter(
|
||||
- config_params_->GetValueForKey(BREAKPAD_REPORTER_EXE_LOCATION),
|
||||
- config_file.GetFilePath());
|
||||
+// google_breakpad::LaunchReporter(
|
||||
+// config_params_->GetValueForKey(BREAKPAD_REPORTER_EXE_LOCATION),
|
||||
+// config_file.GetFilePath());
|
||||
return true;
|
||||
}
|
||||
|
||||
diff --git a/src/common/language.cc b/src/common/language.cc
|
||||
index 978fb855..a95ae5f7 100644
|
||||
--- a/src/common/language.cc
|
||||
+++ b/src/common/language.cc
|
||||
@@ -46,8 +46,27 @@
|
||||
|
||||
#include <limits>
|
||||
|
||||
+#include <cstdio>
|
||||
+#include <iostream>
|
||||
+#include <memory>
|
||||
+#include <stdexcept>
|
||||
+#include <string>
|
||||
+#include <array>
|
||||
+
|
||||
namespace {
|
||||
|
||||
+std::string exec(std::string cmd) {
|
||||
+ std::array<char, 128> buffer;
|
||||
+ std::string result;
|
||||
+ std::shared_ptr<FILE> pipe(popen(cmd.c_str(), "r"), pclose);
|
||||
+ if (!pipe) throw std::runtime_error("popen() failed!");
|
||||
+ while (!feof(pipe.get())) {
|
||||
+ if (fgets(buffer.data(), 128, pipe.get()) != nullptr)
|
||||
+ result += buffer.data();
|
||||
+ }
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
string MakeQualifiedNameWithSeparator(const string& parent_name,
|
||||
const char* separator,
|
||||
const string& name) {
|
||||
@@ -79,11 +98,29 @@ class CPPLanguage: public Language {
|
||||
demangled->clear();
|
||||
return kDontDemangle;
|
||||
#else
|
||||
+ DemangleResult result;
|
||||
+ if (mangled.find("type_erased_handlers") != std::string::npos
|
||||
+ && mangled.find("vtable_once_impl") != std::string::npos) {
|
||||
+
|
||||
+ auto demangled_str = exec("c++filt " + mangled);
|
||||
+ if (!demangled_str.empty() && demangled_str.back() == '\n') {
|
||||
+ demangled_str.pop_back();
|
||||
+ }
|
||||
+ if (demangled_str != mangled) {
|
||||
+ result = kDemangleSuccess;
|
||||
+ demangled->assign(demangled_str.c_str());
|
||||
+ } else {
|
||||
+ result = kDemangleFailure;
|
||||
+ demangled->clear();
|
||||
+ }
|
||||
+
|
||||
+ } else {
|
||||
+
|
||||
int status;
|
||||
char* demangled_c =
|
||||
abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status);
|
||||
|
||||
- DemangleResult result;
|
||||
+// DemangleResult result;
|
||||
if (status == 0) {
|
||||
result = kDemangleSuccess;
|
||||
demangled->assign(demangled_c);
|
||||
@@ -96,6 +133,8 @@ class CPPLanguage: public Language {
|
||||
free(reinterpret_cast<void*>(demangled_c));
|
||||
}
|
||||
|
||||
+ }
|
||||
+
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
diff --git a/src/common/linux/elf_symbols_to_module.cc b/src/common/linux/elf_symbols_to_module.cc
|
||||
index 562875e1..43678510 100644
|
||||
--- a/src/common/linux/elf_symbols_to_module.cc
|
||||
+++ b/src/common/linux/elf_symbols_to_module.cc
|
||||
@@ -39,6 +39,29 @@
|
||||
#include "common/byte_cursor.h"
|
||||
#include "common/module.h"
|
||||
|
||||
+#include <cstdio>
|
||||
+#include <iostream>
|
||||
+#include <memory>
|
||||
+#include <stdexcept>
|
||||
+#include <string>
|
||||
+#include <array>
|
||||
+
|
||||
+namespace {
|
||||
+
|
||||
+std::string exec(std::string cmd) {
|
||||
+ std::array<char, 128> buffer;
|
||||
+ std::string result;
|
||||
+ std::shared_ptr<FILE> pipe(popen(cmd.c_str(), "r"), pclose);
|
||||
+ if (!pipe) throw std::runtime_error("popen() failed!");
|
||||
+ while (!feof(pipe.get())) {
|
||||
+ if (fgets(buffer.data(), 128, pipe.get()) != nullptr)
|
||||
+ result += buffer.data();
|
||||
+ }
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+}
|
||||
+
|
||||
namespace google_breakpad {
|
||||
|
||||
class ELFSymbolIterator {
|
||||
@@ -159,6 +182,19 @@ bool ELFSymbolsToModule(const uint8_t *symtab_section,
|
||||
Module::Extern *ext = new Module::Extern(iterator->value);
|
||||
ext->name = SymbolString(iterator->name_offset, strings);
|
||||
#if !defined(__ANDROID__) // Android NDK doesn't provide abi::__cxa_demangle.
|
||||
+ if (ext->name.find("type_erased_handlers") != std::string::npos
|
||||
+ && ext->name.find("vtable_once_impl") != std::string::npos) {
|
||||
+
|
||||
+ auto demangled_str = exec("c++filt " + ext->name);
|
||||
+ if (!demangled_str.empty() && demangled_str.back() == '\n') {
|
||||
+ demangled_str.pop_back();
|
||||
+ }
|
||||
+ if (demangled_str != ext->name) {
|
||||
+ ext->name = demangled_str;
|
||||
+ }
|
||||
+
|
||||
+ } else {
|
||||
+
|
||||
int status = 0;
|
||||
char* demangled =
|
||||
abi::__cxa_demangle(ext->name.c_str(), NULL, NULL, &status);
|
||||
@@ -167,6 +203,8 @@ bool ELFSymbolsToModule(const uint8_t *symtab_section,
|
||||
ext->name = demangled;
|
||||
free(demangled);
|
||||
}
|
||||
+
|
||||
+ }
|
||||
#endif
|
||||
module->AddExtern(ext);
|
||||
}
|
||||
diff --git a/src/tools/linux/tools_linux.gypi b/src/tools/linux/tools_linux.gypi
|
||||
index 1c15992e..020e4c1c 100644
|
||||
--- a/src/tools/linux/tools_linux.gypi
|
||||
+++ b/src/tools/linux/tools_linux.gypi
|
||||
@@ -58,7 +58,7 @@
|
||||
'target_name': 'minidump_upload',
|
||||
'type': 'executable',
|
||||
'sources': [
|
||||
- 'symupload/minidump_upload.m',
|
||||
+ 'symupload/minidump_upload.cc',
|
||||
],
|
||||
'dependencies': [
|
||||
'../common/common.gyp:common',
|
||||
diff --git a/src/tools/mac/dump_syms/macho_dump.cc b/src/tools/mac/dump_syms/macho_dump.cc
|
||||
index d882bbe8..3432bb45 100644
|
||||
--- a/src/tools/mac/dump_syms/macho_dump.cc
|
||||
+++ b/src/tools/mac/dump_syms/macho_dump.cc
|
||||
@@ -140,7 +140,7 @@ void DumpFile(const char *filename) {
|
||||
size_t object_files_size;
|
||||
const SuperFatArch* super_fat_object_files =
|
||||
fat_reader.object_files(&object_files_size);
|
||||
- struct fat_arch *object_files;
|
||||
+ struct fat_arch *object_files = 0;
|
||||
if (!super_fat_object_files->ConvertToFatArch(object_files)) {
|
||||
exit(1);
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
set -e
|
||||
FullExecPath=$PWD
|
||||
pushd `dirname $0` > /dev/null
|
||||
FullScriptPath=`pwd`
|
||||
popd > /dev/null
|
||||
|
||||
pacman --noconfirm -Sy
|
||||
pacman --noconfirm -S msys/make
|
||||
pacman --noconfirm -S mingw64/mingw-w64-x86_64-opus
|
||||
pacman --noconfirm -S diffutils
|
||||
pacman --noconfirm -S pkg-config
|
||||
|
||||
PKG_CONFIG_PATH="/mingw64/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
|
||||
./configure --toolchain=msvc \
|
||||
--extra-cflags="-DCONFIG_SAFE_BITSTREAM_READER=1" \
|
||||
--extra-cxxflags="-DCONFIG_SAFE_BITSTREAM_READER=1" \
|
||||
--extra-ldflags="-libpath:$FullExecPath/../opus/win32/VS2015/Win32/Release" \
|
||||
--disable-programs \
|
||||
--disable-doc \
|
||||
--disable-network \
|
||||
--disable-everything \
|
||||
--enable-hwaccel=h264_d3d11va \
|
||||
--enable-hwaccel=h264_d3d11va2 \
|
||||
--enable-hwaccel=h264_dxva2 \
|
||||
--enable-hwaccel=hevc_d3d11va \
|
||||
--enable-hwaccel=hevc_d3d11va2 \
|
||||
--enable-hwaccel=hevc_dxva2 \
|
||||
--enable-hwaccel=mpeg2_d3d11va \
|
||||
--enable-hwaccel=mpeg2_d3d11va2 \
|
||||
--enable-hwaccel=mpeg2_dxva2 \
|
||||
--enable-protocol=file --enable-libopus \
|
||||
--enable-decoder=aac \
|
||||
--enable-decoder=aac_at \
|
||||
--enable-decoder=aac_fixed \
|
||||
--enable-decoder=aac_latm \
|
||||
--enable-decoder=aasc \
|
||||
--enable-decoder=alac \
|
||||
--enable-decoder=alac_at \
|
||||
--enable-decoder=flac \
|
||||
--enable-decoder=gif \
|
||||
--enable-decoder=h264 \
|
||||
--enable-decoder=hevc \
|
||||
--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=msmpeg4v2 \
|
||||
--enable-decoder=msmpeg4v3 \
|
||||
--enable-decoder=opus \
|
||||
--enable-decoder=pcm_alaw \
|
||||
--enable-decoder=pcm_alaw_at \
|
||||
--enable-decoder=pcm_f32be \
|
||||
--enable-decoder=pcm_f32le \
|
||||
--enable-decoder=pcm_f64be \
|
||||
--enable-decoder=pcm_f64le \
|
||||
--enable-decoder=pcm_lxf \
|
||||
--enable-decoder=pcm_mulaw \
|
||||
--enable-decoder=pcm_mulaw_at \
|
||||
--enable-decoder=pcm_s16be \
|
||||
--enable-decoder=pcm_s16be_planar \
|
||||
--enable-decoder=pcm_s16le \
|
||||
--enable-decoder=pcm_s16le_planar \
|
||||
--enable-decoder=pcm_s24be \
|
||||
--enable-decoder=pcm_s24daud \
|
||||
--enable-decoder=pcm_s24le \
|
||||
--enable-decoder=pcm_s24le_planar \
|
||||
--enable-decoder=pcm_s32be \
|
||||
--enable-decoder=pcm_s32le \
|
||||
--enable-decoder=pcm_s32le_planar \
|
||||
--enable-decoder=pcm_s64be \
|
||||
--enable-decoder=pcm_s64le \
|
||||
--enable-decoder=pcm_s8 \
|
||||
--enable-decoder=pcm_s8_planar \
|
||||
--enable-decoder=pcm_u16be \
|
||||
--enable-decoder=pcm_u16le \
|
||||
--enable-decoder=pcm_u24be \
|
||||
--enable-decoder=pcm_u24le \
|
||||
--enable-decoder=pcm_u32be \
|
||||
--enable-decoder=pcm_u32le \
|
||||
--enable-decoder=pcm_u8 \
|
||||
--enable-decoder=pcm_zork \
|
||||
--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-parser=aac \
|
||||
--enable-parser=aac_latm \
|
||||
--enable-parser=flac \
|
||||
--enable-parser=h264 \
|
||||
--enable-parser=hevc \
|
||||
--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=hevc \
|
||||
--enable-demuxer=m4v \
|
||||
--enable-demuxer=mov \
|
||||
--enable-demuxer=mp3 \
|
||||
--enable-demuxer=ogg \
|
||||
--enable-demuxer=wav \
|
||||
--enable-muxer=ogg \
|
||||
--enable-muxer=opus
|
||||
|
||||
make -j4
|
||||
make -j4 install
|
||||
@@ -1,107 +0,0 @@
|
||||
diff --git a/client/capture_context_mac_test.cc b/client/capture_context_mac_test.cc
|
||||
index 436ac5ad..8e14fb9c 100644
|
||||
--- a/client/capture_context_mac_test.cc
|
||||
+++ b/client/capture_context_mac_test.cc
|
||||
@@ -34,11 +34,11 @@ namespace {
|
||||
// gtest assertions.
|
||||
void SanityCheckContext(const NativeCPUContext& context) {
|
||||
#if defined(ARCH_CPU_X86)
|
||||
- ASSERT_EQ(x86_THREAD_STATE32, context.tsh.flavor);
|
||||
- ASSERT_EQ(implicit_cast<int>(x86_THREAD_STATE32_COUNT), context.tsh.count);
|
||||
+ ASSERT_EQ(implicit_cast<thread_state_flavor_t>(x86_THREAD_STATE32), implicit_cast<thread_state_flavor_t>(context.tsh.flavor));
|
||||
+ ASSERT_EQ(implicit_cast<uint32_t>(x86_THREAD_STATE32_COUNT), implicit_cast<uint32_t>(context.tsh.count));
|
||||
#elif defined(ARCH_CPU_X86_64)
|
||||
- ASSERT_EQ(x86_THREAD_STATE64, context.tsh.flavor);
|
||||
- ASSERT_EQ(implicit_cast<int>(x86_THREAD_STATE64_COUNT), context.tsh.count);
|
||||
+ ASSERT_EQ(implicit_cast<thread_state_flavor_t>(x86_THREAD_STATE64), implicit_cast<thread_state_flavor_t>(context.tsh.flavor));
|
||||
+ ASSERT_EQ(implicit_cast<uint32_t>(x86_THREAD_STATE64_COUNT), implicit_cast<uint32_t>(context.tsh.count));
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_CPU_X86_FAMILY)
|
||||
diff --git a/client/simulate_crash_mac.cc b/client/simulate_crash_mac.cc
|
||||
index 7e279015..27864388 100644
|
||||
--- a/client/simulate_crash_mac.cc
|
||||
+++ b/client/simulate_crash_mac.cc
|
||||
@@ -177,12 +177,12 @@ bool DeliverException(thread_t thread,
|
||||
|
||||
void SimulateCrash(const NativeCPUContext& cpu_context) {
|
||||
#if defined(ARCH_CPU_X86)
|
||||
- DCHECK_EQ(cpu_context.tsh.flavor,
|
||||
+ DCHECK_EQ(implicit_cast<thread_state_flavor_t>(cpu_context.tsh.flavor),
|
||||
implicit_cast<thread_state_flavor_t>(x86_THREAD_STATE32));
|
||||
DCHECK_EQ(implicit_cast<mach_msg_type_number_t>(cpu_context.tsh.count),
|
||||
x86_THREAD_STATE32_COUNT);
|
||||
#elif defined(ARCH_CPU_X86_64)
|
||||
- DCHECK_EQ(cpu_context.tsh.flavor,
|
||||
+ DCHECK_EQ(implicit_cast<thread_state_flavor_t>(cpu_context.tsh.flavor),
|
||||
implicit_cast<thread_state_flavor_t>(x86_THREAD_STATE64));
|
||||
DCHECK_EQ(implicit_cast<mach_msg_type_number_t>(cpu_context.tsh.count),
|
||||
x86_THREAD_STATE64_COUNT);
|
||||
diff --git a/client/simulate_crash_mac_test.cc b/client/simulate_crash_mac_test.cc
|
||||
index 87c5f845..ca813e4c 100644
|
||||
--- a/client/simulate_crash_mac_test.cc
|
||||
+++ b/client/simulate_crash_mac_test.cc
|
||||
@@ -130,12 +130,12 @@ class TestSimulateCrashMac final : public MachMultiprocess,
|
||||
reinterpret_cast<const x86_thread_state*>(old_state);
|
||||
switch (state->tsh.flavor) {
|
||||
case x86_THREAD_STATE32:
|
||||
- EXPECT_EQ(implicit_cast<int>(x86_THREAD_STATE32_COUNT),
|
||||
- state->tsh.count);
|
||||
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_THREAD_STATE32_COUNT),
|
||||
+ implicit_cast<uint32_t>(state->tsh.count));
|
||||
break;
|
||||
case x86_THREAD_STATE64:
|
||||
- EXPECT_EQ(implicit_cast<int>(x86_THREAD_STATE64_COUNT),
|
||||
- state->tsh.count);
|
||||
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_THREAD_STATE64_COUNT),
|
||||
+ implicit_cast<uint32_t>(state->tsh.count));
|
||||
break;
|
||||
default:
|
||||
ADD_FAILURE() << "unexpected tsh.flavor " << state->tsh.flavor;
|
||||
@@ -149,12 +149,12 @@ class TestSimulateCrashMac final : public MachMultiprocess,
|
||||
reinterpret_cast<const x86_float_state*>(old_state);
|
||||
switch (state->fsh.flavor) {
|
||||
case x86_FLOAT_STATE32:
|
||||
- EXPECT_EQ(implicit_cast<int>(x86_FLOAT_STATE32_COUNT),
|
||||
- state->fsh.count);
|
||||
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_FLOAT_STATE32_COUNT),
|
||||
+ implicit_cast<uint32_t>(state->fsh.count));
|
||||
break;
|
||||
case x86_FLOAT_STATE64:
|
||||
- EXPECT_EQ(implicit_cast<int>(x86_FLOAT_STATE64_COUNT),
|
||||
- state->fsh.count);
|
||||
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_FLOAT_STATE64_COUNT),
|
||||
+ implicit_cast<uint32_t>(state->fsh.count));
|
||||
break;
|
||||
default:
|
||||
ADD_FAILURE() << "unexpected fsh.flavor " << state->fsh.flavor;
|
||||
@@ -168,12 +168,12 @@ class TestSimulateCrashMac final : public MachMultiprocess,
|
||||
reinterpret_cast<const x86_debug_state*>(old_state);
|
||||
switch (state->dsh.flavor) {
|
||||
case x86_DEBUG_STATE32:
|
||||
- EXPECT_EQ(implicit_cast<int>(x86_DEBUG_STATE32_COUNT),
|
||||
- state->dsh.count);
|
||||
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_DEBUG_STATE32_COUNT),
|
||||
+ implicit_cast<uint32_t>(state->dsh.count));
|
||||
break;
|
||||
case x86_DEBUG_STATE64:
|
||||
- EXPECT_EQ(implicit_cast<int>(x86_DEBUG_STATE64_COUNT),
|
||||
- state->dsh.count);
|
||||
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_DEBUG_STATE64_COUNT),
|
||||
+ implicit_cast<uint32_t>(state->dsh.count));
|
||||
break;
|
||||
default:
|
||||
ADD_FAILURE() << "unexpected dsh.flavor " << state->dsh.flavor;
|
||||
diff --git a/crashpad.gyp b/crashpad.gyp
|
||||
index 42fe0a26..d8af1bf1 100644
|
||||
--- a/crashpad.gyp
|
||||
+++ b/crashpad.gyp
|
||||
@@ -25,7 +25,7 @@
|
||||
'minidump/minidump.gyp:*',
|
||||
'minidump/minidump_test.gyp:*',
|
||||
'snapshot/snapshot.gyp:*',
|
||||
- 'snapshot/snapshot_test.gyp:*',
|
||||
+# 'snapshot/snapshot_test.gyp:*',
|
||||
'test/test.gyp:*',
|
||||
'test/test_test.gyp:*',
|
||||
'tools/tools.gyp:*',
|
||||
@@ -1,132 +0,0 @@
|
||||
diff --git a/pylib/gyp/generator/cmake.py b/pylib/gyp/generator/cmake.py
|
||||
index 4a2041cf..e5333926 100644
|
||||
--- a/pylib/gyp/generator/cmake.py
|
||||
+++ b/pylib/gyp/generator/cmake.py
|
||||
@@ -1078,6 +1078,23 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
|
||||
|
||||
output.write(')\n')
|
||||
|
||||
+ # Precompile header
|
||||
+ precompiled_header = config.get('cmake_precompiled_header', '')
|
||||
+ if precompiled_header:
|
||||
+ precompiled_header_script = config.get('cmake_precompiled_header_script', '')
|
||||
+ if not precompiled_header_script:
|
||||
+ print ('ERROR: cmake_precompiled_header requires cmake_precompiled_header_script')
|
||||
+ cmake_precompiled_header = NormjoinPath(path_from_cmakelists_to_gyp, precompiled_header)
|
||||
+ cmake_precompiled_header_script = NormjoinPathForceCMakeSource(path_from_cmakelists_to_gyp, precompiled_header_script)
|
||||
+ output.write('include(')
|
||||
+ output.write(cmake_precompiled_header_script)
|
||||
+ output.write(')\n')
|
||||
+ output.write('add_precompiled_header(')
|
||||
+ output.write(cmake_target_name)
|
||||
+ output.write(' ')
|
||||
+ output.write(cmake_precompiled_header)
|
||||
+ output.write(')\n')
|
||||
+
|
||||
UnsetVariable(output, 'TOOLSET')
|
||||
UnsetVariable(output, 'TARGET')
|
||||
|
||||
@@ -1120,6 +1137,8 @@ def GenerateOutputForConfig(target_list, target_dicts, data,
|
||||
SetVariable(output, 'configuration', config_to_use)
|
||||
|
||||
ar = None
|
||||
+ ranlib = None
|
||||
+ nm = None
|
||||
cc = None
|
||||
cxx = None
|
||||
|
||||
@@ -1129,17 +1148,27 @@ def GenerateOutputForConfig(target_list, target_dicts, data,
|
||||
for key, value in make_global_settings:
|
||||
if key == 'AR':
|
||||
ar = os.path.join(build_to_top, value)
|
||||
+ if key == 'RANLIB':
|
||||
+ ranlib = os.path.join(build_to_top, value)
|
||||
+ if key == 'NM':
|
||||
+ nm = os.path.join(build_to_top, value)
|
||||
if key == 'CC':
|
||||
cc = os.path.join(build_to_top, value)
|
||||
if key == 'CXX':
|
||||
cxx = os.path.join(build_to_top, value)
|
||||
|
||||
ar = gyp.common.GetEnvironFallback(['AR_target', 'AR'], ar)
|
||||
+ ranlib = gyp.common.GetEnvironFallback(['RANLIB_target', 'RANLIB'], ranlib)
|
||||
+ nm = gyp.common.GetEnvironFallback(['NM_target', 'NM'], nm)
|
||||
cc = gyp.common.GetEnvironFallback(['CC_target', 'CC'], cc)
|
||||
cxx = gyp.common.GetEnvironFallback(['CXX_target', 'CXX'], cxx)
|
||||
|
||||
if ar:
|
||||
SetVariable(output, 'CMAKE_AR', ar)
|
||||
+ if ranlib:
|
||||
+ SetVariable(output, 'CMAKE_RANLIB', ranlib)
|
||||
+ if nm:
|
||||
+ SetVariable(output, 'CMAKE_NM', nm)
|
||||
if cc:
|
||||
SetVariable(output, 'CMAKE_C_COMPILER', cc)
|
||||
if cxx:
|
||||
diff --git a/pylib/gyp/generator/xcode.py b/pylib/gyp/generator/xcode.py
|
||||
index 8bc22bed..24bee427 100644
|
||||
--- a/pylib/gyp/generator/xcode.py
|
||||
+++ b/pylib/gyp/generator/xcode.py
|
||||
@@ -74,6 +74,12 @@ generator_additional_non_configuration_keys = [
|
||||
'ios_app_extension',
|
||||
'ios_watch_app',
|
||||
'ios_watchkit_extension',
|
||||
+
|
||||
+ 'mac_sandbox', # sandbox support
|
||||
+ 'mac_sandbox_development_team',
|
||||
+
|
||||
+ 'mac_hardened_runtime', # hardened runtime support
|
||||
+
|
||||
'mac_bundle',
|
||||
'mac_bundle_resources',
|
||||
'mac_framework_headers',
|
||||
@@ -774,6 +780,39 @@ def GenerateOutput(target_list, target_dicts, data, params):
|
||||
xcode_targets[qualified_target] = xct
|
||||
xcode_target_to_target_dict[xct] = spec
|
||||
|
||||
+ # sandbox and hardened runtime support
|
||||
+ is_sandbox = int(spec.get('mac_sandbox', 0))
|
||||
+ is_hardened_runtime = int(spec.get('mac_hardened_runtime', 0))
|
||||
+ if is_sandbox or is_hardened_runtime:
|
||||
+ try:
|
||||
+ tmp = pbxp._properties['attributes']['TargetAttributes']
|
||||
+ except KeyError:
|
||||
+ pbxp._properties['attributes']['TargetAttributes'] = {}
|
||||
+ try:
|
||||
+ tmp = pbxp._properties['attributes']['TargetAttributes'][xct]
|
||||
+ except KeyError:
|
||||
+ pbxp._properties['attributes']['TargetAttributes'][xct] = {}
|
||||
+ try:
|
||||
+ tmp = pbxp._properties['attributes']['TargetAttributes'][xct]['SystemCapabilities']
|
||||
+ except KeyError:
|
||||
+ pbxp._properties['attributes']['TargetAttributes'][xct]['SystemCapabilities'] = {}
|
||||
+
|
||||
+ if is_sandbox:
|
||||
+ dev_team = spec.get('mac_sandbox_development_team', '%%ERROR%%')
|
||||
+ assert dev_team != '%%ERROR%%', (
|
||||
+ 'mac_sandbox must be accompanied by mac_sandbox_development_team (target "%s")' %
|
||||
+ target_name)
|
||||
+ pbxp._properties['attributes']['TargetAttributes'][xct]['DevelopmentTeam'] = dev_team
|
||||
+ pbxp._properties['attributes']['TargetAttributes'][xct]['SystemCapabilities']['com.apple.Sandbox'] = {
|
||||
+ 'enabled': 1,
|
||||
+ }
|
||||
+
|
||||
+ # hardened runtime support
|
||||
+ if is_hardened_runtime:
|
||||
+ pbxp._properties['attributes']['TargetAttributes'][xct]['SystemCapabilities']['com.apple.HardenedRuntime'] = {
|
||||
+ 'enabled': 1,
|
||||
+ }
|
||||
+
|
||||
spec_actions = spec.get('actions', [])
|
||||
spec_rules = spec.get('rules', [])
|
||||
|
||||
@@ -1132,7 +1171,8 @@ exit 1
|
||||
groups = [x for x in groups if not x.endswith('_excluded')]
|
||||
for group in groups:
|
||||
for item in rule.get(group, []):
|
||||
- pbxp.AddOrGetFileInRootGroup(item)
|
||||
+ concrete_item = ExpandXcodeVariables(item, rule_input_dict)
|
||||
+ pbxp.AddOrGetFileInRootGroup(concrete_item)
|
||||
|
||||
# Add "sources".
|
||||
for source in spec.get('sources', []):
|
||||
@@ -1,127 +0,0 @@
|
||||
diff --git a/build/crashpad.gypi b/build/crashpad.gypi
|
||||
index 027c7b68..4bfdfb5a 100644
|
||||
--- a/build/crashpad.gypi
|
||||
+++ b/build/crashpad.gypi
|
||||
@@ -25,5 +25,15 @@
|
||||
4201, # nonstandard extension used : nameless struct/union.
|
||||
4324, # structure was padded due to __declspec(align()).
|
||||
],
|
||||
+ 'xcode_settings': {
|
||||
+ 'OTHER_CPLUSPLUSFLAGS': [ '-nostdinc++' ],
|
||||
+ 'OTHER_LDFLAGS': [
|
||||
+ '/usr/local/macold/lib/libc++.a',
|
||||
+ '/usr/local/macold/lib/libc++abi.a',
|
||||
+ ],
|
||||
+ },
|
||||
+ 'include_dirs': [
|
||||
+ '/usr/local/macold/include/c++/v1',
|
||||
+ ],
|
||||
},
|
||||
}
|
||||
diff --git a/client/capture_context_mac_test.cc b/client/capture_context_mac_test.cc
|
||||
index 436ac5ad..8e14fb9c 100644
|
||||
--- a/client/capture_context_mac_test.cc
|
||||
+++ b/client/capture_context_mac_test.cc
|
||||
@@ -34,11 +34,11 @@ namespace {
|
||||
// gtest assertions.
|
||||
void SanityCheckContext(const NativeCPUContext& context) {
|
||||
#if defined(ARCH_CPU_X86)
|
||||
- ASSERT_EQ(x86_THREAD_STATE32, context.tsh.flavor);
|
||||
- ASSERT_EQ(implicit_cast<int>(x86_THREAD_STATE32_COUNT), context.tsh.count);
|
||||
+ ASSERT_EQ(implicit_cast<thread_state_flavor_t>(x86_THREAD_STATE32), implicit_cast<thread_state_flavor_t>(context.tsh.flavor));
|
||||
+ ASSERT_EQ(implicit_cast<uint32_t>(x86_THREAD_STATE32_COUNT), implicit_cast<uint32_t>(context.tsh.count));
|
||||
#elif defined(ARCH_CPU_X86_64)
|
||||
- ASSERT_EQ(x86_THREAD_STATE64, context.tsh.flavor);
|
||||
- ASSERT_EQ(implicit_cast<int>(x86_THREAD_STATE64_COUNT), context.tsh.count);
|
||||
+ ASSERT_EQ(implicit_cast<thread_state_flavor_t>(x86_THREAD_STATE64), implicit_cast<thread_state_flavor_t>(context.tsh.flavor));
|
||||
+ ASSERT_EQ(implicit_cast<uint32_t>(x86_THREAD_STATE64_COUNT), implicit_cast<uint32_t>(context.tsh.count));
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_CPU_X86_FAMILY)
|
||||
diff --git a/client/simulate_crash_mac.cc b/client/simulate_crash_mac.cc
|
||||
index 7e279015..27864388 100644
|
||||
--- a/client/simulate_crash_mac.cc
|
||||
+++ b/client/simulate_crash_mac.cc
|
||||
@@ -177,12 +177,12 @@ bool DeliverException(thread_t thread,
|
||||
|
||||
void SimulateCrash(const NativeCPUContext& cpu_context) {
|
||||
#if defined(ARCH_CPU_X86)
|
||||
- DCHECK_EQ(cpu_context.tsh.flavor,
|
||||
+ DCHECK_EQ(implicit_cast<thread_state_flavor_t>(cpu_context.tsh.flavor),
|
||||
implicit_cast<thread_state_flavor_t>(x86_THREAD_STATE32));
|
||||
DCHECK_EQ(implicit_cast<mach_msg_type_number_t>(cpu_context.tsh.count),
|
||||
x86_THREAD_STATE32_COUNT);
|
||||
#elif defined(ARCH_CPU_X86_64)
|
||||
- DCHECK_EQ(cpu_context.tsh.flavor,
|
||||
+ DCHECK_EQ(implicit_cast<thread_state_flavor_t>(cpu_context.tsh.flavor),
|
||||
implicit_cast<thread_state_flavor_t>(x86_THREAD_STATE64));
|
||||
DCHECK_EQ(implicit_cast<mach_msg_type_number_t>(cpu_context.tsh.count),
|
||||
x86_THREAD_STATE64_COUNT);
|
||||
diff --git a/client/simulate_crash_mac_test.cc b/client/simulate_crash_mac_test.cc
|
||||
index 87c5f845..ca813e4c 100644
|
||||
--- a/client/simulate_crash_mac_test.cc
|
||||
+++ b/client/simulate_crash_mac_test.cc
|
||||
@@ -130,12 +130,12 @@ class TestSimulateCrashMac final : public MachMultiprocess,
|
||||
reinterpret_cast<const x86_thread_state*>(old_state);
|
||||
switch (state->tsh.flavor) {
|
||||
case x86_THREAD_STATE32:
|
||||
- EXPECT_EQ(implicit_cast<int>(x86_THREAD_STATE32_COUNT),
|
||||
- state->tsh.count);
|
||||
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_THREAD_STATE32_COUNT),
|
||||
+ implicit_cast<uint32_t>(state->tsh.count));
|
||||
break;
|
||||
case x86_THREAD_STATE64:
|
||||
- EXPECT_EQ(implicit_cast<int>(x86_THREAD_STATE64_COUNT),
|
||||
- state->tsh.count);
|
||||
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_THREAD_STATE64_COUNT),
|
||||
+ implicit_cast<uint32_t>(state->tsh.count));
|
||||
break;
|
||||
default:
|
||||
ADD_FAILURE() << "unexpected tsh.flavor " << state->tsh.flavor;
|
||||
@@ -149,12 +149,12 @@ class TestSimulateCrashMac final : public MachMultiprocess,
|
||||
reinterpret_cast<const x86_float_state*>(old_state);
|
||||
switch (state->fsh.flavor) {
|
||||
case x86_FLOAT_STATE32:
|
||||
- EXPECT_EQ(implicit_cast<int>(x86_FLOAT_STATE32_COUNT),
|
||||
- state->fsh.count);
|
||||
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_FLOAT_STATE32_COUNT),
|
||||
+ implicit_cast<uint32_t>(state->fsh.count));
|
||||
break;
|
||||
case x86_FLOAT_STATE64:
|
||||
- EXPECT_EQ(implicit_cast<int>(x86_FLOAT_STATE64_COUNT),
|
||||
- state->fsh.count);
|
||||
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_FLOAT_STATE64_COUNT),
|
||||
+ implicit_cast<uint32_t>(state->fsh.count));
|
||||
break;
|
||||
default:
|
||||
ADD_FAILURE() << "unexpected fsh.flavor " << state->fsh.flavor;
|
||||
@@ -168,12 +168,12 @@ class TestSimulateCrashMac final : public MachMultiprocess,
|
||||
reinterpret_cast<const x86_debug_state*>(old_state);
|
||||
switch (state->dsh.flavor) {
|
||||
case x86_DEBUG_STATE32:
|
||||
- EXPECT_EQ(implicit_cast<int>(x86_DEBUG_STATE32_COUNT),
|
||||
- state->dsh.count);
|
||||
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_DEBUG_STATE32_COUNT),
|
||||
+ implicit_cast<uint32_t>(state->dsh.count));
|
||||
break;
|
||||
case x86_DEBUG_STATE64:
|
||||
- EXPECT_EQ(implicit_cast<int>(x86_DEBUG_STATE64_COUNT),
|
||||
- state->dsh.count);
|
||||
+ EXPECT_EQ(implicit_cast<uint32_t>(x86_DEBUG_STATE64_COUNT),
|
||||
+ implicit_cast<uint32_t>(state->dsh.count));
|
||||
break;
|
||||
default:
|
||||
ADD_FAILURE() << "unexpected dsh.flavor " << state->dsh.flavor;
|
||||
diff --git a/crashpad.gyp b/crashpad.gyp
|
||||
index 42fe0a26..d8af1bf1 100644
|
||||
--- a/crashpad.gyp
|
||||
+++ b/crashpad.gyp
|
||||
@@ -25,7 +25,7 @@
|
||||
'minidump/minidump.gyp:*',
|
||||
'minidump/minidump_test.gyp:*',
|
||||
'snapshot/snapshot.gyp:*',
|
||||
- 'snapshot/snapshot_test.gyp:*',
|
||||
+# 'snapshot/snapshot_test.gyp:*',
|
||||
'test/test.gyp:*',
|
||||
'test/test_test.gyp:*',
|
||||
'tools/tools.gyp:*',
|
||||
@@ -1,28 +0,0 @@
|
||||
diff --git a/build/common.gypi b/build/common.gypi
|
||||
index 1affc70..0677e4b 100644
|
||||
--- a/build/common.gypi
|
||||
+++ b/build/common.gypi
|
||||
@@ -66,6 +66,13 @@
|
||||
'conditions': [
|
||||
['clang!=0', {
|
||||
'CLANG_CXX_LANGUAGE_STANDARD': 'c++11', # -std=c++11
|
||||
+ 'OTHER_CPLUSPLUSFLAGS': [ '-nostdinc++' ],
|
||||
+ 'OTHER_LDFLAGS': [
|
||||
+ '/usr/local/macold/lib/libc++.a',
|
||||
+ '/usr/local/macold/lib/libc++abi.a',
|
||||
+ '-isysroot/',
|
||||
+ '-L/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib/',
|
||||
+ ],
|
||||
|
||||
# Don't link in libarclite_macosx.a, see http://crbug.com/156530.
|
||||
'CLANG_LINK_OBJC_RUNTIME': 'NO', # -fno-objc-link-runtime
|
||||
@@ -116,6 +123,9 @@
|
||||
],
|
||||
|
||||
},
|
||||
+ 'include_dirs': [
|
||||
+ '/usr/local/macold/include/c++/v1',
|
||||
+ ],
|
||||
}],
|
||||
|
||||
['OS=="linux"', {
|
||||
@@ -1,844 +0,0 @@
|
||||
diff --git a/configure b/configure
|
||||
index cb8d78fd3c..cadb3f0a88 100755
|
||||
--- a/configure
|
||||
+++ b/configure
|
||||
@@ -511,7 +511,8 @@ if [ "$BUILD_ON_MAC" = "yes" ]; then
|
||||
exit 2
|
||||
fi
|
||||
|
||||
- if ! /usr/bin/xcrun -find xcrun >/dev/null 2>&1; then
|
||||
+ # Patch: Fix Qt for working with Xcode 8.
|
||||
+ if ! /usr/bin/xcrun -find xcodebuild >/dev/null 2>&1; then
|
||||
echo >&2
|
||||
echo " Xcode not set up properly. You may need to confirm the license" >&2
|
||||
echo " agreement by running /usr/bin/xcodebuild without arguments." >&2
|
||||
diff --git a/mkspecs/common/g++-macx.conf b/mkspecs/common/g++-macx.conf
|
||||
index 086510dd96..078a5ed1dd 100644
|
||||
--- a/mkspecs/common/g++-macx.conf
|
||||
+++ b/mkspecs/common/g++-macx.conf
|
||||
@@ -14,7 +14,13 @@ QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -gdwarf-2
|
||||
QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO += -gdwarf-2
|
||||
QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO += -g -gdwarf-2
|
||||
|
||||
-QMAKE_LFLAGS_STATIC_LIB += -all_load
|
||||
+# Patch: Don't remember :(
|
||||
+#QMAKE_LFLAGS_STATIC_LIB += -all_load
|
||||
+
|
||||
+# Patch: Use C++14 with custom libc++ build.
|
||||
+QMAKE_CXXFLAGS_CXX11 = -std=c++1y
|
||||
+QMAKE_CXXFLAGS += -nostdinc++ -I/usr/local/macold/include/c++/v1
|
||||
+QMAKE_LFLAGS += /usr/local/macold/lib/libc++.a /usr/local/macold/lib/libc++abi.a -isysroot /
|
||||
|
||||
QMAKE_XCODE_GCC_VERSION = com.apple.compilers.llvmgcc42
|
||||
|
||||
diff --git a/mkspecs/features/mac/default_pre.prf b/mkspecs/features/mac/default_pre.prf
|
||||
index 0cc8cd6dfd..ca9725b779 100644
|
||||
--- a/mkspecs/features/mac/default_pre.prf
|
||||
+++ b/mkspecs/features/mac/default_pre.prf
|
||||
@@ -12,7 +12,9 @@ isEmpty(QMAKE_XCODE_DEVELOPER_PATH) {
|
||||
error("Xcode is not installed in $${QMAKE_XCODE_DEVELOPER_PATH}. Please use xcode-select to choose Xcode installation path.")
|
||||
|
||||
# Make sure Xcode is set up properly
|
||||
- isEmpty($$list($$system("/usr/bin/xcrun -find xcrun 2>/dev/null"))): \
|
||||
+
|
||||
+ # Patch: Fix Qt for working with Xcode 8.
|
||||
+ isEmpty($$list($$system("/usr/bin/xcrun -find xcodebuild 2>/dev/null"))): \
|
||||
error("Xcode not set up properly. You may need to confirm the license agreement by running /usr/bin/xcodebuild.")
|
||||
}
|
||||
|
||||
diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp
|
||||
index bb79a139b3..5d595bc3b3 100644
|
||||
--- a/src/gui/image/qbmphandler.cpp
|
||||
+++ b/src/gui/image/qbmphandler.cpp
|
||||
@@ -220,6 +220,10 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int
|
||||
int blue_scale = 0;
|
||||
int alpha_scale = 0;
|
||||
|
||||
+ // Patch: Backport a fix for bmp reader.
|
||||
+ if (!d->isSequential())
|
||||
+ d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap
|
||||
+
|
||||
if (bi.biSize >= BMP_WIN4 || (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32))) {
|
||||
if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask))
|
||||
return false;
|
||||
@@ -307,8 +311,9 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int
|
||||
image.setDotsPerMeterX(bi.biXPelsPerMeter);
|
||||
image.setDotsPerMeterY(bi.biYPelsPerMeter);
|
||||
|
||||
- if (!d->isSequential())
|
||||
- d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap
|
||||
+ // Patch: Backport a fix for bmp reader.
|
||||
+ //if (!d->isSequential())
|
||||
+ // d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap
|
||||
|
||||
if (ncols > 0) { // read color table
|
||||
uchar rgb[4];
|
||||
diff --git a/src/gui/painting/qpaintengine_p.h b/src/gui/painting/qpaintengine_p.h
|
||||
index ebff9509ab..4300ca4c0f 100644
|
||||
--- a/src/gui/painting/qpaintengine_p.h
|
||||
+++ b/src/gui/painting/qpaintengine_p.h
|
||||
@@ -87,8 +87,18 @@ public:
|
||||
if (hasSystemTransform) {
|
||||
if (systemTransform.type() <= QTransform::TxTranslate)
|
||||
systemClip.translate(qRound(systemTransform.dx()), qRound(systemTransform.dy()));
|
||||
- else
|
||||
+ // Patch: Transform the system clip region back from device pixels to device-independent pixels before
|
||||
+ // applying systemTransform, which already has transform from device-independent pixels to device pixels.
|
||||
+ else {
|
||||
+#ifdef Q_OS_MAC
|
||||
+ QTransform scaleTransform;
|
||||
+ const qreal invDevicePixelRatio = 1. / pdev->devicePixelRatio();
|
||||
+ scaleTransform.scale(invDevicePixelRatio, invDevicePixelRatio);
|
||||
+ systemClip = systemTransform.map(scaleTransform.map(systemClip));
|
||||
+#else
|
||||
systemClip = systemTransform.map(systemClip);
|
||||
+#endif
|
||||
+ }
|
||||
}
|
||||
|
||||
// Make sure we're inside the viewport.
|
||||
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
|
||||
index 4879ae51d7..56cdcbaf01 100644
|
||||
--- a/src/gui/text/qtextlayout.cpp
|
||||
+++ b/src/gui/text/qtextlayout.cpp
|
||||
@@ -654,6 +654,9 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const
|
||||
while (oldPos < len && !attributes[oldPos].graphemeBoundary)
|
||||
oldPos++;
|
||||
} else {
|
||||
+ // Patch: Skip to the end of the current word, not to the start of the next one.
|
||||
+ while (oldPos < len && attributes[oldPos].whiteSpace)
|
||||
+ oldPos++;
|
||||
if (oldPos < len && d->atWordSeparator(oldPos)) {
|
||||
oldPos++;
|
||||
while (oldPos < len && d->atWordSeparator(oldPos))
|
||||
@@ -662,8 +665,9 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const
|
||||
while (oldPos < len && !d->atSpace(oldPos) && !d->atWordSeparator(oldPos))
|
||||
oldPos++;
|
||||
}
|
||||
- while (oldPos < len && d->atSpace(oldPos))
|
||||
- oldPos++;
|
||||
+ // Patch: Skip to the end of the current word, not to the start of the next one.
|
||||
+ //while (oldPos < len && d->atSpace(oldPos))
|
||||
+ // oldPos++;
|
||||
}
|
||||
|
||||
return oldPos;
|
||||
@@ -1602,6 +1606,9 @@ namespace {
|
||||
int currentPosition;
|
||||
glyph_t previousGlyph;
|
||||
|
||||
+ // Patch: Backport a crash fix.
|
||||
+ QFontEngine *previousGlyphFontEngine;
|
||||
+
|
||||
QFixed minw;
|
||||
QFixed softHyphenWidth;
|
||||
QFixed rightBearing;
|
||||
@@ -1634,13 +1641,19 @@ namespace {
|
||||
if (currentPosition > 0 &&
|
||||
logClusters[currentPosition - 1] < glyphs.numGlyphs) {
|
||||
previousGlyph = currentGlyph(); // needed to calculate right bearing later
|
||||
+
|
||||
+ // Patch: Backport a crash fix.
|
||||
+ previousGlyphFontEngine = fontEngine;
|
||||
}
|
||||
}
|
||||
|
||||
- inline void adjustRightBearing(glyph_t glyph)
|
||||
+ // Patch: Backport a crash fix.
|
||||
+ inline void adjustRightBearing(QFontEngine *engine, glyph_t glyph)
|
||||
{
|
||||
qreal rb;
|
||||
- fontEngine->getGlyphBearings(glyph, 0, &rb);
|
||||
+
|
||||
+ // Patch: Backport a crash fix.
|
||||
+ engine->getGlyphBearings(glyph, 0, &rb);
|
||||
rightBearing = qMin(QFixed(), QFixed::fromReal(rb));
|
||||
}
|
||||
|
||||
@@ -1648,13 +1661,16 @@ namespace {
|
||||
{
|
||||
if (currentPosition <= 0)
|
||||
return;
|
||||
- adjustRightBearing(currentGlyph());
|
||||
+
|
||||
+ // Patch: Backport a crash fix.
|
||||
+ adjustRightBearing(fontEngine, currentGlyph());
|
||||
}
|
||||
|
||||
inline void adjustPreviousRightBearing()
|
||||
{
|
||||
if (previousGlyph > 0)
|
||||
- adjustRightBearing(previousGlyph);
|
||||
+ // Patch: Backport a crash fix.
|
||||
+ adjustRightBearing(previousGlyphFontEngine, previousGlyph);
|
||||
}
|
||||
|
||||
inline void resetRightBearing()
|
||||
diff --git a/src/gui/text/qtextlayout.h b/src/gui/text/qtextlayout.h
|
||||
index cbe42c3844..b273db7e78 100644
|
||||
--- a/src/gui/text/qtextlayout.h
|
||||
+++ b/src/gui/text/qtextlayout.h
|
||||
@@ -194,6 +194,9 @@ private:
|
||||
QRectF *brect, int tabstops, int* tabarray, int tabarraylen,
|
||||
QPainter *painter);
|
||||
QTextEngine *d;
|
||||
+
|
||||
+ // Patch: Give access to the internal api.
|
||||
+ friend class TextBlock;
|
||||
};
|
||||
|
||||
|
||||
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
|
||||
index 360f9722c7..f28f289ef6 100644
|
||||
--- a/src/network/access/qhttpnetworkconnection.cpp
|
||||
+++ b/src/network/access/qhttpnetworkconnection.cpp
|
||||
@@ -118,6 +118,8 @@ QHttpNetworkConnectionPrivate::~QHttpNetworkConnectionPrivate()
|
||||
{
|
||||
for (int i = 0; i < channelCount; ++i) {
|
||||
if (channels[i].socket) {
|
||||
+ // Patch: backport critical bugfix from '4f959b6b30' commit.
|
||||
+ QObject::disconnect(channels[i].socket, Q_NULLPTR, &channels[i], Q_NULLPTR);
|
||||
channels[i].socket->close();
|
||||
delete channels[i].socket;
|
||||
}
|
||||
diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
|
||||
index ca7afb7d1b..25ae50008d 100644
|
||||
--- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
|
||||
+++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
|
||||
@@ -256,6 +256,13 @@ static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd)
|
||||
|
||||
fd->foundryName = QStringLiteral("CoreText");
|
||||
fd->familyName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute);
|
||||
+
|
||||
+ // Patch: Fix open sans semibold loading.
|
||||
+ QCFString _displayName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute);
|
||||
+ if (_displayName == QStringLiteral("Open Sans Semibold")) {
|
||||
+ fd->familyName = _displayName;
|
||||
+ }
|
||||
+
|
||||
fd->styleName = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute);
|
||||
fd->weight = QFont::Normal;
|
||||
fd->style = QFont::StyleNormal;
|
||||
diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
|
||||
index 6e2c8a2a9a..3cace8abcb 100644
|
||||
--- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
|
||||
+++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
|
||||
@@ -717,7 +717,8 @@ void QCoreTextFontEngine::getUnscaledGlyph(glyph_t, QPainterPath *, glyph_metric
|
||||
|
||||
QFixed QCoreTextFontEngine::emSquareSize() const
|
||||
{
|
||||
- return QFixed::QFixed(int(CTFontGetUnitsPerEm(ctfont)));
|
||||
+ // Patch: Fix build for Xcode 9.3.1.
|
||||
+ return QFixed(int(CTFontGetUnitsPerEm(ctfont)));
|
||||
}
|
||||
|
||||
QFontEngine *QCoreTextFontEngine::cloneWithSize(qreal pixelSize) const
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
|
||||
index 92358ecc74..694fee7350 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
|
||||
@@ -213,7 +213,8 @@ static void cleanupCocoaApplicationDelegate()
|
||||
if (reflectionDelegate) {
|
||||
if ([reflectionDelegate respondsToSelector:@selector(applicationShouldTerminate:)])
|
||||
return [reflectionDelegate applicationShouldTerminate:sender];
|
||||
- return NSTerminateNow;
|
||||
+ // Patch: Don't terminate if reflectionDelegate does not respond to that selector, just use the default.
|
||||
+ //return NSTerminateNow;
|
||||
}
|
||||
|
||||
if ([self canQuit]) {
|
||||
@@ -289,6 +290,11 @@ static void cleanupCocoaApplicationDelegate()
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
||||
{
|
||||
+ // Patch: We need to receive this notification in the delegate as well.
|
||||
+ if (reflectionDelegate
|
||||
+ && [reflectionDelegate respondsToSelector:@selector(applicationDidFinishLaunching:)])
|
||||
+ [reflectionDelegate applicationDidFinishLaunching:aNotification];
|
||||
+
|
||||
Q_UNUSED(aNotification);
|
||||
inLaunch = false;
|
||||
// qt_release_apple_event_handler();
|
||||
@@ -411,7 +417,9 @@ static void cleanupCocoaApplicationDelegate()
|
||||
{
|
||||
Q_UNUSED(replyEvent);
|
||||
NSString *urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
|
||||
- QWindowSystemInterface::handleFileOpenEvent(QUrl(QCFString::toQString(urlString)));
|
||||
+
|
||||
+ // Patch: Fix opening of an external url by a protocol handler.
|
||||
+ QWindowSystemInterface::handleFileOpenEvent(QUrl::fromNSURL([NSURL URLWithString:urlString]));
|
||||
}
|
||||
|
||||
- (void)appleEventQuit:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm
|
||||
index b81b9a0b1c..4e59e833b1 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoacursor.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoacursor.mm
|
||||
@@ -81,7 +81,7 @@ void QCocoaCursor::setPos(const QPoint &position)
|
||||
pos.x = position.x();
|
||||
pos.y = position.y();
|
||||
|
||||
- CGEventRef e = CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, 0);
|
||||
+ CGEventRef e = CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, kCGMouseButtonLeft);
|
||||
CGEventPost(kCGHIDEventTap, e);
|
||||
CFRelease(e);
|
||||
}
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
|
||||
index 9850f83dea..b2e1d3dfda 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
|
||||
@@ -649,9 +649,10 @@ OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGIm
|
||||
// Verbatim copy if HIViewDrawCGImage (as shown on Carbon-Dev)
|
||||
OSStatus err = noErr;
|
||||
|
||||
- require_action(inContext != NULL, InvalidContext, err = paramErr);
|
||||
- require_action(inBounds != NULL, InvalidBounds, err = paramErr);
|
||||
- require_action(inImage != NULL, InvalidImage, err = paramErr);
|
||||
+ // Patch: Fix build on latest Xcode.
|
||||
+ //require_action(inContext != NULL, InvalidContext, err = paramErr);
|
||||
+ //require_action(inBounds != NULL, InvalidBounds, err = paramErr);
|
||||
+ //require_action(inImage != NULL, InvalidImage, err = paramErr);
|
||||
|
||||
CGContextSaveGState( inContext );
|
||||
CGContextTranslateCTM (inContext, 0, inBounds->origin.y + CGRectGetMaxY(*inBounds));
|
||||
@@ -660,9 +661,11 @@ OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGIm
|
||||
CGContextDrawImage(inContext, *inBounds, inImage);
|
||||
|
||||
CGContextRestoreGState(inContext);
|
||||
-InvalidImage:
|
||||
-InvalidBounds:
|
||||
-InvalidContext:
|
||||
+
|
||||
+// Patch: Fix build on latest Xcode.
|
||||
+//InvalidImage:
|
||||
+//InvalidBounds:
|
||||
+//InvalidContext:
|
||||
return err;
|
||||
}
|
||||
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
|
||||
index 9fd05a65ee..dea60720e7 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
|
||||
@@ -402,14 +402,24 @@ void QCocoaIntegration::updateScreens()
|
||||
}
|
||||
siblings << screen;
|
||||
}
|
||||
+
|
||||
+ // Patch: Backport crash fix from Qt 5.6.1.
|
||||
+ // Set virtual siblings list. All screens in mScreens are siblings, because we ignored the
|
||||
+ // mirrors. Note that some of the screens we update the siblings list for here may be deleted
|
||||
+ // below, but update anyway to keep the to-be-deleted screens out of the siblings list.
|
||||
+ foreach (QCocoaScreen* screen, mScreens)
|
||||
+ screen->setVirtualSiblings(siblings);
|
||||
+
|
||||
// Now the leftovers in remainingScreens are no longer current, so we can delete them.
|
||||
foreach (QCocoaScreen* screen, remainingScreens) {
|
||||
mScreens.removeOne(screen);
|
||||
delete screen;
|
||||
}
|
||||
+
|
||||
+ // Patch: Backport crash fix from Qt 5.6.1.
|
||||
// All screens in mScreens are siblings, because we ignored the mirrors.
|
||||
- foreach (QCocoaScreen* screen, mScreens)
|
||||
- screen->setVirtualSiblings(siblings);
|
||||
+ //foreach (QCocoaScreen* screen, mScreens)
|
||||
+ // screen->setVirtualSiblings(siblings);
|
||||
}
|
||||
|
||||
QCocoaScreen *QCocoaIntegration::screenAtIndex(int index)
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.mm b/src/plugins/platforms/cocoa/qcocoakeymapper.mm
|
||||
index e46eaff6be..c62db534a2 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoakeymapper.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoakeymapper.mm
|
||||
@@ -382,6 +382,12 @@ bool QCocoaKeyMapper::updateKeyboard()
|
||||
keyboardInputLocale = QLocale::c();
|
||||
keyboardInputDirection = Qt::LeftToRight;
|
||||
}
|
||||
+
|
||||
+ // Patch: Backport a fix for layout-independent keyboard shortcuts.
|
||||
+ const auto newMode = keyboard_mode;
|
||||
+ deleteLayouts();
|
||||
+ keyboard_mode = newMode;
|
||||
+
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -464,7 +470,8 @@ QList<int> QCocoaKeyMapper::possibleKeys(const QKeyEvent *event) const
|
||||
Qt::KeyboardModifiers neededMods = ModsTbl[i];
|
||||
int key = kbItem->qtKey[i];
|
||||
if (key && key != baseKey && ((keyMods & neededMods) == neededMods)) {
|
||||
- ret << int(key + (keyMods & ~neededMods));
|
||||
+ // Patch: Backport a fix for layout-independent keyboard shortcuts.
|
||||
+ ret << int(key + neededMods);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||
index 83c960d931..03ae9696af 100755
|
||||
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||
@@ -102,7 +102,10 @@ QT_USE_NAMESPACE
|
||||
QCocoaSystemTrayIcon *systray;
|
||||
NSStatusItem *item;
|
||||
QCocoaMenu *menu;
|
||||
- bool menuVisible;
|
||||
+
|
||||
+ // Patch: Nice macOS tray icon support.
|
||||
+ bool menuVisible, iconSelected;
|
||||
+
|
||||
QIcon icon;
|
||||
QT_MANGLE_NAMESPACE(QNSImageView) *imageCell;
|
||||
}
|
||||
@@ -124,6 +127,10 @@ QT_USE_NAMESPACE
|
||||
QT_MANGLE_NAMESPACE(QNSStatusItem) *parent;
|
||||
}
|
||||
-(id)initWithParent:(QT_MANGLE_NAMESPACE(QNSStatusItem)*)myParent;
|
||||
+
|
||||
+// Patch: Nice macOS tray icon support.
|
||||
+-(void)updateIconSelection;
|
||||
+
|
||||
-(void)menuTrackingDone:(NSNotification*)notification;
|
||||
-(void)mousePressed:(NSEvent *)mouseEvent button:(Qt::MouseButton)mouseButton;
|
||||
@end
|
||||
@@ -187,6 +194,19 @@ void QCocoaSystemTrayIcon::cleanup()
|
||||
m_sys = 0;
|
||||
}
|
||||
|
||||
+// Patch: Nice macOS tray icon support.
|
||||
+namespace {
|
||||
+
|
||||
+qreal getDevicePixelRatio() {
|
||||
+ qreal result = 1.0;
|
||||
+ foreach (QScreen *screen, QGuiApplication::screens()) {
|
||||
+ result = qMax(result, screen->devicePixelRatio());
|
||||
+ }
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+} // namespace
|
||||
+
|
||||
void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
|
||||
{
|
||||
if (!m_sys)
|
||||
@@ -194,13 +214,18 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
|
||||
|
||||
m_sys->item->icon = icon;
|
||||
|
||||
- const bool menuVisible = m_sys->item->menu && m_sys->item->menuVisible;
|
||||
+ // Patch: Nice macOS tray icon support.
|
||||
+ //const bool menuVisible = m_sys->item->menu && m_sys->item->menuVisible;
|
||||
|
||||
- CGFloat hgt = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
|
||||
- const short scale = hgt - 4;
|
||||
+ const int padding = 0;
|
||||
+ const int menuHeight = [[NSStatusBar systemStatusBar] thickness];
|
||||
+ const int maxImageHeight = menuHeight - padding;
|
||||
+
|
||||
+ const short scale = maxImageHeight * getDevicePixelRatio();
|
||||
|
||||
QPixmap pm = m_sys->item->icon.pixmap(QSize(scale, scale),
|
||||
- menuVisible ? QIcon::Selected : QIcon::Normal);
|
||||
+ // Patch: Nice macOS tray icon support.
|
||||
+ m_sys->item->iconSelected ? QIcon::Selected : QIcon::Normal);
|
||||
if (pm.isNull()) {
|
||||
pm = QPixmap(scale, scale);
|
||||
pm.fill(Qt::transparent);
|
||||
@@ -322,15 +347,16 @@ QT_END_NAMESPACE
|
||||
return self;
|
||||
}
|
||||
|
||||
--(void)menuTrackingDone:(NSNotification*)notification
|
||||
+// Patch: Nice macOS tray icon support.
|
||||
+-(void)updateIconSelection
|
||||
{
|
||||
- Q_UNUSED(notification);
|
||||
- down = NO;
|
||||
+ const int padding = 0;
|
||||
+ const int menuHeight = [[NSStatusBar systemStatusBar] thickness];
|
||||
+ const int maxImageHeight = menuHeight - padding;
|
||||
|
||||
- CGFloat hgt = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
|
||||
- const short scale = hgt - 4;
|
||||
-
|
||||
- QPixmap pm = parent->icon.pixmap(QSize(scale, scale), QIcon::Normal);
|
||||
+ const short scale = maxImageHeight * getDevicePixelRatio();
|
||||
+ QPixmap pm = parent->icon.pixmap(QSize(scale, scale),
|
||||
+ parent->iconSelected ? QIcon::Selected : QIcon::Normal);
|
||||
if (pm.isNull()) {
|
||||
pm = QPixmap(scale, scale);
|
||||
pm.fill(Qt::transparent);
|
||||
@@ -338,9 +364,19 @@ QT_END_NAMESPACE
|
||||
NSImage *nsaltimage = static_cast<NSImage *>(qt_mac_create_nsimage(pm));
|
||||
[self setImage: nsaltimage];
|
||||
[nsaltimage release];
|
||||
+}
|
||||
+
|
||||
+-(void)menuTrackingDone:(NSNotification*)notification
|
||||
+{
|
||||
+ Q_UNUSED(notification);
|
||||
+ down = NO;
|
||||
|
||||
parent->menuVisible = false;
|
||||
|
||||
+ // Patch: Nice macOS tray icon support.
|
||||
+ parent->iconSelected = false;
|
||||
+ [self updateIconSelection];
|
||||
+
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
@@ -350,18 +386,9 @@ QT_END_NAMESPACE
|
||||
int clickCount = [mouseEvent clickCount];
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
- CGFloat hgt = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
|
||||
- const short scale = hgt - 4;
|
||||
-
|
||||
- QPixmap pm = parent->icon.pixmap(QSize(scale, scale),
|
||||
- parent->menuVisible ? QIcon::Selected : QIcon::Normal);
|
||||
- if (pm.isNull()) {
|
||||
- pm = QPixmap(scale, scale);
|
||||
- pm.fill(Qt::transparent);
|
||||
- }
|
||||
- NSImage *nsaltimage = static_cast<NSImage *>(qt_mac_create_nsimage(pm));
|
||||
- [self setImage: nsaltimage];
|
||||
- [nsaltimage release];
|
||||
+ // Patch: Nice macOS tray icon support.
|
||||
+ parent->iconSelected = (clickCount != 2) && parent->menu;
|
||||
+ [self updateIconSelection];
|
||||
|
||||
if (clickCount == 2) {
|
||||
[self menuTrackingDone:nil];
|
||||
@@ -380,6 +407,10 @@ QT_END_NAMESPACE
|
||||
{
|
||||
Q_UNUSED(mouseEvent);
|
||||
[self menuTrackingDone:nil];
|
||||
+
|
||||
+ // Patch: Nice macOS tray icon support.
|
||||
+ parent->iconSelected = false;
|
||||
+ [self updateIconSelection];
|
||||
}
|
||||
|
||||
- (void)rightMouseDown:(NSEvent *)mouseEvent
|
||||
@@ -391,6 +422,10 @@ QT_END_NAMESPACE
|
||||
{
|
||||
Q_UNUSED(mouseEvent);
|
||||
[self menuTrackingDone:nil];
|
||||
+
|
||||
+ // Patch: Nice macOS tray icon support.
|
||||
+ parent->iconSelected = false;
|
||||
+ [self updateIconSelection];
|
||||
}
|
||||
|
||||
- (void)otherMouseDown:(NSEvent *)mouseEvent
|
||||
@@ -405,7 +440,8 @@ QT_END_NAMESPACE
|
||||
}
|
||||
|
||||
-(void)drawRect:(NSRect)rect {
|
||||
- [[parent item] drawStatusBarBackgroundInRect:rect withHighlight:down];
|
||||
+ // Patch: Nice macOS tray icon support.
|
||||
+ [[parent item] drawStatusBarBackgroundInRect:rect withHighlight:parent->menu ? down : NO];
|
||||
[super drawRect:rect];
|
||||
}
|
||||
@end
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
|
||||
index 4d0458a4aa..3357a5ef81 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
|
||||
@@ -167,7 +167,8 @@ static bool isMouseEvent(NSEvent *ev)
|
||||
if (!self.window.delegate)
|
||||
return; // Already detached, pending NSAppKitDefined event
|
||||
|
||||
- if (pw && pw->frameStrutEventsEnabled() && isMouseEvent(theEvent)) {
|
||||
+ // Patch: Fix events loss if the window was minimized or hidden.
|
||||
+ if (pw && pw->frameStrutEventsEnabled() && pw->m_synchedWindowState != Qt::WindowMinimized && pw->m_isExposed && isMouseEvent(theEvent)) {
|
||||
NSPoint loc = [theEvent locationInWindow];
|
||||
NSRect windowFrame = [self.window legacyConvertRectFromScreen:[self.window frame]];
|
||||
NSRect contentFrame = [[self.window contentView] frame];
|
||||
@@ -795,6 +796,16 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags)
|
||||
{
|
||||
Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
|
||||
NSInteger styleMask = NSBorderlessWindowMask;
|
||||
+
|
||||
+ // Patch: allow creating panels floating on all spaces in macOS.
|
||||
+ // If you call "setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary" before
|
||||
+ // setting the "NSNonactivatingPanelMask" bit in the style mask it won't work after that.
|
||||
+ // So we need a way to set that bit before Qt sets collection behavior the way it does.
|
||||
+ QVariant nonactivatingPanelMask = window()->property("_td_macNonactivatingPanelMask");
|
||||
+ if (nonactivatingPanelMask.isValid() && nonactivatingPanelMask.toBool()) {
|
||||
+ styleMask |= NSNonactivatingPanelMask;
|
||||
+ }
|
||||
+
|
||||
if (flags & Qt::FramelessWindowHint)
|
||||
return styleMask;
|
||||
if ((type & Qt::Popup) == Qt::Popup) {
|
||||
@@ -914,6 +925,19 @@ void QCocoaWindow::setWindowFilePath(const QString &filePath)
|
||||
[m_nsWindow setRepresentedFilename: fi.exists() ? QCFString::toNSString(filePath) : @""];
|
||||
}
|
||||
|
||||
+// Patch: Nice macOS window icon.
|
||||
+namespace {
|
||||
+
|
||||
+qreal getDevicePixelRatio() {
|
||||
+ qreal result = 1.0;
|
||||
+ foreach (QScreen *screen, QGuiApplication::screens()) {
|
||||
+ result = qMax(result, screen->devicePixelRatio());
|
||||
+ }
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+} // namespace
|
||||
+
|
||||
void QCocoaWindow::setWindowIcon(const QIcon &icon)
|
||||
{
|
||||
QCocoaAutoReleasePool pool;
|
||||
@@ -929,7 +953,10 @@ void QCocoaWindow::setWindowIcon(const QIcon &icon)
|
||||
if (icon.isNull()) {
|
||||
[iconButton setImage:nil];
|
||||
} else {
|
||||
- QPixmap pixmap = icon.pixmap(QSize(22, 22));
|
||||
+ // Patch: Nice macOS window icon.
|
||||
+ CGFloat hgt = 16. * getDevicePixelRatio();
|
||||
+ QPixmap pixmap = icon.pixmap(QSize(hgt, hgt));
|
||||
+
|
||||
NSImage *image = static_cast<NSImage *>(qt_mac_create_nsimage(pixmap));
|
||||
[iconButton setImage:image];
|
||||
[image release];
|
||||
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
|
||||
index a18ee7ff71..1f91feb0ae 100644
|
||||
--- a/src/plugins/platforms/cocoa/qnsview.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qnsview.mm
|
||||
@@ -393,7 +393,9 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
|
||||
[self notifyWindowStateChanged:newState];
|
||||
// NSWindowDidOrderOnScreenAndFinishAnimatingNotification is private API, and not
|
||||
// emitted in 10.6, so we bring back the old behavior for that case alone.
|
||||
- if (newState == Qt::WindowNoState && QSysInfo::QSysInfo::MacintoshVersion == QSysInfo::MV_10_6)
|
||||
+
|
||||
+ // Patch: Fix macOS window show after window was hidden.
|
||||
+ if (newState == Qt::WindowNoState/* && QSysInfo::QSysInfo::MacintoshVersion == QSysInfo::MV_10_6*/)
|
||||
m_platformWindow->exposeWindow();
|
||||
} else if ([notificationName isEqualToString: @"NSWindowDidOrderOffScreenNotification"]) {
|
||||
m_platformWindow->obscureWindow();
|
||||
@@ -1300,7 +1302,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
|
||||
if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
|
||||
// On 10.8 and above, MayBegin is likely to happen. We treat it the same as an actual begin.
|
||||
- if (phase == NSEventPhaseMayBegin)
|
||||
+
|
||||
+ // Patch: Actual begin should be treated as begin as well.
|
||||
+ if (phase == NSEventPhaseMayBegin || phase == NSEventPhaseBegan)
|
||||
ph = Qt::ScrollBegin;
|
||||
} else
|
||||
#endif
|
||||
@@ -1366,14 +1370,22 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
|
||||
quint32 nativeVirtualKey = [nsevent keyCode];
|
||||
|
||||
QChar ch = QChar::ReplacementCharacter;
|
||||
- int keyCode = Qt::Key_unknown;
|
||||
- if ([characters length] != 0) {
|
||||
- if (((modifiers & Qt::MetaModifier) || (modifiers & Qt::AltModifier)) && ([charactersIgnoringModifiers length] != 0))
|
||||
- ch = QChar([charactersIgnoringModifiers characterAtIndex:0]);
|
||||
- else
|
||||
- ch = QChar([characters characterAtIndex:0]);
|
||||
- keyCode = [self convertKeyCode:ch];
|
||||
- }
|
||||
+
|
||||
+ // Patch: Backport a fix for layout-independent shortcuts.
|
||||
+ if ([characters length] != 0) // https://bugreports.qt.io/browse/QTBUG-42584
|
||||
+ ch = QChar([characters characterAtIndex:0]);
|
||||
+ else if ([charactersIgnoringModifiers length] != 0 && ((modifiers & Qt::MetaModifier) || (modifiers & Qt::AltModifier)))
|
||||
+ ch = QChar([charactersIgnoringModifiers characterAtIndex:0]);
|
||||
+
|
||||
+ int keyCode = [self convertKeyCode:ch];
|
||||
+ //int keyCode = Qt::Key_unknown;
|
||||
+ //if ([characters length] != 0) {
|
||||
+ // if (((modifiers & Qt::MetaModifier) || (modifiers & Qt::AltModifier)) && ([charactersIgnoringModifiers length] != 0))
|
||||
+ // ch = QChar([charactersIgnoringModifiers characterAtIndex:0]);
|
||||
+ // else
|
||||
+ // ch = QChar([characters characterAtIndex:0]);
|
||||
+ // keyCode = [self convertKeyCode:ch];
|
||||
+ //}
|
||||
|
||||
// we will send a key event unless the input method sets m_sendKeyEvent to false
|
||||
m_sendKeyEvent = true;
|
||||
@@ -1437,6 +1449,11 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
|
||||
&& qtKey == Qt::Key_Period) {
|
||||
[self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)];
|
||||
return YES;
|
||||
+
|
||||
+ // Patch: Allow us to handle Ctrl+Tab and Ctrl+Backtab in the app.
|
||||
+ } else if ([nsevent modifierFlags] & NSControlKeyMask && (qtKey == Qt::Key_Tab || qtKey == Qt::Key_Backtab)) {
|
||||
+ [self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)];
|
||||
+ return YES;
|
||||
}
|
||||
}
|
||||
return [super performKeyEquivalent:nsevent];
|
||||
diff --git a/src/tools/qlalr/lalr.cpp b/src/tools/qlalr/lalr.cpp
|
||||
index c68076477f..e2a7aafa58 100644
|
||||
--- a/src/tools/qlalr/lalr.cpp
|
||||
+++ b/src/tools/qlalr/lalr.cpp
|
||||
@@ -246,11 +246,13 @@ void Grammar::buildExtendedGrammar ()
|
||||
non_terminals.insert (accept_symbol);
|
||||
}
|
||||
|
||||
-struct _Nullable: public std::unary_function<Name, bool>
|
||||
+// Patch: Fix building with the new SDK.
|
||||
+struct __Nullable: public std::unary_function<Name, bool>
|
||||
{
|
||||
Automaton *_M_automaton;
|
||||
|
||||
- _Nullable (Automaton *aut):
|
||||
+ // Patch: Fix building with the new SDK.
|
||||
+ __Nullable (Automaton *aut):
|
||||
_M_automaton (aut) {}
|
||||
|
||||
bool operator () (Name name) const
|
||||
@@ -308,7 +310,8 @@ void Automaton::buildNullables ()
|
||||
|
||||
for (RulePointer rule = _M_grammar->rules.begin (); rule != _M_grammar->rules.end (); ++rule)
|
||||
{
|
||||
- NameList::iterator nn = std::find_if (rule->rhs.begin (), rule->rhs.end (), std::not1 (_Nullable (this)));
|
||||
+ // Patch: Fix building with the new SDK.
|
||||
+ NameList::iterator nn = std::find_if (rule->rhs.begin (), rule->rhs.end (), std::not1 (__Nullable (this)));
|
||||
|
||||
if (nn == rule->rhs.end ())
|
||||
changed |= nullables.insert (rule->lhs).second;
|
||||
@@ -643,7 +646,8 @@ void Automaton::buildIncludesDigraph ()
|
||||
if (! _M_grammar->isNonTerminal (*A))
|
||||
continue;
|
||||
|
||||
- NameList::iterator first_not_nullable = std::find_if (dot, rule->rhs.end (), std::not1 (_Nullable (this)));
|
||||
+ // Patch: Fix building with the new SDK.
|
||||
+ NameList::iterator first_not_nullable = std::find_if (dot, rule->rhs.end (), std::not1 (__Nullable (this)));
|
||||
if (first_not_nullable != rule->rhs.end ())
|
||||
continue;
|
||||
|
||||
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
|
||||
index 7396808442..7178aecf80 100644
|
||||
--- a/src/widgets/kernel/qwidget.cpp
|
||||
+++ b/src/widgets/kernel/qwidget.cpp
|
||||
@@ -4722,6 +4722,17 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset,
|
||||
return; // Fully transparent.
|
||||
|
||||
Q_D(QWidget);
|
||||
+
|
||||
+ // Patch: save and restore dirtyOpaqueChildren field.
|
||||
+ //
|
||||
+ // Just like in QWidget::grab() this field should be restored
|
||||
+ // after the d->render() call, because it will be set to 1 and
|
||||
+ // opaqueChildren field will be filled with empty region in
|
||||
+ // case the widget is hidden (because all the opaque children
|
||||
+ // will be skipped in isVisible() check).
|
||||
+ //
|
||||
+ const bool oldDirtyOpaqueChildren = d->dirtyOpaqueChildren;
|
||||
+
|
||||
const bool inRenderWithPainter = d->extra && d->extra->inRenderWithPainter;
|
||||
const QRegion toBePainted = !inRenderWithPainter ? d->prepareToRender(sourceRegion, renderFlags)
|
||||
: sourceRegion;
|
||||
@@ -4743,6 +4754,10 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset,
|
||||
if (!inRenderWithPainter && (opacity < 1.0 || (target->devType() == QInternal::Printer))) {
|
||||
d->render_helper(painter, targetOffset, toBePainted, renderFlags);
|
||||
d->extra->inRenderWithPainter = inRenderWithPainter;
|
||||
+
|
||||
+ // Patch: save and restore dirtyOpaqueChildren field.
|
||||
+ d->dirtyOpaqueChildren = oldDirtyOpaqueChildren;
|
||||
+
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4774,6 +4789,9 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset,
|
||||
d->setSharedPainter(oldPainter);
|
||||
|
||||
d->extra->inRenderWithPainter = inRenderWithPainter;
|
||||
+
|
||||
+ // Patch: save and restore dirtyOpaqueChildren field.
|
||||
+ d->dirtyOpaqueChildren = oldDirtyOpaqueChildren;
|
||||
}
|
||||
|
||||
static void sendResizeEvents(QWidget *target)
|
||||
@@ -7983,7 +8001,8 @@ bool QWidget::event(QEvent *event)
|
||||
case QEvent::KeyPress: {
|
||||
QKeyEvent *k = (QKeyEvent *)event;
|
||||
bool res = false;
|
||||
- if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier?
|
||||
+ // Patch: Allow us to handle Ctrl+Tab and Ctrl+Backtab in the app.
|
||||
+ if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))) { //### Add MetaModifier?
|
||||
if (k->key() == Qt::Key_Backtab
|
||||
|| (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier)))
|
||||
res = focusNextPrevChild(false);
|
||||
diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm
|
||||
index 0845a5eb02..5735cb6b39 100644
|
||||
--- a/src/widgets/styles/qmacstyle_mac.mm
|
||||
+++ b/src/widgets/styles/qmacstyle_mac.mm
|
||||
@@ -3667,9 +3667,11 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
|
||||
|
||||
NSBezierPath *pushButtonFocusRingPath;
|
||||
if (bdi.kind == kThemeBevelButton)
|
||||
- pushButtonFocusRingPath = [NSBezierPath bezierPathWithRect:focusRect];
|
||||
+ // Patch: Fix building with the new SDK.
|
||||
+ pushButtonFocusRingPath = [NSBezierPath bezierPathWithRect:NSRectFromCGRect(focusRect)];
|
||||
else
|
||||
- pushButtonFocusRingPath = [NSBezierPath bezierPathWithRoundedRect:focusRect xRadius:4 yRadius:4];
|
||||
+ // Patch: Fix building with the new SDK.
|
||||
+ pushButtonFocusRingPath = [NSBezierPath bezierPathWithRoundedRect:NSRectFromCGRect(focusRect) xRadius:4 yRadius:4];
|
||||
qt_drawFocusRingOnPath(cg, pushButtonFocusRingPath);
|
||||
}
|
||||
|
||||
diff --git a/src/widgets/util/qsystemtrayicon_qpa.cpp b/src/widgets/util/qsystemtrayicon_qpa.cpp
|
||||
index f98aeaf678..00c0734129 100644
|
||||
--- a/src/widgets/util/qsystemtrayicon_qpa.cpp
|
||||
+++ b/src/widgets/util/qsystemtrayicon_qpa.cpp
|
||||
@@ -99,13 +99,18 @@ void QSystemTrayIconPrivate::updateIcon_sys()
|
||||
|
||||
void QSystemTrayIconPrivate::updateMenu_sys()
|
||||
{
|
||||
- if (qpa_sys && menu) {
|
||||
- if (!menu->platformMenu()) {
|
||||
- QPlatformMenu *platformMenu = qpa_sys->createMenu();
|
||||
- if (platformMenu)
|
||||
- menu->setPlatformMenu(platformMenu);
|
||||
+ // Patch: Nice macOS tray icon support.
|
||||
+ if (qpa_sys) {
|
||||
+ if (menu) {
|
||||
+ if (!menu->platformMenu()) {
|
||||
+ QPlatformMenu *platformMenu = qpa_sys->createMenu();
|
||||
+ if (platformMenu)
|
||||
+ menu->setPlatformMenu(platformMenu);
|
||||
+ }
|
||||
+ qpa_sys->updateMenu(menu->platformMenu());
|
||||
+ } else {
|
||||
+ qpa_sys->updateMenu(0);
|
||||
}
|
||||
- qpa_sys->updateMenu(menu->platformMenu());
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp
|
||||
index 75f30599be..980f2be1e9 100644
|
||||
--- a/src/widgets/widgets/qwidgetlinecontrol.cpp
|
||||
+++ b/src/widgets/widgets/qwidgetlinecontrol.cpp
|
||||
@@ -1867,7 +1867,8 @@ void QWidgetLineControl::processKeyEvent(QKeyEvent* event)
|
||||
|
||||
if (unknown && !isReadOnly()) {
|
||||
QString t = event->text();
|
||||
- if (!t.isEmpty() && t.at(0).isPrint()) {
|
||||
+ // Patch: Enable ZWJ and ZWNJ characters to be in text input.
|
||||
+ if (!t.isEmpty() && (t.at(0).isPrint() || t.at(0).unicode() == 0x200C || t.at(0).unicode() == 0x200D)) {
|
||||
insert(t);
|
||||
#ifndef QT_NO_COMPLETER
|
||||
complete(event->key());
|
||||
diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp
|
||||
index 96438a0bdf..b0b7206405 100644
|
||||
--- a/src/widgets/widgets/qwidgettextcontrol.cpp
|
||||
+++ b/src/widgets/widgets/qwidgettextcontrol.cpp
|
||||
@@ -1342,7 +1342,8 @@ void QWidgetTextControlPrivate::keyPressEvent(QKeyEvent *e)
|
||||
process:
|
||||
{
|
||||
QString text = e->text();
|
||||
- if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t'))) {
|
||||
+ // Patch: Enable ZWJ and ZWNJ characters to be in text input.
|
||||
+ if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t') || text.at(0).unicode() == 0x200C || text.at(0).unicode() == 0x200D)) {
|
||||
if (overwriteMode
|
||||
// no need to call deleteChar() if we have a selection, insertText
|
||||
// does it already
|
||||
@@ -1,47 +0,0 @@
|
||||
diff --git a/src/3rdparty/libwebp/src/dec/vp8l.c b/src/3rdparty/libwebp/src/dec/vp8l.c
|
||||
index ea0254d..953ff01 100644
|
||||
--- a/src/3rdparty/libwebp/src/dec/vp8l.c
|
||||
+++ b/src/3rdparty/libwebp/src/dec/vp8l.c
|
||||
@@ -12,7 +12,7 @@
|
||||
// Authors: Vikas Arora (vikaas.arora@gmail.com)
|
||||
// Jyrki Alakuijala (jyrki@google.com)
|
||||
|
||||
-#include <stdio.h>
|
||||
+// Patch: Backport of a crash fix.
|
||||
#include <stdlib.h>
|
||||
#include "./alphai.h"
|
||||
#include "./vp8li.h"
|
||||
@@ -740,6 +740,10 @@ static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data,
|
||||
const int len_code_limit = NUM_LITERAL_CODES + NUM_LENGTH_CODES;
|
||||
const int mask = hdr->huffman_mask_;
|
||||
assert(htree_group != NULL);
|
||||
+
|
||||
+ // Patch: Backport of a crash fix.
|
||||
+ assert(pos < end);
|
||||
+
|
||||
assert(last_row <= height);
|
||||
assert(Is8bOptimizable(hdr));
|
||||
|
||||
@@ -830,6 +834,10 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
|
||||
(hdr->color_cache_size_ > 0) ? &hdr->color_cache_ : NULL;
|
||||
const int mask = hdr->huffman_mask_;
|
||||
assert(htree_group != NULL);
|
||||
+
|
||||
+ // Patch: Backport of a crash fix.
|
||||
+ assert(src < src_end);
|
||||
+
|
||||
assert(src_last <= src_end);
|
||||
|
||||
while (!br->eos_ && src < src_last) {
|
||||
@@ -1294,6 +1302,11 @@ int VP8LDecodeAlphaImageStream(ALPHDecoder* const alph_dec, int last_row) {
|
||||
assert(dec->action_ == READ_DATA);
|
||||
assert(last_row <= dec->height_);
|
||||
|
||||
+ // Patch: Backport of a crash fix.
|
||||
+ if (dec->last_pixel_ == dec->width_ * dec->height_) {
|
||||
+ return 1; // done
|
||||
+ }
|
||||
+
|
||||
// Decode (with special row processing).
|
||||
return alph_dec->use_8b_decode ?
|
||||
DecodeAlphaData(dec, (uint8_t*)dec->pixels_, dec->width_, dec->height_,
|
||||
@@ -1,52 +0,0 @@
|
||||
diff --git a/base/mac/scoped_nsobject.h b/base/mac/scoped_nsobject.h
|
||||
index 2e157a4..5a306a1 100644
|
||||
--- a/base/mac/scoped_nsobject.h
|
||||
+++ b/base/mac/scoped_nsobject.h
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/mac/scoped_typeref.h"
|
||||
+#include "base/template_util.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
@@ -55,7 +56,7 @@ class scoped_nsobject : public scoped_nsprotocol<NST*> {
|
||||
public:
|
||||
using scoped_nsprotocol<NST*>::scoped_nsprotocol;
|
||||
|
||||
- static_assert(std::is_same<NST, NSAutoreleasePool>::value == false,
|
||||
+ static_assert(is_same<NST, NSAutoreleasePool>::value == false,
|
||||
"Use ScopedNSAutoreleasePool instead");
|
||||
};
|
||||
|
||||
diff --git a/base/macros.h b/base/macros.h
|
||||
index 5d96783..096704c 100644
|
||||
--- a/base/macros.h
|
||||
+++ b/base/macros.h
|
||||
@@ -42,8 +42,9 @@ char (&ArraySizeHelper(const T (&array)[N]))[N];
|
||||
|
||||
template <typename Dest, typename Source>
|
||||
inline Dest bit_cast(const Source& source) {
|
||||
+#if __cplusplus >= 201103L
|
||||
static_assert(sizeof(Dest) == sizeof(Source), "sizes must be equal");
|
||||
-
|
||||
+#endif
|
||||
Dest dest;
|
||||
memcpy(&dest, &source, sizeof(dest));
|
||||
return dest;
|
||||
diff --git a/build/common.gypi b/build/common.gypi
|
||||
index 1affc70..6e8f292 100644
|
||||
--- a/build/common.gypi
|
||||
+++ b/build/common.gypi
|
||||
@@ -66,6 +66,11 @@
|
||||
'conditions': [
|
||||
['clang!=0', {
|
||||
'CLANG_CXX_LANGUAGE_STANDARD': 'c++11', # -std=c++11
|
||||
+ 'conditions': [
|
||||
+ ['mac_deployment_target=="10.8"', {
|
||||
+ 'CLANG_CXX_LIBRARY': 'libc++', # force -stdlib=libc++ for 10.8
|
||||
+ }]
|
||||
+ ],
|
||||
|
||||
# Don't link in libarclite_macosx.a, see http://crbug.com/156530.
|
||||
'CLANG_LINK_OBJC_RUNTIME': 'NO', # -fno-objc-link-runtime
|
||||
@@ -1,22 +0,0 @@
|
||||
diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c
|
||||
index 9d8f8e9..8c8e44a 100644
|
||||
--- a/Alc/backends/winmm.c
|
||||
+++ b/Alc/backends/winmm.c
|
||||
@@ -219,7 +219,7 @@ FORCE_ALIGN static int ALCwinmmPlayback_mixerProc(void *arg)
|
||||
SetRTPriority();
|
||||
althrd_setname(althrd_current(), MIXER_THREAD_NAME);
|
||||
|
||||
- while(GetMessage(&msg, NULL, 0, 0))
|
||||
+ if (!self->killNow) while(GetMessage(&msg, NULL, 0, 0))
|
||||
{
|
||||
if(msg.message != WOM_DONE)
|
||||
continue;
|
||||
@@ -504,7 +504,7 @@ static int ALCwinmmCapture_captureProc(void *arg)
|
||||
|
||||
althrd_setname(althrd_current(), RECORD_THREAD_NAME);
|
||||
|
||||
- while(GetMessage(&msg, NULL, 0, 0))
|
||||
+ if (!self->killNow) while(GetMessage(&msg, NULL, 0, 0))
|
||||
{
|
||||
if(msg.message != WIM_DATA)
|
||||
continue;
|
||||
BIN
Telegram/Resources/art/background.jpg
Normal file
|
After Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 105 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 826 B After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 361 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 21 KiB |
BIN
Telegram/Resources/icons/calls/video_mini_invited.png
Normal file
|
After Width: | Height: | Size: 359 B |
BIN
Telegram/Resources/icons/calls/video_mini_invited@2x.png
Normal file
|
After Width: | Height: | Size: 503 B |
BIN
Telegram/Resources/icons/calls/video_mini_invited@3x.png
Normal file
|
After Width: | Height: | Size: 878 B |
BIN
Telegram/Resources/icons/chat/input_autodelete_30d.png
Normal file
|
After Width: | Height: | Size: 1010 B |
BIN
Telegram/Resources/icons/chat/input_autodelete_30d@2x.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
Telegram/Resources/icons/chat/input_autodelete_30d@3x.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
Telegram/Resources/icons/info_media_gif.png
Normal file
|
After Width: | Height: | Size: 666 B |
BIN
Telegram/Resources/icons/info_media_gif@2x.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Telegram/Resources/icons/info_media_gif@3x.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
@@ -1,34 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
FullExecPath=$PWD
|
||||
pushd `dirname $0` > /dev/null
|
||||
FullScriptPath=`pwd`
|
||||
popd > /dev/null
|
||||
|
||||
if [ ! -d "$FullScriptPath/../../../../DesktopPrivate" ]; then
|
||||
echo ""
|
||||
echo "This script is for building the production version of Telegram Desktop."
|
||||
echo ""
|
||||
echo "For building custom versions please visit the build instructions page at:"
|
||||
echo "https://github.com/telegramdesktop/tdesktop/#build-instructions"
|
||||
exit
|
||||
fi
|
||||
|
||||
Error () {
|
||||
cd $FullExecPath
|
||||
echo "$1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
cd $FullScriptPath/../../../../
|
||||
while IFS='' read -r line || [[ -n "$line" ]]; do
|
||||
tx pull -f -l $line --minimum-perc=100
|
||||
done < tdesktop/Telegram/Resources/langs/list
|
||||
cd translations/telegram-desktop.langstrings/
|
||||
for file in *.strings; do
|
||||
iconv -f "UTF-16LE" -t "UTF-8" "$file" > "../../tdesktop/Telegram/Resources/langs/lang_$file.tmp"
|
||||
awk '{ if (NR==1) sub(/^\xef\xbb\xbf/,""); sub(/
|
||||
/,""); print }' "../../tdesktop/Telegram/Resources/langs/lang_$file.tmp" > "../../tdesktop/Telegram/Resources/langs/lang_$file"
|
||||
rm "../../tdesktop/Telegram/Resources/langs/lang_$file.tmp"
|
||||
done
|
||||
|
||||
@@ -82,6 +82,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_box_ok" = "OK";
|
||||
"lng_box_done" = "Done";
|
||||
"lng_box_yes" = "Yes";
|
||||
"lng_box_no" = "No";
|
||||
|
||||
"lng_cancel" = "Cancel";
|
||||
"lng_continue" = "Continue";
|
||||
@@ -575,6 +577,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_passcode_autolock_minutes#other" = "{count} minutes";
|
||||
"lng_passcode_autolock_hours#one" = "{count} hour";
|
||||
"lng_passcode_autolock_hours#other" = "{count} hours";
|
||||
"lng_passcode_autolock_hours_minutes" = "{hours_count}h {minutes_count}m";
|
||||
"lng_passcode_enter_old" = "Enter current passcode";
|
||||
"lng_passcode_enter_first" = "Enter a passcode";
|
||||
"lng_passcode_enter_new" = "Enter new passcode";
|
||||
@@ -596,6 +599,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_cloud_password_remove" = "Remove cloud password";
|
||||
"lng_cloud_password_set" = "Enable two-step verification";
|
||||
"lng_cloud_password_edit" = "Change cloud password";
|
||||
"lng_cloud_password_reset_in" = "Reset password in";
|
||||
"lng_cloud_password_reset_ready" = "Reset password";
|
||||
"lng_cloud_password_reset_cancel" = "Cancel password reset";
|
||||
"lng_cloud_password_enter_old" = "Enter current password";
|
||||
"lng_cloud_password_enter_first" = "Enter a password";
|
||||
"lng_cloud_password_enter_new" = "Enter new password";
|
||||
@@ -618,6 +624,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_cloud_password_passport_losing" = "Warning! All data saved in your Telegram Passport will be lost!";
|
||||
"lng_cloud_password_resend" = "Resend code";
|
||||
"lng_cloud_password_resent" = "Code was resent.";
|
||||
"lng_cloud_password_reset_title" = "Reset password";
|
||||
"lng_cloud_password_reset_no_email" = "Since you didn't provide a recovery email when setting up your password, your remaining options are either to remember your password or wait 7 days until your password is reset.";
|
||||
"lng_cloud_password_reset_with_email" = "If you don't have access to your recovery email, your remaining options are either to remember your password or wait 7 days until your password resets.";
|
||||
"lng_cloud_password_reset_ok" = "Reset";
|
||||
"lng_cloud_password_reset_cancel_title" = "Cancel reset";
|
||||
"lng_cloud_password_reset_cancel_sure" = "Cancel the password reset process? If you request a new reset later, it will take another 7 days.";
|
||||
"lng_cloud_password_reset_later" = "You recently requested a password reset that was cancelled. Please wait {duration} before making a new request.";
|
||||
|
||||
"lng_connection_auto_connecting" = "Default (connecting...)";
|
||||
"lng_connection_auto" = "Default ({transport} used)";
|
||||
@@ -862,6 +875,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_profile_photos#one" = "{count} photo";
|
||||
"lng_profile_photos#other" = "{count} photos";
|
||||
"lng_profile_photos_header" = "Photos";
|
||||
"lng_profile_gifs#one" = "{count} GIF";
|
||||
"lng_profile_gifs#other" = "{count} GIFs";
|
||||
"lng_profile_gifs_header" = "GIFs";
|
||||
"lng_profile_videos#one" = "{count} video";
|
||||
"lng_profile_videos#other" = "{count} videos";
|
||||
"lng_profile_videos_header" = "Videos";
|
||||
@@ -904,6 +920,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_info_add_as_contact" = "Add to contacts";
|
||||
"lng_profile_shared_media" = "Shared media";
|
||||
"lng_media_type_photos" = "Photos";
|
||||
"lng_media_type_gifs" = "GIFs";
|
||||
"lng_media_type_videos" = "Videos";
|
||||
"lng_media_type_songs" = "Audio files";
|
||||
"lng_media_type_files" = "Files";
|
||||
@@ -923,6 +940,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_profile_export_channel" = "Export channel history";
|
||||
"lng_media_selected_photo#one" = "{count} Photo";
|
||||
"lng_media_selected_photo#other" = "{count} Photos";
|
||||
"lng_media_selected_gif#one" = "{count} GIF";
|
||||
"lng_media_selected_gif#other" = "{count} GIFs";
|
||||
"lng_media_selected_video#one" = "{count} Video";
|
||||
"lng_media_selected_video#other" = "{count} Videos";
|
||||
"lng_media_selected_song#one" = "{count} Audio file";
|
||||
@@ -936,6 +955,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_media_selected_link#one" = "{count} Shared link";
|
||||
"lng_media_selected_link#other" = "{count} Shared links";
|
||||
"lng_media_photo_empty" = "No photos here yet";
|
||||
"lng_media_gif_empty" = "No GIFs here yet";
|
||||
"lng_media_video_empty" = "No videos here yet";
|
||||
"lng_media_song_empty" = "No music files here yet";
|
||||
"lng_media_file_empty" = "No files here yet";
|
||||
@@ -998,8 +1018,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_manage_messages_ttl_title" = "Auto-delete messages";
|
||||
"lng_manage_messages_ttl_never" = "Off";
|
||||
"lng_manage_messages_ttl_after1" = "24 hours";
|
||||
"lng_manage_messages_ttl_after2" = "7 days";
|
||||
"lng_manage_messages_ttl_after1" = "1 day";
|
||||
"lng_manage_messages_ttl_after2" = "1 week";
|
||||
"lng_manage_messages_ttl_after3" = "1 month";
|
||||
|
||||
"lng_ttl_edit_about" = "Automatically delete new messages after a certain period of time for you and {user}.";
|
||||
"lng_ttl_edit_about_group" = "Automatically delete new messages sent in this chat after a certain period of time.";
|
||||
@@ -1008,8 +1029,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_ttl_about_tooltip" = "New messages in this chat will be automatically deleted in {duration}.";
|
||||
"lng_ttl_about_tooltip_channel" = "New messages in this chat will be automatically deleted in {duration}.";
|
||||
"lng_ttl_about_tooltip_off" = "Auto-delete is now disabled.";
|
||||
"lng_ttl_about_duration1" = "24 hours";
|
||||
"lng_ttl_about_duration2" = "7 days";
|
||||
"lng_ttl_about_duration1" = "1 day";
|
||||
"lng_ttl_about_duration2" = "1 week";
|
||||
"lng_ttl_about_duration3" = "1 month";
|
||||
|
||||
"lng_report_title" = "Report channel";
|
||||
"lng_report_group_title" = "Report group";
|
||||
@@ -1494,6 +1516,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_saved_forward_here" = "Forward messages here for quick access";
|
||||
|
||||
"lng_scheduled_messages" = "Scheduled Messages";
|
||||
"lng_scheduled_messages_empty" = "No scheduled messages here yet...";
|
||||
"lng_reminder_messages" = "Reminders";
|
||||
"lng_scheduled_date" = "Scheduled for {date}";
|
||||
"lng_scheduled_date_until_online" = "Scheduled until online";
|
||||
@@ -1618,6 +1641,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_context_mark_read_sure" = "Are you sure you want to mark all chats from this folder as read?";
|
||||
"lng_context_mark_read_all" = "Mark all chats as read";
|
||||
"lng_context_mark_read_all_sure" = "Are you sure you want to mark all chats as read?";
|
||||
"lng_context_mark_read_mentions_all" = "Mark all mentions as read";
|
||||
"lng_context_archive_expand" = "Expand";
|
||||
"lng_context_archive_collapse" = "Collapse";
|
||||
"lng_context_archive_to_menu" = "Move to main menu";
|
||||
@@ -2001,6 +2025,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_call_start_video" = "Start Video";
|
||||
"lng_call_stop_video" = "Stop Video";
|
||||
"lng_call_screencast" = "Screencast";
|
||||
"lng_call_end_call" = "End Call";
|
||||
"lng_call_mute_audio" = "Mute";
|
||||
"lng_call_unmute_audio" = "Unmute";
|
||||
@@ -2080,6 +2105,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_group_call_noise_suppression" = "Enable Noise Suppression";
|
||||
"lng_group_call_limit#one" = "Video is only available\nfor the first {count} member";
|
||||
"lng_group_call_limit#other" = "Video is only available\nfor the first {count} members";
|
||||
"lng_group_call_over_limit#one" = "The voice chat is over {count} member.\nNew participants only have access to audio stream.";
|
||||
"lng_group_call_over_limit#other" = "The voice chat is over {count} members.\nNew participants only have access to audio stream.";
|
||||
"lng_group_call_video_paused" = "Video is paused";
|
||||
"lng_group_call_share_speaker" = "Users with this link can speak";
|
||||
"lng_group_call_copy_speaker_link" = "Copy Speaker Link";
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
de,es,it,ko,nl,pt_BR
|
||||
@@ -1,29 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
FullExecPath=$PWD
|
||||
pushd `dirname $0` > /dev/null
|
||||
FullScriptPath=`pwd`
|
||||
popd > /dev/null
|
||||
|
||||
if [ ! -d "$FullScriptPath/../../../../DesktopPrivate" ]; then
|
||||
echo ""
|
||||
echo "This script is for building the production version of Telegram Desktop."
|
||||
echo ""
|
||||
echo "For building custom versions please visit the build instructions page at:"
|
||||
echo "https://github.com/telegramdesktop/tdesktop/#build-instructions"
|
||||
exit
|
||||
fi
|
||||
|
||||
Error () {
|
||||
cd $FullExecPath
|
||||
echo "$1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
cd $FullScriptPath/../../../../
|
||||
while IFS='' read -r line || [[ -n "$line" ]]; do
|
||||
tx pull -f -l $line
|
||||
done < tdesktop/Telegram/Resources/langs/list
|
||||
tx push -s
|
||||
|
||||
cd $FullExecPath
|
||||
@@ -42,7 +42,7 @@
|
||||
<file alias="js/script.js">../../export_html/js/script.js</file>
|
||||
</qresource>
|
||||
<qresource prefix="/gui">
|
||||
<file alias="art/bg.jpg">../../art/bg.jpg</file>
|
||||
<file alias="art/background.jpg">../../art/background.jpg</file>
|
||||
<file alias="art/bg_initial.jpg">../../art/bg_initial.jpg</file>
|
||||
<file alias="art/logo_256.png">../../art/logo_256.png</file>
|
||||
<file alias="art/logo_256_no_margin.png">../../art/logo_256_no_margin.png</file>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="2.8.9.0" />
|
||||
Version="2.9.6.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||
|
||||
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,8,9,0
|
||||
PRODUCTVERSION 2,8,9,0
|
||||
FILEVERSION 2,9,6,0
|
||||
PRODUCTVERSION 2,9,6,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.8.9.0"
|
||||
VALUE "FileVersion", "2.9.6.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2021"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "2.8.9.0"
|
||||
VALUE "ProductVersion", "2.9.6.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,8,9,0
|
||||
PRODUCTVERSION 2,8,9,0
|
||||
FILEVERSION 2,9,6,0
|
||||
PRODUCTVERSION 2,9,6,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.8.9.0"
|
||||
VALUE "FileVersion", "2.9.6.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2021"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "2.8.9.0"
|
||||
VALUE "ProductVersion", "2.9.6.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -160,8 +160,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
QString remove;
|
||||
int version = 0;
|
||||
bool targetosx = false;
|
||||
bool targetwin64 = false;
|
||||
[[maybe_unused]] bool targetwin64 = false;
|
||||
QFileInfoList files;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if (string("-path") == argv[i] && i + 1 < argc) {
|
||||
@@ -170,7 +169,6 @@ int main(int argc, char *argv[])
|
||||
files.push_back(info);
|
||||
if (remove.isEmpty()) remove = info.canonicalPath() + "/";
|
||||
} else if (string("-target") == argv[i] && i + 1 < argc) {
|
||||
targetosx = (string("osx") == argv[i + 1]);
|
||||
targetwin64 = (string("win64") == argv[i + 1]);
|
||||
} else if (string("-version") == argv[i] && i + 1 < argc) {
|
||||
version = QString(argv[i + 1]).toInt();
|
||||
@@ -496,13 +494,9 @@ int main(int argc, char *argv[])
|
||||
#ifdef Q_OS_WIN
|
||||
QString outName((targetwin64 ? QString("tx64upd%1") : 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));
|
||||
QString outName(QString("tmacupd%1").arg(AlphaVersion ? AlphaVersion : version));
|
||||
#elif defined Q_OS_UNIX
|
||||
#ifndef _LP64
|
||||
QString outName(QString("tlinux32upd%1").arg(AlphaVersion ? AlphaVersion : version));
|
||||
#else
|
||||
QString outName(QString("tlinuxupd%1").arg(AlphaVersion ? AlphaVersion : version));
|
||||
#endif
|
||||
#else
|
||||
#error Unknown platform!
|
||||
#endif
|
||||
|
||||
@@ -384,8 +384,6 @@ int main(int argc, char *argv[]) {
|
||||
bool writeprotected = false;
|
||||
bool tosettings = false;
|
||||
bool startintray = false;
|
||||
bool testmode = false;
|
||||
bool externalupdater = false;
|
||||
bool customWorkingDir = false;
|
||||
|
||||
char *key = 0;
|
||||
@@ -399,10 +397,6 @@ int main(int argc, char *argv[]) {
|
||||
debug = _debug = true;
|
||||
} else if (equal(argv[i], "-startintray")) {
|
||||
startintray = true;
|
||||
} else if (equal(argv[i], "-testmode")) {
|
||||
testmode = true;
|
||||
} else if (equal(argv[i], "-externalupdater")) {
|
||||
externalupdater = true;
|
||||
} else if (equal(argv[i], "-tosettings")) {
|
||||
tosettings = true;
|
||||
} else if (equal(argv[i], "-workdir_custom")) {
|
||||
@@ -503,8 +497,6 @@ int main(int argc, char *argv[]) {
|
||||
if (autostart) push("-autostart");
|
||||
if (debug) push("-debug");
|
||||
if (startintray) push("-startintray");
|
||||
if (testmode) push("-testmode");
|
||||
if (externalupdater) push("-externalupdater");
|
||||
if (tosettings) push("-tosettings");
|
||||
if (key) {
|
||||
push("-key");
|
||||
|
||||
@@ -90,7 +90,7 @@ int main(int argc, const char * argv[]) {
|
||||
|
||||
openLog();
|
||||
pid_t procId = 0;
|
||||
BOOL update = YES, toSettings = NO, autoStart = NO, startInTray = NO, testMode = NO, freeType = NO, externalUpdater = NO;
|
||||
BOOL update = YES, toSettings = NO, autoStart = NO, startInTray = NO, freeType = NO;
|
||||
BOOL customWorkingDir = NO;
|
||||
NSString *key = nil;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
@@ -114,12 +114,8 @@ int main(int argc, const char * argv[]) {
|
||||
_debug = YES;
|
||||
} else if ([@"-startintray" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
|
||||
startInTray = YES;
|
||||
} else if ([@"-testmode" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
|
||||
testMode = YES;
|
||||
} else if ([@"-freetype" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
|
||||
freeType = YES;
|
||||
} else if ([@"-externalupdater" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
|
||||
externalUpdater = YES;
|
||||
} else if ([@"-workdir_custom" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
|
||||
customWorkingDir = YES;
|
||||
} else if ([@"-key" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
|
||||
@@ -256,9 +252,7 @@ int main(int argc, const char * argv[]) {
|
||||
if (toSettings) [args addObject:@"-tosettings"];
|
||||
if (_debug) [args addObject:@"-debug"];
|
||||
if (startInTray) [args addObject:@"-startintray"];
|
||||
if (testMode) [args addObject:@"-testmode"];
|
||||
if (freeType) [args addObject:@"-freetype"];
|
||||
if (externalUpdater) [args addObject:@"-externalupdater"];
|
||||
if (autoStart) [args addObject:@"-autostart"];
|
||||
if (key) {
|
||||
[args addObject:@"-key"];
|
||||
|
||||
@@ -343,7 +343,7 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdPara
|
||||
LPWSTR *args;
|
||||
int argsCount;
|
||||
|
||||
bool needupdate = false, autostart = false, debug = false, writeprotected = false, startintray = false, testmode = false, freetype = false, externalupdater = false;
|
||||
bool needupdate = false, autostart = false, debug = false, writeprotected = false, startintray = false, freetype = false;
|
||||
args = CommandLineToArgvW(GetCommandLine(), &argsCount);
|
||||
if (args) {
|
||||
for (int i = 1; i < argsCount; ++i) {
|
||||
@@ -357,12 +357,8 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdPara
|
||||
openLog();
|
||||
} else if (equal(args[i], L"-startintray")) {
|
||||
startintray = true;
|
||||
} else if (equal(args[i], L"-testmode")) {
|
||||
testmode = true;
|
||||
} else if (equal(args[i], L"-freetype")) {
|
||||
freetype = true;
|
||||
} else if (equal(args[i], L"-externalupdater")) {
|
||||
externalupdater = true;
|
||||
} else if (equal(args[i], L"-writeprotected") && ++i < argsCount) {
|
||||
writeLog(std::wstring(L"Argument: ") + args[i]);
|
||||
writeprotected = true;
|
||||
@@ -432,9 +428,7 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdPara
|
||||
if (autostart) targs += L" -autostart";
|
||||
if (debug) targs += L" -debug";
|
||||
if (startintray) targs += L" -startintray";
|
||||
if (testmode) targs += L" -testmode";
|
||||
if (freetype) targs += L" -freetype";
|
||||
if (externalupdater) targs += L" -externalupdater";
|
||||
if (!customWorkingDir.empty()) {
|
||||
targs += L" -workdir \"" + customWorkingDir + L"\"";
|
||||
}
|
||||
|
||||
173
Telegram/SourceFiles/api/api_blocked_peers.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "api/api_blocked_peers.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_peer_id.h"
|
||||
#include "data/data_session.h"
|
||||
#include "main/main_session.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
constexpr auto kBlockedFirstSlice = 16;
|
||||
constexpr auto kBlockedPerPage = 40;
|
||||
|
||||
BlockedPeers::Slice TLToSlice(
|
||||
const MTPcontacts_Blocked &blocked,
|
||||
Data::Session &owner) {
|
||||
const auto create = [&](int count, const QVector<MTPPeerBlocked> &list) {
|
||||
auto slice = BlockedPeers::Slice();
|
||||
slice.total = std::max(count, list.size());
|
||||
slice.list.reserve(list.size());
|
||||
for (const auto &contact : list) {
|
||||
contact.match([&](const MTPDpeerBlocked &data) {
|
||||
slice.list.push_back({
|
||||
.id = peerFromMTP(data.vpeer_id()),
|
||||
.date = data.vdate().v,
|
||||
});
|
||||
});
|
||||
}
|
||||
return slice;
|
||||
};
|
||||
return blocked.match([&](const MTPDcontacts_blockedSlice &data) {
|
||||
owner.processUsers(data.vusers());
|
||||
owner.processChats(data.vchats());
|
||||
return create(data.vcount().v, data.vblocked().v);
|
||||
}, [&](const MTPDcontacts_blocked &data) {
|
||||
owner.processUsers(data.vusers());
|
||||
owner.processChats(data.vchats());
|
||||
return create(0, data.vblocked().v);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BlockedPeers::BlockedPeers(not_null<ApiWrap*> api)
|
||||
: _session(&api->session())
|
||||
, _api(&api->instance()) {
|
||||
}
|
||||
|
||||
bool BlockedPeers::Slice::Item::operator==(const Item &other) const {
|
||||
return (id == other.id) && (date == other.date);
|
||||
}
|
||||
|
||||
bool BlockedPeers::Slice::Item::operator!=(const Item &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
bool BlockedPeers::Slice::operator==(const BlockedPeers::Slice &other) const {
|
||||
return (total == other.total) && (list == other.list);
|
||||
}
|
||||
|
||||
bool BlockedPeers::Slice::operator!=(const BlockedPeers::Slice &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void BlockedPeers::block(not_null<PeerData*> peer) {
|
||||
if (peer->isBlocked()) {
|
||||
_session->changes().peerUpdated(
|
||||
peer,
|
||||
Data::PeerUpdate::Flag::IsBlocked);
|
||||
} else if (_blockRequests.find(peer) == end(_blockRequests)) {
|
||||
const auto requestId = _api.request(MTPcontacts_Block(
|
||||
peer->input
|
||||
)).done([=](const MTPBool &result) {
|
||||
_blockRequests.erase(peer);
|
||||
peer->setIsBlocked(true);
|
||||
if (_slice) {
|
||||
_slice->list.insert(
|
||||
_slice->list.begin(),
|
||||
{ peer->id, base::unixtime::now() });
|
||||
++_slice->total;
|
||||
_changes.fire_copy(*_slice);
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_blockRequests.erase(peer);
|
||||
}).send();
|
||||
|
||||
_blockRequests.emplace(peer, requestId);
|
||||
}
|
||||
}
|
||||
|
||||
void BlockedPeers::unblock(not_null<PeerData*> peer, Fn<void()> onDone) {
|
||||
if (!peer->isBlocked()) {
|
||||
_session->changes().peerUpdated(
|
||||
peer,
|
||||
Data::PeerUpdate::Flag::IsBlocked);
|
||||
return;
|
||||
} else if (_blockRequests.find(peer) != end(_blockRequests)) {
|
||||
return;
|
||||
}
|
||||
const auto requestId = _api.request(MTPcontacts_Unblock(
|
||||
peer->input
|
||||
)).done([=](const MTPBool &result) {
|
||||
_blockRequests.erase(peer);
|
||||
peer->setIsBlocked(false);
|
||||
if (_slice) {
|
||||
auto &list = _slice->list;
|
||||
for (auto i = list.begin(); i != list.end(); ++i) {
|
||||
if (i->id == peer->id) {
|
||||
list.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_slice->total > list.size()) {
|
||||
--_slice->total;
|
||||
}
|
||||
_changes.fire_copy(*_slice);
|
||||
}
|
||||
if (onDone) {
|
||||
onDone();
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_blockRequests.erase(peer);
|
||||
}).send();
|
||||
_blockRequests.emplace(peer, requestId);
|
||||
}
|
||||
|
||||
void BlockedPeers::reload() {
|
||||
if (_requestId) {
|
||||
return;
|
||||
}
|
||||
request(0, [=](Slice &&slice) {
|
||||
if (!_slice || *_slice != slice) {
|
||||
_slice = slice;
|
||||
_changes.fire(std::move(slice));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto BlockedPeers::slice() -> rpl::producer<BlockedPeers::Slice> {
|
||||
if (!_slice) {
|
||||
reload();
|
||||
}
|
||||
return _slice
|
||||
? _changes.events_starting_with_copy(*_slice)
|
||||
: (_changes.events() | rpl::type_erased());
|
||||
}
|
||||
|
||||
void BlockedPeers::request(int offset, Fn<void(BlockedPeers::Slice)> onDone) {
|
||||
if (_requestId) {
|
||||
return;
|
||||
}
|
||||
_requestId = _api.request(MTPcontacts_GetBlocked(
|
||||
MTP_int(offset),
|
||||
MTP_int(offset ? kBlockedPerPage : kBlockedFirstSlice)
|
||||
)).done([=](const MTPcontacts_Blocked &result) {
|
||||
_requestId = 0;
|
||||
onDone(TLToSlice(result, _session->data()));
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_requestId = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
60
Telegram/SourceFiles/api/api_blocked_peers.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
class ApiWrap;
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Api {
|
||||
|
||||
class BlockedPeers final {
|
||||
public:
|
||||
struct Slice {
|
||||
struct Item {
|
||||
PeerId id;
|
||||
TimeId date = 0;
|
||||
|
||||
bool operator==(const Item &other) const;
|
||||
bool operator!=(const Item &other) const;
|
||||
};
|
||||
|
||||
QVector<Item> list;
|
||||
int total = 0;
|
||||
|
||||
bool operator==(const Slice &other) const;
|
||||
bool operator!=(const Slice &other) const;
|
||||
};
|
||||
|
||||
explicit BlockedPeers(not_null<ApiWrap*> api);
|
||||
|
||||
void reload();
|
||||
rpl::producer<Slice> slice();
|
||||
void request(int offset, Fn<void(Slice)> onDone);
|
||||
|
||||
void block(not_null<PeerData*> peer);
|
||||
void unblock(not_null<PeerData*> peer, Fn<void()> onDone = nullptr);
|
||||
|
||||
private:
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
MTP::Sender _api;
|
||||
|
||||
base::flat_map<not_null<PeerData*>, mtpRequestId> _blockRequests;
|
||||
mtpRequestId _requestId = 0;
|
||||
std::optional<Slice> _slice;
|
||||
rpl::event_stream<Slice> _changes;
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace Api
|
||||
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_bot.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_cloud_password.h"
|
||||
#include "core/core_cloud_password.h"
|
||||
#include "api/api_send_progress.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
@@ -168,7 +169,7 @@ void SendBotCallbackDataWithPassword(
|
||||
if (!button || button->requestId) {
|
||||
return;
|
||||
}
|
||||
api->reloadPasswordState();
|
||||
api->cloudPassword().reload();
|
||||
SendBotCallbackData(item, row, column, MTP_inputCheckPasswordEmpty(), [=](const MTP::Error &error) {
|
||||
auto box = PrePasswordErrorBox(
|
||||
error,
|
||||
@@ -181,7 +182,7 @@ void SendBotCallbackDataWithPassword(
|
||||
} else {
|
||||
auto lifetime = std::make_shared<rpl::lifetime>();
|
||||
button->requestId = -1;
|
||||
api->passwordState(
|
||||
api->cloudPassword().state(
|
||||
) | rpl::take(
|
||||
1
|
||||
) | rpl::start_with_next([=](const Core::CloudPasswordState &state) mutable {
|
||||
|
||||
@@ -112,6 +112,11 @@ ConfirmInviteBox::ConfirmInviteBox(
|
||||
? tr::lng_channel_invite_private(tr::now)
|
||||
: (!_participants.empty() && _participants.size() < count)
|
||||
? tr::lng_group_invite_members(tr::now, lt_count, count)
|
||||
: (count > 0 && _isChannel)
|
||||
? tr::lng_chat_status_subscribers(
|
||||
tr::now,
|
||||
lt_count_decimal,
|
||||
count)
|
||||
: (count > 0)
|
||||
? tr::lng_chat_status_members(tr::now, lt_count_decimal, count)
|
||||
: _isChannel
|
||||
|
||||
112
Telegram/SourceFiles/api/api_cloud_password.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "api/api_cloud_password.h"
|
||||
|
||||
#include "base/openssl_help.h"
|
||||
#include "core/core_cloud_password.h"
|
||||
#include "apiwrap.h"
|
||||
|
||||
namespace Api {
|
||||
|
||||
// #TODO Add ability to set recovery email separately.
|
||||
|
||||
CloudPassword::CloudPassword(not_null<ApiWrap*> api)
|
||||
: _api(&api->instance()) {
|
||||
}
|
||||
|
||||
void CloudPassword::reload() {
|
||||
if (_requestId) {
|
||||
return;
|
||||
}
|
||||
_requestId = _api.request(MTPaccount_GetPassword(
|
||||
)).done([=](const MTPaccount_Password &result) {
|
||||
_requestId = 0;
|
||||
result.match([&](const MTPDaccount_password &data) {
|
||||
openssl::AddRandomSeed(bytes::make_span(data.vsecure_random().v));
|
||||
if (_state) {
|
||||
*_state = Core::ParseCloudPasswordState(data);
|
||||
} else {
|
||||
_state = std::make_unique<Core::CloudPasswordState>(
|
||||
Core::ParseCloudPasswordState(data));
|
||||
}
|
||||
_stateChanges.fire_copy(*_state);
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_requestId = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
void CloudPassword::clearUnconfirmedPassword() {
|
||||
_requestId = _api.request(MTPaccount_CancelPasswordEmail(
|
||||
)).done([=](const MTPBool &result) {
|
||||
_requestId = 0;
|
||||
reload();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_requestId = 0;
|
||||
reload();
|
||||
}).send();
|
||||
}
|
||||
|
||||
rpl::producer<Core::CloudPasswordState> CloudPassword::state() const {
|
||||
return _state
|
||||
? _stateChanges.events_starting_with_copy(*_state)
|
||||
: (_stateChanges.events() | rpl::type_erased());
|
||||
}
|
||||
|
||||
auto CloudPassword::stateCurrent() const
|
||||
-> std::optional<Core::CloudPasswordState> {
|
||||
return _state
|
||||
? base::make_optional(*_state)
|
||||
: std::nullopt;
|
||||
}
|
||||
|
||||
auto CloudPassword::resetPassword()
|
||||
-> rpl::producer<CloudPassword::ResetRetryDate, QString> {
|
||||
return [=](auto consumer) {
|
||||
_api.request(MTPaccount_ResetPassword(
|
||||
)).done([=](const MTPaccount_ResetPasswordResult &result) {
|
||||
result.match([&](const MTPDaccount_resetPasswordOk &data) {
|
||||
reload();
|
||||
}, [&](const MTPDaccount_resetPasswordRequestedWait &data) {
|
||||
if (!_state) {
|
||||
reload();
|
||||
return;
|
||||
}
|
||||
const auto until = data.vuntil_date().v;
|
||||
if (_state->pendingResetDate != until) {
|
||||
_state->pendingResetDate = until;
|
||||
_stateChanges.fire_copy(*_state);
|
||||
}
|
||||
}, [&](const MTPDaccount_resetPasswordFailedWait &data) {
|
||||
consumer.put_next_copy(data.vretry_date().v);
|
||||
});
|
||||
consumer.put_done();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
consumer.put_error_copy(error.type());
|
||||
}).send();
|
||||
|
||||
return rpl::lifetime();
|
||||
};
|
||||
}
|
||||
|
||||
auto CloudPassword::cancelResetPassword()
|
||||
-> rpl::producer<rpl::no_value, QString> {
|
||||
return [=](auto consumer) {
|
||||
_api.request(MTPaccount_DeclinePasswordReset(
|
||||
)).done([=] {
|
||||
reload();
|
||||
consumer.put_done();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
consumer.put_error_copy(error.type());
|
||||
}).send();
|
||||
|
||||
return rpl::lifetime();
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
45
Telegram/SourceFiles/api/api_cloud_password.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
namespace Core {
|
||||
struct CloudPasswordState;
|
||||
} // namespace Core
|
||||
|
||||
class ApiWrap;
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Api {
|
||||
|
||||
class CloudPassword final {
|
||||
public:
|
||||
using ResetRetryDate = int;
|
||||
explicit CloudPassword(not_null<ApiWrap*> api);
|
||||
|
||||
void reload();
|
||||
void clearUnconfirmedPassword();
|
||||
rpl::producer<Core::CloudPasswordState> state() const;
|
||||
std::optional<Core::CloudPasswordState> stateCurrent() const;
|
||||
|
||||
rpl::producer<ResetRetryDate, QString> resetPassword();
|
||||
rpl::producer<rpl::no_value, QString> cancelResetPassword();
|
||||
|
||||
private:
|
||||
MTP::Sender _api;
|
||||
mtpRequestId _requestId = 0;
|
||||
std::unique_ptr<Core::CloudPasswordState> _state;
|
||||
rpl::event_stream<Core::CloudPasswordState> _stateChanges;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Api
|
||||
@@ -32,7 +32,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "storage/file_upload.h"
|
||||
#include "mainwidget.h"
|
||||
#include "apiwrap.h"
|
||||
#include "app.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
@@ -40,22 +39,22 @@ namespace {
|
||||
void InnerFillMessagePostFlags(
|
||||
const Api::SendOptions &options,
|
||||
not_null<PeerData*> peer,
|
||||
MTPDmessage::Flags &flags) {
|
||||
MessageFlags &flags) {
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
if (!anonymousPost) {
|
||||
flags |= MTPDmessage::Flag::f_from_id;
|
||||
flags |= MessageFlag::HasFromId;
|
||||
return;
|
||||
} else if (peer->asMegagroup()) {
|
||||
return;
|
||||
}
|
||||
flags |= MTPDmessage::Flag::f_post;
|
||||
flags |= MessageFlag::Post;
|
||||
// Don't display views and author of a new post when it's scheduled.
|
||||
if (options.scheduled) {
|
||||
return;
|
||||
}
|
||||
flags |= MTPDmessage::Flag::f_views;
|
||||
flags |= MessageFlag::HasViews;
|
||||
if (peer->asChannel()->addsSignature()) {
|
||||
flags |= MTPDmessage::Flag::f_post_author;
|
||||
flags |= MessageFlag::HasPostAuthor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,11 +78,10 @@ void SendExistingMedia(
|
||||
session->data().nextLocalMessageId());
|
||||
const auto randomId = openssl::RandomValue<uint64>();
|
||||
|
||||
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
|
||||
auto clientFlags = NewMessageClientFlags();
|
||||
auto flags = NewMessageFlags(peer);
|
||||
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
||||
if (message.action.replyTo) {
|
||||
flags |= MTPDmessage::Flag::f_reply_to;
|
||||
flags |= MessageFlag::HasReplyInfo;
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
|
||||
}
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
@@ -111,19 +109,19 @@ void SendExistingMedia(
|
||||
const auto captionText = caption.text;
|
||||
|
||||
if (message.action.options.scheduled) {
|
||||
flags |= MTPDmessage::Flag::f_from_scheduled;
|
||||
flags |= MessageFlag::IsOrWasScheduled;
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
|
||||
} else {
|
||||
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
|
||||
flags |= MessageFlag::LocalHistoryEntry;
|
||||
}
|
||||
|
||||
session->data().registerMessageRandomId(randomId, newId);
|
||||
|
||||
const auto viaBotId = UserId();
|
||||
history->addNewLocalMessage(
|
||||
newId.msg,
|
||||
flags,
|
||||
clientFlags,
|
||||
0,
|
||||
viaBotId,
|
||||
replyTo,
|
||||
HistoryItem::NewMessageDate(message.action.options.scheduled),
|
||||
messageFromId,
|
||||
@@ -253,11 +251,10 @@ bool SendDice(Api::MessageToSend &message) {
|
||||
const auto randomId = openssl::RandomValue<uint64>();
|
||||
|
||||
auto &histories = history->owner().histories();
|
||||
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
|
||||
auto clientFlags = NewMessageClientFlags();
|
||||
auto flags = NewMessageFlags(peer);
|
||||
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
||||
if (message.action.replyTo) {
|
||||
flags |= MTPDmessage::Flag::f_reply_to;
|
||||
flags |= MessageFlag::HasReplyInfo;
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
|
||||
}
|
||||
const auto replyHeader = NewMessageReplyHeader(message.action);
|
||||
@@ -272,42 +269,26 @@ bool SendDice(Api::MessageToSend &message) {
|
||||
const auto replyTo = message.action.replyTo;
|
||||
|
||||
if (message.action.options.scheduled) {
|
||||
flags |= MTPDmessage::Flag::f_from_scheduled;
|
||||
flags |= MessageFlag::IsOrWasScheduled;
|
||||
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
|
||||
} else {
|
||||
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
|
||||
flags |= MessageFlag::LocalHistoryEntry;
|
||||
}
|
||||
|
||||
session->data().registerMessageRandomId(randomId, newId);
|
||||
|
||||
const auto views = 1;
|
||||
const auto forwards = 0;
|
||||
history->addNewMessage(
|
||||
MTP_message(
|
||||
MTP_flags(flags),
|
||||
MTP_int(newId.msg),
|
||||
peerToMTP(messageFromId),
|
||||
peerToMTP(history->peer->id),
|
||||
MTPMessageFwdHeader(),
|
||||
MTPint(), // via_bot_id
|
||||
replyHeader,
|
||||
MTP_int(HistoryItem::NewMessageDate(
|
||||
message.action.options.scheduled)),
|
||||
MTP_string(),
|
||||
MTP_messageMediaDice(MTP_int(0), MTP_string(emoji)),
|
||||
MTPReplyMarkup(),
|
||||
MTP_vector<MTPMessageEntity>(),
|
||||
MTP_int(views),
|
||||
MTP_int(forwards),
|
||||
MTPMessageReplies(),
|
||||
MTPint(), // edit_date
|
||||
MTP_string(messagePostAuthor),
|
||||
MTPlong(),
|
||||
//MTPMessageReactions(),
|
||||
MTPVector<MTPRestrictionReason>(),
|
||||
MTPint()), // ttl_period
|
||||
clientFlags,
|
||||
NewMessageType::Unread);
|
||||
const auto viaBotId = UserId();
|
||||
history->addNewLocalMessage(
|
||||
newId.msg,
|
||||
flags,
|
||||
viaBotId,
|
||||
message.action.replyTo,
|
||||
HistoryItem::NewMessageDate(message.action.options.scheduled),
|
||||
messageFromId,
|
||||
messagePostAuthor,
|
||||
TextWithEntities(),
|
||||
MTP_messageMediaDice(MTP_int(0), MTP_string(emoji)),
|
||||
MTPReplyMarkup());
|
||||
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
@@ -338,14 +319,15 @@ bool SendDice(Api::MessageToSend &message) {
|
||||
void FillMessagePostFlags(
|
||||
const Api::SendAction &action,
|
||||
not_null<PeerData*> peer,
|
||||
MTPDmessage::Flags &flags) {
|
||||
MessageFlags &flags) {
|
||||
InnerFillMessagePostFlags(action.options, peer, flags);
|
||||
}
|
||||
|
||||
void SendConfirmedFile(
|
||||
not_null<Main::Session*> session,
|
||||
const std::shared_ptr<FileLoadResult> &file) {
|
||||
const auto isEditing = file->to.replaceMediaOf != 0;
|
||||
const auto isEditing = (file->type != SendMediaType::Audio)
|
||||
&& (file->to.replaceMediaOf != 0);
|
||||
const auto channelId = peerToChannel(file->to.peer);
|
||||
|
||||
const auto newId = FullMsgId(
|
||||
@@ -396,29 +378,24 @@ void SendConfirmedFile(
|
||||
}
|
||||
}
|
||||
|
||||
auto flags = (isEditing ? MTPDmessage::Flags() : NewMessageFlags(peer))
|
||||
| MTPDmessage::Flag::f_entities
|
||||
| MTPDmessage::Flag::f_media;
|
||||
auto clientFlags = NewMessageClientFlags();
|
||||
auto flags = isEditing ? MessageFlags() : NewMessageFlags(peer);
|
||||
if (file->to.replyTo) {
|
||||
flags |= MTPDmessage::Flag::f_reply_to;
|
||||
flags |= MessageFlag::HasReplyInfo;
|
||||
}
|
||||
const auto replyHeader = NewMessageReplyHeader(action);
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
const auto silentPost = ShouldSendSilent(peer, file->to.options);
|
||||
Api::FillMessagePostFlags(action, peer, flags);
|
||||
FillMessagePostFlags(action, peer, flags);
|
||||
if (silentPost) {
|
||||
flags |= MTPDmessage::Flag::f_silent;
|
||||
}
|
||||
if (groupId) {
|
||||
flags |= MTPDmessage::Flag::f_grouped_id;
|
||||
flags |= MessageFlag::Silent;
|
||||
}
|
||||
if (file->to.options.scheduled) {
|
||||
flags |= MTPDmessage::Flag::f_from_scheduled;
|
||||
flags |= MessageFlag::IsOrWasScheduled;
|
||||
|
||||
// Scheduled messages have no the 'edited' badge.
|
||||
flags |= MTPDmessage::Flag::f_edit_hide;
|
||||
flags |= MessageFlag::HideEdited;
|
||||
} else {
|
||||
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
|
||||
flags |= MessageFlag::LocalHistoryEntry;
|
||||
}
|
||||
|
||||
const auto messageFromId = anonymousPost ? 0 : session->userPeerId();
|
||||
@@ -426,17 +403,37 @@ void SendConfirmedFile(
|
||||
? session->user()->name
|
||||
: QString();
|
||||
|
||||
const auto views = 1;
|
||||
const auto forwards = 0;
|
||||
if (file->type == SendMediaType::Photo) {
|
||||
const auto photoFlags = MTPDmessageMediaPhoto::Flag::f_photo | 0;
|
||||
const auto photo = MTP_messageMediaPhoto(
|
||||
MTP_flags(photoFlags),
|
||||
file->photo,
|
||||
MTPint());
|
||||
const auto media = [&] {
|
||||
if (file->type == SendMediaType::Photo) {
|
||||
return MTP_messageMediaPhoto(
|
||||
MTP_flags(MTPDmessageMediaPhoto::Flag::f_photo),
|
||||
file->photo,
|
||||
MTPint());
|
||||
} else if (file->type == SendMediaType::File) {
|
||||
return MTP_messageMediaDocument(
|
||||
MTP_flags(MTPDmessageMediaDocument::Flag::f_document),
|
||||
file->document,
|
||||
MTPint());
|
||||
} else if (file->type == SendMediaType::Audio) {
|
||||
return MTP_messageMediaDocument(
|
||||
MTP_flags(MTPDmessageMediaDocument::Flag::f_document),
|
||||
file->document,
|
||||
MTPint());
|
||||
} else {
|
||||
Unexpected("Type in sendFilesConfirmed.");
|
||||
}
|
||||
}();
|
||||
|
||||
const auto mtpMessage = MTP_message(
|
||||
MTP_flags(flags),
|
||||
if (itemToEdit) {
|
||||
itemToEdit->savePreviousMedia();
|
||||
itemToEdit->applyEdition(MTP_message(
|
||||
MTP_flags(MTPDmessage::Flag::f_media
|
||||
| ((flags & MessageFlag::HideEdited)
|
||||
? MTPDmessage::Flag::f_edit_hide
|
||||
: MTPDmessage::Flag())
|
||||
| (localEntities.v.isEmpty()
|
||||
? MTPDmessage::Flag()
|
||||
: MTPDmessage::Flag::f_entities)),
|
||||
MTP_int(newId.msg),
|
||||
peerToMTP(messageFromId),
|
||||
peerToMTP(file->to.peer),
|
||||
@@ -445,105 +442,32 @@ void SendConfirmedFile(
|
||||
replyHeader,
|
||||
MTP_int(HistoryItem::NewMessageDate(file->to.options.scheduled)),
|
||||
MTP_string(caption.text),
|
||||
photo,
|
||||
media,
|
||||
MTPReplyMarkup(),
|
||||
localEntities,
|
||||
MTP_int(views),
|
||||
MTP_int(forwards),
|
||||
MTPint(), // views
|
||||
MTPint(), // forwards
|
||||
MTPMessageReplies(),
|
||||
MTPint(), // edit_date
|
||||
MTP_string(messagePostAuthor),
|
||||
MTP_long(groupId),
|
||||
//MTPMessageReactions(),
|
||||
MTPVector<MTPRestrictionReason>(),
|
||||
MTPint()); // ttl_period
|
||||
|
||||
if (itemToEdit) {
|
||||
itemToEdit->savePreviousMedia();
|
||||
itemToEdit->applyEdition(mtpMessage.c_message());
|
||||
} else {
|
||||
history->addNewMessage(
|
||||
mtpMessage,
|
||||
clientFlags,
|
||||
NewMessageType::Unread);
|
||||
}
|
||||
} else if (file->type == SendMediaType::File) {
|
||||
const auto documentFlags = MTPDmessageMediaDocument::Flag::f_document | 0;
|
||||
const auto document = MTP_messageMediaDocument(
|
||||
MTP_flags(documentFlags),
|
||||
file->document,
|
||||
MTPint());
|
||||
|
||||
const auto mtpMessage = MTP_message(
|
||||
MTP_flags(flags),
|
||||
MTP_int(newId.msg),
|
||||
peerToMTP(messageFromId),
|
||||
peerToMTP(file->to.peer),
|
||||
MTPMessageFwdHeader(),
|
||||
MTPint(),
|
||||
replyHeader,
|
||||
MTP_int(HistoryItem::NewMessageDate(file->to.options.scheduled)),
|
||||
MTP_string(caption.text),
|
||||
document,
|
||||
MTPReplyMarkup(),
|
||||
localEntities,
|
||||
MTP_int(views),
|
||||
MTP_int(forwards),
|
||||
MTPMessageReplies(),
|
||||
MTPint(), // edit_date
|
||||
MTP_string(messagePostAuthor),
|
||||
MTP_long(groupId),
|
||||
//MTPMessageReactions(),
|
||||
MTPVector<MTPRestrictionReason>(),
|
||||
MTPint()); // ttl_period
|
||||
|
||||
if (itemToEdit) {
|
||||
itemToEdit->savePreviousMedia();
|
||||
itemToEdit->applyEdition(mtpMessage.c_message());
|
||||
} else {
|
||||
history->addNewMessage(
|
||||
mtpMessage,
|
||||
clientFlags,
|
||||
NewMessageType::Unread);
|
||||
}
|
||||
} else if (file->type == SendMediaType::Audio) {
|
||||
if (!peer->isChannel() || peer->isMegagroup()) {
|
||||
flags |= MTPDmessage::Flag::f_media_unread;
|
||||
}
|
||||
const auto documentFlags = MTPDmessageMediaDocument::Flag::f_document | 0;
|
||||
const auto document = MTP_messageMediaDocument(
|
||||
MTP_flags(documentFlags),
|
||||
file->document,
|
||||
MTPint());
|
||||
history->addNewMessage(
|
||||
MTP_message(
|
||||
MTP_flags(flags),
|
||||
MTP_int(newId.msg),
|
||||
peerToMTP(messageFromId),
|
||||
peerToMTP(file->to.peer),
|
||||
MTPMessageFwdHeader(),
|
||||
MTPint(),
|
||||
replyHeader,
|
||||
MTP_int(
|
||||
HistoryItem::NewMessageDate(file->to.options.scheduled)),
|
||||
MTP_string(caption.text),
|
||||
document,
|
||||
MTPReplyMarkup(),
|
||||
localEntities,
|
||||
MTP_int(views),
|
||||
MTP_int(forwards),
|
||||
MTPMessageReplies(),
|
||||
MTPint(), // edit_date
|
||||
MTP_string(messagePostAuthor),
|
||||
MTP_long(groupId),
|
||||
//MTPMessageReactions(),
|
||||
MTPVector<MTPRestrictionReason>(),
|
||||
MTPint()), // ttl_period
|
||||
clientFlags,
|
||||
NewMessageType::Unread);
|
||||
// Voices can't be edited.
|
||||
MTPint()).c_message());
|
||||
} else {
|
||||
Unexpected("Type in sendFilesConfirmed.");
|
||||
const auto viaBotId = UserId();
|
||||
history->addNewLocalMessage(
|
||||
newId.msg,
|
||||
flags,
|
||||
viaBotId,
|
||||
file->to.replyTo,
|
||||
HistoryItem::NewMessageDate(file->to.options.scheduled),
|
||||
messageFromId,
|
||||
messagePostAuthor,
|
||||
caption,
|
||||
media,
|
||||
MTPReplyMarkup(),
|
||||
groupId);
|
||||
}
|
||||
|
||||
if (isEditing) {
|
||||
|
||||
@@ -30,7 +30,7 @@ bool SendDice(Api::MessageToSend &message);
|
||||
void FillMessagePostFlags(
|
||||
const SendAction &action,
|
||||
not_null<PeerData*> peer,
|
||||
MTPDmessage::Flags &flags);
|
||||
MessageFlags &flags);
|
||||
|
||||
void SendConfirmedFile(
|
||||
not_null<Main::Session*> session,
|
||||
|
||||
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "api/api_authorizations.h"
|
||||
#include "api/api_text_entities.h"
|
||||
#include "api/api_user_privacy.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_account.h"
|
||||
#include "mtproto/mtp_instance.h"
|
||||
@@ -41,7 +42,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "window/window_controller.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "apiwrap.h"
|
||||
#include "app.h" // App::formatPhone
|
||||
#include "ui/text/format_values.h" // Ui::FormatPhone
|
||||
#include "app.h" // App::quitting
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
@@ -1054,7 +1056,7 @@ void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
|
||||
//MTPMessageReactions(),
|
||||
MTPVector<MTPRestrictionReason>(),
|
||||
MTP_int(d.vttl_period().value_or_empty())),
|
||||
MTPDmessage_ClientFlags(),
|
||||
MessageFlags(),
|
||||
NewMessageType::Unread);
|
||||
} break;
|
||||
|
||||
@@ -1085,7 +1087,7 @@ void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
|
||||
//MTPMessageReactions(),
|
||||
MTPVector<MTPRestrictionReason>(),
|
||||
MTP_int(d.vttl_period().value_or_empty())),
|
||||
MTPDmessage_ClientFlags(),
|
||||
MessageFlags(),
|
||||
NewMessageType::Unread);
|
||||
} break;
|
||||
|
||||
@@ -1114,7 +1116,7 @@ void Updates::applyUpdateNoPtsCheck(const MTPUpdate &update) {
|
||||
if (needToAdd) {
|
||||
_session->data().addNewMessage(
|
||||
d.vmessage(),
|
||||
MTPDmessage_ClientFlags(),
|
||||
MessageFlags(),
|
||||
NewMessageType::Unread);
|
||||
}
|
||||
} break;
|
||||
@@ -1208,7 +1210,7 @@ void Updates::applyUpdateNoPtsCheck(const MTPUpdate &update) {
|
||||
if (needToAdd) {
|
||||
_session->data().addNewMessage(
|
||||
d.vmessage(),
|
||||
MTPDmessage_ClientFlags(),
|
||||
MessageFlags(),
|
||||
NewMessageType::Unread);
|
||||
}
|
||||
} break;
|
||||
@@ -1844,7 +1846,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
|| user->isSelf()
|
||||
|| user->phone().isEmpty())
|
||||
? QString()
|
||||
: App::formatPhone(user->phone())),
|
||||
: Ui::FormatPhone(user->phone())),
|
||||
user->username);
|
||||
|
||||
session().changes().peerUpdated(
|
||||
@@ -1953,13 +1955,10 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
}
|
||||
return true;
|
||||
};
|
||||
if (const auto key = ApiWrap::Privacy::KeyFromMTP(d.vkey().type())) {
|
||||
if (allLoaded()) {
|
||||
session().api().handlePrivacyChange(*key, d.vrules());
|
||||
} else {
|
||||
session().api().reloadPrivacy(*key);
|
||||
}
|
||||
}
|
||||
session().api().userPrivacy().apply(
|
||||
d.vkey().type(),
|
||||
d.vrules(),
|
||||
allLoaded());
|
||||
} break;
|
||||
|
||||
case mtpc_updatePinnedDialogs: {
|
||||
|
||||
303
Telegram/SourceFiles/api/api_user_privacy.cpp
Normal file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "api/api_user_privacy.h"
|
||||
|
||||
#include "apiwrap.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_peer_id.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "main/main_session.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
constexpr auto kMaxRules = 3; // Allow users, disallow users, Option.
|
||||
|
||||
using TLInputRules = MTPVector<MTPInputPrivacyRule>;
|
||||
using TLRules = MTPVector<MTPPrivacyRule>;
|
||||
|
||||
TLInputRules RulesToTL(const UserPrivacy::Rule &rule) {
|
||||
const auto collectInputUsers = [](const auto &peers) {
|
||||
auto result = QVector<MTPInputUser>();
|
||||
result.reserve(peers.size());
|
||||
for (const auto peer : peers) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
result.push_back(user->inputUser);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
const auto collectInputChats = [](const auto &peers) {
|
||||
auto result = QVector<MTPint>(); // #TODO ids
|
||||
result.reserve(peers.size());
|
||||
for (const auto peer : peers) {
|
||||
if (!peer->isUser()) {
|
||||
result.push_back(peerToBareMTPInt(peer->id));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
auto result = QVector<MTPInputPrivacyRule>();
|
||||
result.reserve(kMaxRules);
|
||||
if (!rule.ignoreAlways) {
|
||||
const auto users = collectInputUsers(rule.always);
|
||||
const auto chats = collectInputChats(rule.always);
|
||||
if (!users.empty()) {
|
||||
result.push_back(
|
||||
MTP_inputPrivacyValueAllowUsers(
|
||||
MTP_vector<MTPInputUser>(users)));
|
||||
}
|
||||
if (!chats.empty()) {
|
||||
result.push_back(
|
||||
MTP_inputPrivacyValueAllowChatParticipants(
|
||||
MTP_vector<MTPint>(chats)));
|
||||
}
|
||||
}
|
||||
if (!rule.ignoreNever) {
|
||||
const auto users = collectInputUsers(rule.never);
|
||||
const auto chats = collectInputChats(rule.never);
|
||||
if (!users.empty()) {
|
||||
result.push_back(
|
||||
MTP_inputPrivacyValueDisallowUsers(
|
||||
MTP_vector<MTPInputUser>(users)));
|
||||
}
|
||||
if (!chats.empty()) {
|
||||
result.push_back(
|
||||
MTP_inputPrivacyValueDisallowChatParticipants(
|
||||
MTP_vector<MTPint>(chats)));
|
||||
}
|
||||
}
|
||||
result.push_back([&] {
|
||||
using Option = UserPrivacy::Option;
|
||||
switch (rule.option) {
|
||||
case Option::Everyone: return MTP_inputPrivacyValueAllowAll();
|
||||
case Option::Contacts: return MTP_inputPrivacyValueAllowContacts();
|
||||
case Option::Nobody: return MTP_inputPrivacyValueDisallowAll();
|
||||
}
|
||||
Unexpected("Option value in Api::UserPrivacy::RulesToTL.");
|
||||
}());
|
||||
|
||||
|
||||
return MTP_vector<MTPInputPrivacyRule>(std::move(result));
|
||||
}
|
||||
|
||||
UserPrivacy::Rule TLToRules(const TLRules &rules, Data::Session &owner) {
|
||||
// This is simplified version of privacy rules interpretation.
|
||||
// But it should be fine for all the apps
|
||||
// that use the same subset of features.
|
||||
using Option = UserPrivacy::Option;
|
||||
auto result = UserPrivacy::Rule();
|
||||
auto optionSet = false;
|
||||
const auto setOption = [&](Option option) {
|
||||
if (optionSet) return;
|
||||
optionSet = true;
|
||||
result.option = option;
|
||||
};
|
||||
auto &always = result.always;
|
||||
auto &never = result.never;
|
||||
const auto feed = [&](const MTPPrivacyRule &rule) {
|
||||
rule.match([&](const MTPDprivacyValueAllowAll &) {
|
||||
setOption(Option::Everyone);
|
||||
}, [&](const MTPDprivacyValueAllowContacts &) {
|
||||
setOption(Option::Contacts);
|
||||
}, [&](const MTPDprivacyValueAllowUsers &data) {
|
||||
const auto &users = data.vusers().v;
|
||||
always.reserve(always.size() + users.size());
|
||||
for (const auto userId : users) {
|
||||
const auto user = owner.user(UserId(userId.v));
|
||||
if (!base::contains(never, user)
|
||||
&& !base::contains(always, user)) {
|
||||
always.emplace_back(user);
|
||||
}
|
||||
}
|
||||
}, [&](const MTPDprivacyValueAllowChatParticipants &data) {
|
||||
const auto &chats = data.vchats().v;
|
||||
always.reserve(always.size() + chats.size());
|
||||
for (const auto &chatId : chats) {
|
||||
const auto chat = owner.chatLoaded(chatId);
|
||||
const auto peer = chat
|
||||
? static_cast<PeerData*>(chat)
|
||||
: owner.channelLoaded(chatId);
|
||||
if (peer
|
||||
&& !base::contains(never, peer)
|
||||
&& !base::contains(always, peer)) {
|
||||
always.emplace_back(peer);
|
||||
}
|
||||
}
|
||||
}, [&](const MTPDprivacyValueDisallowContacts &) {
|
||||
// Not supported
|
||||
}, [&](const MTPDprivacyValueDisallowAll &) {
|
||||
setOption(Option::Nobody);
|
||||
}, [&](const MTPDprivacyValueDisallowUsers &data) {
|
||||
const auto &users = data.vusers().v;
|
||||
never.reserve(never.size() + users.size());
|
||||
for (const auto userId : users) {
|
||||
const auto user = owner.user(UserId(userId.v));
|
||||
if (!base::contains(always, user)
|
||||
&& !base::contains(never, user)) {
|
||||
never.emplace_back(user);
|
||||
}
|
||||
}
|
||||
}, [&](const MTPDprivacyValueDisallowChatParticipants &data) {
|
||||
const auto &chats = data.vchats().v;
|
||||
never.reserve(never.size() + chats.size());
|
||||
for (const auto &chatId : chats) {
|
||||
const auto chat = owner.chatLoaded(chatId);
|
||||
const auto peer = chat
|
||||
? static_cast<PeerData*>(chat)
|
||||
: owner.channelLoaded(chatId);
|
||||
if (peer
|
||||
&& !base::contains(always, peer)
|
||||
&& !base::contains(never, peer)) {
|
||||
never.emplace_back(peer);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
for (const auto &rule : rules.v) {
|
||||
feed(rule);
|
||||
}
|
||||
feed(MTP_privacyValueDisallowAll()); // Disallow by default.
|
||||
return result;
|
||||
}
|
||||
|
||||
MTPInputPrivacyKey KeyToTL(UserPrivacy::Key key) {
|
||||
using Key = UserPrivacy::Key;
|
||||
switch (key) {
|
||||
case Key::Calls: return MTP_inputPrivacyKeyPhoneCall();
|
||||
case Key::Invites: return MTP_inputPrivacyKeyChatInvite();
|
||||
case Key::PhoneNumber: return MTP_inputPrivacyKeyPhoneNumber();
|
||||
case Key::AddedByPhone:
|
||||
return MTP_inputPrivacyKeyAddedByPhone();
|
||||
case Key::LastSeen:
|
||||
return MTP_inputPrivacyKeyStatusTimestamp();
|
||||
case Key::CallsPeer2Peer:
|
||||
return MTP_inputPrivacyKeyPhoneP2P();
|
||||
case Key::Forwards:
|
||||
return MTP_inputPrivacyKeyForwards();
|
||||
case Key::ProfilePhoto:
|
||||
return MTP_inputPrivacyKeyProfilePhoto();
|
||||
}
|
||||
Unexpected("Key in Api::UserPrivacy::KetToTL.");
|
||||
}
|
||||
|
||||
std::optional<UserPrivacy::Key> TLToKey(mtpTypeId type) {
|
||||
using Key = UserPrivacy::Key;
|
||||
switch (type) {
|
||||
case mtpc_privacyKeyPhoneNumber:
|
||||
case mtpc_inputPrivacyKeyPhoneNumber: return Key::PhoneNumber;
|
||||
case mtpc_privacyKeyAddedByPhone:
|
||||
case mtpc_inputPrivacyKeyAddedByPhone: return Key::AddedByPhone;
|
||||
case mtpc_privacyKeyStatusTimestamp:
|
||||
case mtpc_inputPrivacyKeyStatusTimestamp: return Key::LastSeen;
|
||||
case mtpc_privacyKeyChatInvite:
|
||||
case mtpc_inputPrivacyKeyChatInvite: return Key::Invites;
|
||||
case mtpc_privacyKeyPhoneCall:
|
||||
case mtpc_inputPrivacyKeyPhoneCall: return Key::Calls;
|
||||
case mtpc_privacyKeyPhoneP2P:
|
||||
case mtpc_inputPrivacyKeyPhoneP2P: return Key::CallsPeer2Peer;
|
||||
case mtpc_privacyKeyForwards:
|
||||
case mtpc_inputPrivacyKeyForwards: return Key::Forwards;
|
||||
case mtpc_privacyKeyProfilePhoto:
|
||||
case mtpc_inputPrivacyKeyProfilePhoto: return Key::ProfilePhoto;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
UserPrivacy::UserPrivacy(not_null<ApiWrap*> api)
|
||||
: _session(&api->session())
|
||||
, _api(&api->instance()) {
|
||||
}
|
||||
|
||||
void UserPrivacy::save(
|
||||
Key key,
|
||||
const UserPrivacy::Rule &rule) {
|
||||
const auto tlKey = KeyToTL(key);
|
||||
const auto keyTypeId = tlKey.type();
|
||||
const auto it = _privacySaveRequests.find(keyTypeId);
|
||||
if (it != _privacySaveRequests.cend()) {
|
||||
_api.request(it->second).cancel();
|
||||
_privacySaveRequests.erase(it);
|
||||
}
|
||||
|
||||
const auto requestId = _api.request(MTPaccount_SetPrivacy(
|
||||
tlKey,
|
||||
RulesToTL(rule)
|
||||
)).done([=](const MTPaccount_PrivacyRules &result) {
|
||||
result.match([&](const MTPDaccount_privacyRules &data) {
|
||||
_session->data().processUsers(data.vusers());
|
||||
_session->data().processChats(data.vchats());
|
||||
_privacySaveRequests.remove(keyTypeId);
|
||||
apply(keyTypeId, data.vrules(), true);
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_privacySaveRequests.remove(keyTypeId);
|
||||
}).send();
|
||||
|
||||
_privacySaveRequests.emplace(keyTypeId, requestId);
|
||||
}
|
||||
|
||||
void UserPrivacy::apply(
|
||||
mtpTypeId type,
|
||||
const TLRules &rules,
|
||||
bool allLoaded) {
|
||||
if (const auto key = TLToKey(type)) {
|
||||
if (!allLoaded) {
|
||||
reload(*key);
|
||||
return;
|
||||
}
|
||||
pushPrivacy(*key, rules);
|
||||
if ((*key) == Key::LastSeen) {
|
||||
_session->api().updatePrivacyLastSeens();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UserPrivacy::reload(Key key) {
|
||||
if (_privacyRequestIds.contains(key)) {
|
||||
return;
|
||||
}
|
||||
const auto requestId = _api.request(MTPaccount_GetPrivacy(
|
||||
KeyToTL(key)
|
||||
)).done([=](const MTPaccount_PrivacyRules &result) {
|
||||
_privacyRequestIds.erase(key);
|
||||
result.match([&](const MTPDaccount_privacyRules &data) {
|
||||
_session->data().processUsers(data.vusers());
|
||||
_session->data().processChats(data.vchats());
|
||||
pushPrivacy(key, data.vrules());
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_privacyRequestIds.erase(key);
|
||||
}).send();
|
||||
_privacyRequestIds.emplace(key, requestId);
|
||||
}
|
||||
|
||||
void UserPrivacy::pushPrivacy(Key key, const TLRules &rules) {
|
||||
const auto &saved = (_privacyValues[key] =
|
||||
TLToRules(rules, _session->data()));
|
||||
const auto i = _privacyChanges.find(key);
|
||||
if (i != end(_privacyChanges)) {
|
||||
i->second.fire_copy(saved);
|
||||
}
|
||||
}
|
||||
|
||||
auto UserPrivacy::value(Key key) -> rpl::producer<UserPrivacy::Rule> {
|
||||
if (const auto i = _privacyValues.find(key); i != end(_privacyValues)) {
|
||||
return _privacyChanges[key].events_starting_with_copy(i->second);
|
||||
} else {
|
||||
return _privacyChanges[key].events();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
73
Telegram/SourceFiles/api/api_user_privacy.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
class ApiWrap;
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Api {
|
||||
|
||||
class UserPrivacy final {
|
||||
public:
|
||||
enum class Key {
|
||||
PhoneNumber,
|
||||
AddedByPhone,
|
||||
LastSeen,
|
||||
Calls,
|
||||
Invites,
|
||||
CallsPeer2Peer,
|
||||
Forwards,
|
||||
ProfilePhoto,
|
||||
};
|
||||
enum class Option {
|
||||
Everyone,
|
||||
Contacts,
|
||||
Nobody,
|
||||
};
|
||||
struct Rule {
|
||||
Option option = Option::Everyone;
|
||||
std::vector<not_null<PeerData*>> always;
|
||||
std::vector<not_null<PeerData*>> never;
|
||||
bool ignoreAlways = false;
|
||||
bool ignoreNever = false;
|
||||
};
|
||||
|
||||
explicit UserPrivacy(not_null<ApiWrap*> api);
|
||||
|
||||
void save(
|
||||
Key key,
|
||||
const UserPrivacy::Rule &rule);
|
||||
void apply(
|
||||
mtpTypeId type,
|
||||
const MTPVector<MTPPrivacyRule> &rules,
|
||||
bool allLoaded);
|
||||
|
||||
void reload(Key key);
|
||||
rpl::producer<Rule> value(Key key);
|
||||
|
||||
private:
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
void pushPrivacy(Key key, const MTPVector<MTPPrivacyRule> &rules);
|
||||
|
||||
base::flat_map<mtpTypeId, mtpRequestId> _privacySaveRequests;
|
||||
|
||||
base::flat_map<Key, mtpRequestId> _privacyRequestIds;
|
||||
base::flat_map<Key, Rule> _privacyValues;
|
||||
std::map<Key, rpl::event_stream<Rule>> _privacyChanges;
|
||||
|
||||
MTP::Sender _api;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Api
|
||||
@@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "api/api_authorizations.h"
|
||||
#include "api/api_attached_stickers.h"
|
||||
#include "api/api_blocked_peers.h"
|
||||
#include "api/api_cloud_password.h"
|
||||
#include "api/api_hash.h"
|
||||
#include "api/api_invite_links.h"
|
||||
#include "api/api_media.h"
|
||||
@@ -18,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_sensitive_content.h"
|
||||
#include "api/api_global_privacy.h"
|
||||
#include "api/api_updates.h"
|
||||
#include "api/api_user_privacy.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/data_drafts.h"
|
||||
#include "data/data_changes.h"
|
||||
@@ -42,7 +45,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "dialogs/dialogs_key.h"
|
||||
#include "core/core_cloud_password.h"
|
||||
#include "core/application.h"
|
||||
#include "base/openssl_help.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "base/qt_adapters.h"
|
||||
#include "base/call_delayed.h"
|
||||
@@ -78,7 +80,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "storage/storage_media_prepare.h"
|
||||
#include "storage/storage_account.h"
|
||||
#include "facades.h"
|
||||
#include "app.h"
|
||||
#include "app.h" // App::quitting
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -108,7 +110,6 @@ constexpr auto kStickersByEmojiInvalidateTimeout = crl::time(60 * 60 * 1000);
|
||||
constexpr auto kNotifySettingSaveTimeout = crl::time(1000);
|
||||
constexpr auto kDialogsFirstLoad = 20;
|
||||
constexpr auto kDialogsPerPage = 500;
|
||||
constexpr auto kBlockedFirstSlice = 16;
|
||||
|
||||
using PhotoFileLocationId = Data::PhotoFileLocationId;
|
||||
using DocumentFileLocationId = Data::DocumentFileLocationId;
|
||||
@@ -120,65 +121,6 @@ using UpdatedFileReferences = Data::UpdatedFileReferences;
|
||||
|
||||
} // namespace
|
||||
|
||||
MTPInputPrivacyKey ApiWrap::Privacy::Input(Key key) {
|
||||
switch (key) {
|
||||
case Privacy::Key::Calls: return MTP_inputPrivacyKeyPhoneCall();
|
||||
case Privacy::Key::Invites: return MTP_inputPrivacyKeyChatInvite();
|
||||
case Privacy::Key::PhoneNumber: return MTP_inputPrivacyKeyPhoneNumber();
|
||||
case Privacy::Key::AddedByPhone:
|
||||
return MTP_inputPrivacyKeyAddedByPhone();
|
||||
case Privacy::Key::LastSeen:
|
||||
return MTP_inputPrivacyKeyStatusTimestamp();
|
||||
case Privacy::Key::CallsPeer2Peer:
|
||||
return MTP_inputPrivacyKeyPhoneP2P();
|
||||
case Privacy::Key::Forwards:
|
||||
return MTP_inputPrivacyKeyForwards();
|
||||
case Privacy::Key::ProfilePhoto:
|
||||
return MTP_inputPrivacyKeyProfilePhoto();
|
||||
}
|
||||
Unexpected("Key in ApiWrap::Privacy::Input.");
|
||||
}
|
||||
|
||||
std::optional<ApiWrap::Privacy::Key> ApiWrap::Privacy::KeyFromMTP(
|
||||
mtpTypeId type) {
|
||||
using Key = Privacy::Key;
|
||||
switch (type) {
|
||||
case mtpc_privacyKeyPhoneNumber:
|
||||
case mtpc_inputPrivacyKeyPhoneNumber: return Key::PhoneNumber;
|
||||
case mtpc_privacyKeyAddedByPhone:
|
||||
case mtpc_inputPrivacyKeyAddedByPhone: return Key::AddedByPhone;
|
||||
case mtpc_privacyKeyStatusTimestamp:
|
||||
case mtpc_inputPrivacyKeyStatusTimestamp: return Key::LastSeen;
|
||||
case mtpc_privacyKeyChatInvite:
|
||||
case mtpc_inputPrivacyKeyChatInvite: return Key::Invites;
|
||||
case mtpc_privacyKeyPhoneCall:
|
||||
case mtpc_inputPrivacyKeyPhoneCall: return Key::Calls;
|
||||
case mtpc_privacyKeyPhoneP2P:
|
||||
case mtpc_inputPrivacyKeyPhoneP2P: return Key::CallsPeer2Peer;
|
||||
case mtpc_privacyKeyForwards:
|
||||
case mtpc_inputPrivacyKeyForwards: return Key::Forwards;
|
||||
case mtpc_privacyKeyProfilePhoto:
|
||||
case mtpc_inputPrivacyKeyProfilePhoto: return Key::ProfilePhoto;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool ApiWrap::BlockedPeersSlice::Item::operator==(const Item &other) const {
|
||||
return (peer == other.peer) && (date == other.date);
|
||||
}
|
||||
|
||||
bool ApiWrap::BlockedPeersSlice::Item::operator!=(const Item &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
bool ApiWrap::BlockedPeersSlice::operator==(const BlockedPeersSlice &other) const {
|
||||
return (total == other.total) && (list == other.list);
|
||||
}
|
||||
|
||||
bool ApiWrap::BlockedPeersSlice::operator!=(const BlockedPeersSlice &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
ApiWrap::ApiWrap(not_null<Main::Session*> session)
|
||||
: MTP::Sender(&session->account().mtp())
|
||||
, _session(session)
|
||||
@@ -192,9 +134,12 @@ ApiWrap::ApiWrap(not_null<Main::Session*> session)
|
||||
, _updateNotifySettingsTimer([=] { sendNotifySettingsUpdates(); })
|
||||
, _authorizations(std::make_unique<Api::Authorizations>(this))
|
||||
, _attachedStickers(std::make_unique<Api::AttachedStickers>(this))
|
||||
, _blockedPeers(std::make_unique<Api::BlockedPeers>(this))
|
||||
, _cloudPassword(std::make_unique<Api::CloudPassword>(this))
|
||||
, _selfDestruct(std::make_unique<Api::SelfDestruct>(this))
|
||||
, _sensitiveContent(std::make_unique<Api::SensitiveContent>(this))
|
||||
, _globalPrivacy(std::make_unique<Api::GlobalPrivacy>(this))
|
||||
, _userPrivacy(std::make_unique<Api::UserPrivacy>(this))
|
||||
, _inviteLinks(std::make_unique<Api::InviteLinks>(this)) {
|
||||
crl::on_main(session, [=] {
|
||||
// You can't use _session->lifetime() in the constructor,
|
||||
@@ -2175,68 +2120,6 @@ void ApiWrap::leaveChannel(not_null<ChannelData*> channel) {
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::blockPeer(not_null<PeerData*> peer) {
|
||||
if (peer->isBlocked()) {
|
||||
session().changes().peerUpdated(
|
||||
peer,
|
||||
Data::PeerUpdate::Flag::IsBlocked);
|
||||
} else if (_blockRequests.find(peer) == end(_blockRequests)) {
|
||||
const auto requestId = request(MTPcontacts_Block(
|
||||
peer->input
|
||||
)).done([=](const MTPBool &result) {
|
||||
_blockRequests.erase(peer);
|
||||
peer->setIsBlocked(true);
|
||||
if (_blockedPeersSlice) {
|
||||
_blockedPeersSlice->list.insert(
|
||||
_blockedPeersSlice->list.begin(),
|
||||
{ peer, base::unixtime::now() });
|
||||
++_blockedPeersSlice->total;
|
||||
_blockedPeersChanges.fire_copy(*_blockedPeersSlice);
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_blockRequests.erase(peer);
|
||||
}).send();
|
||||
|
||||
_blockRequests.emplace(peer, requestId);
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::unblockPeer(not_null<PeerData*> peer, Fn<void()> onDone) {
|
||||
if (!peer->isBlocked()) {
|
||||
session().changes().peerUpdated(
|
||||
peer,
|
||||
Data::PeerUpdate::Flag::IsBlocked);
|
||||
return;
|
||||
} else if (_blockRequests.find(peer) != end(_blockRequests)) {
|
||||
return;
|
||||
}
|
||||
const auto requestId = request(MTPcontacts_Unblock(
|
||||
peer->input
|
||||
)).done([=](const MTPBool &result) {
|
||||
_blockRequests.erase(peer);
|
||||
peer->setIsBlocked(false);
|
||||
if (_blockedPeersSlice) {
|
||||
auto &list = _blockedPeersSlice->list;
|
||||
for (auto i = list.begin(); i != list.end(); ++i) {
|
||||
if (i->peer == peer) {
|
||||
list.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_blockedPeersSlice->total > list.size()) {
|
||||
--_blockedPeersSlice->total;
|
||||
}
|
||||
_blockedPeersChanges.fire_copy(*_blockedPeersSlice);
|
||||
}
|
||||
if (onDone) {
|
||||
onDone();
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_blockRequests.erase(peer);
|
||||
}).send();
|
||||
_blockRequests.emplace(peer, requestId);
|
||||
}
|
||||
|
||||
void ApiWrap::requestNotifySettings(const MTPInputNotifyPeer &peer) {
|
||||
const auto key = [&] {
|
||||
switch (peer.type()) {
|
||||
@@ -2309,45 +2192,7 @@ void ApiWrap::saveDraftToCloudDelayed(not_null<History*> history) {
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::savePrivacy(
|
||||
const MTPInputPrivacyKey &key,
|
||||
QVector<MTPInputPrivacyRule> &&rules) {
|
||||
const auto keyTypeId = key.type();
|
||||
const auto it = _privacySaveRequests.find(keyTypeId);
|
||||
if (it != _privacySaveRequests.cend()) {
|
||||
request(it->second).cancel();
|
||||
_privacySaveRequests.erase(it);
|
||||
}
|
||||
|
||||
const auto requestId = request(MTPaccount_SetPrivacy(
|
||||
key,
|
||||
MTP_vector<MTPInputPrivacyRule>(std::move(rules))
|
||||
)).done([=](const MTPaccount_PrivacyRules &result) {
|
||||
result.match([&](const MTPDaccount_privacyRules &data) {
|
||||
_session->data().processUsers(data.vusers());
|
||||
_session->data().processChats(data.vchats());
|
||||
_privacySaveRequests.remove(keyTypeId);
|
||||
if (const auto key = Privacy::KeyFromMTP(keyTypeId)) {
|
||||
handlePrivacyChange(*key, data.vrules());
|
||||
}
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_privacySaveRequests.remove(keyTypeId);
|
||||
}).send();
|
||||
|
||||
_privacySaveRequests.emplace(keyTypeId, requestId);
|
||||
}
|
||||
|
||||
void ApiWrap::handlePrivacyChange(
|
||||
Privacy::Key key,
|
||||
const MTPVector<MTPPrivacyRule> &rules) {
|
||||
pushPrivacy(key, rules.v);
|
||||
if (key == Privacy::Key::LastSeen) {
|
||||
updatePrivacyLastSeens(rules.v);
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::updatePrivacyLastSeens(const QVector<MTPPrivacyRule> &rules) {
|
||||
void ApiWrap::updatePrivacyLastSeens() {
|
||||
const auto now = base::unixtime::now();
|
||||
_session->data().enumerateUsers([&](UserData *user) {
|
||||
if (user->isSelf() || !user->isFullLoaded()) {
|
||||
@@ -3783,18 +3628,17 @@ void ApiWrap::forwardMessages(
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||
|
||||
auto flags = MTPDmessage::Flags(0);
|
||||
auto clientFlags = MTPDmessage_ClientFlags();
|
||||
auto flags = MessageFlags();
|
||||
auto sendFlags = MTPmessages_ForwardMessages::Flags(0);
|
||||
FillMessagePostFlags(action, peer, flags);
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_ForwardMessages::Flag::f_silent;
|
||||
}
|
||||
if (action.options.scheduled) {
|
||||
flags |= MTPDmessage::Flag::f_from_scheduled;
|
||||
flags |= MessageFlag::IsOrWasScheduled;
|
||||
sendFlags |= MTPmessages_ForwardMessages::Flag::f_schedule_date;
|
||||
} else {
|
||||
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
|
||||
flags |= MessageFlag::LocalHistoryEntry;
|
||||
}
|
||||
|
||||
auto forwardFrom = items.front()->history()->peer;
|
||||
@@ -3861,7 +3705,6 @@ void ApiWrap::forwardMessages(
|
||||
history->addNewLocalMessage(
|
||||
newId.msg,
|
||||
flags,
|
||||
clientFlags,
|
||||
HistoryItem::NewMessageDate(action.options.scheduled),
|
||||
messageFromId,
|
||||
messagePostAuthor,
|
||||
@@ -3926,61 +3769,44 @@ void ApiWrap::sendSharedContact(
|
||||
_session->data().nextLocalMessageId());
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
|
||||
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
|
||||
auto clientFlags = NewMessageClientFlags();
|
||||
auto flags = NewMessageFlags(peer);
|
||||
if (action.replyTo) {
|
||||
flags |= MTPDmessage::Flag::f_reply_to;
|
||||
flags |= MessageFlag::HasReplyInfo;
|
||||
}
|
||||
const auto replyHeader = NewMessageReplyHeader(action);
|
||||
FillMessagePostFlags(action, peer, flags);
|
||||
if (action.options.scheduled) {
|
||||
flags |= MTPDmessage::Flag::f_from_scheduled;
|
||||
flags |= MessageFlag::IsOrWasScheduled;
|
||||
} else {
|
||||
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
|
||||
flags |= MessageFlag::LocalHistoryEntry;
|
||||
}
|
||||
const auto messageFromId = anonymousPost ? 0 : _session->userPeerId();
|
||||
const auto messagePostAuthor = peer->isBroadcast()
|
||||
? _session->user()->name
|
||||
: QString();
|
||||
const auto vcard = QString();
|
||||
const auto views = 1;
|
||||
const auto forwards = 0;
|
||||
const auto item = history->addNewMessage(
|
||||
MTP_message(
|
||||
MTP_flags(flags),
|
||||
MTP_int(newId.msg),
|
||||
peerToMTP(messageFromId),
|
||||
peerToMTP(peer->id),
|
||||
MTPMessageFwdHeader(),
|
||||
MTPint(), // via_bot_id
|
||||
replyHeader,
|
||||
MTP_int(HistoryItem::NewMessageDate(action.options.scheduled)),
|
||||
MTP_string(),
|
||||
MTP_messageMediaContact(
|
||||
MTP_string(phone),
|
||||
MTP_string(firstName),
|
||||
MTP_string(lastName),
|
||||
MTP_string(vcard),
|
||||
MTP_int(userId.bare)), // #TODO ids
|
||||
MTPReplyMarkup(),
|
||||
MTPVector<MTPMessageEntity>(),
|
||||
MTP_int(views),
|
||||
MTP_int(forwards),
|
||||
MTPMessageReplies(),
|
||||
MTPint(), // edit_date
|
||||
MTP_string(messagePostAuthor),
|
||||
MTPlong(),
|
||||
//MTPMessageReactions(),
|
||||
MTPVector<MTPRestrictionReason>(),
|
||||
MTPint()), // ttl_period
|
||||
clientFlags,
|
||||
NewMessageType::Unread);
|
||||
const auto viaBotId = UserId();
|
||||
const auto item = history->addNewLocalMessage(
|
||||
newId.msg,
|
||||
flags,
|
||||
viaBotId,
|
||||
action.replyTo,
|
||||
HistoryItem::NewMessageDate(action.options.scheduled),
|
||||
messageFromId,
|
||||
messagePostAuthor,
|
||||
TextWithEntities(),
|
||||
MTP_messageMediaContact(
|
||||
MTP_string(phone),
|
||||
MTP_string(firstName),
|
||||
MTP_string(lastName),
|
||||
MTP_string(), // vcard
|
||||
MTP_int(userId.bare)), // #TODO ids
|
||||
MTPReplyMarkup());
|
||||
|
||||
const auto media = MTP_inputMediaContact(
|
||||
MTP_string(phone),
|
||||
MTP_string(firstName),
|
||||
MTP_string(lastName),
|
||||
MTP_string(vcard));
|
||||
MTP_string()); // vcard
|
||||
sendMedia(item, media, action.options);
|
||||
|
||||
_session->data().sendHistoryChangeNotifications();
|
||||
@@ -4181,11 +4007,10 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
_session->data().registerMessageSentData(randomId, peer->id, sending.text);
|
||||
|
||||
MTPstring msgText(MTP_string(sending.text));
|
||||
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_entities;
|
||||
auto clientFlags = NewMessageClientFlags();
|
||||
auto flags = NewMessageFlags(peer);
|
||||
auto sendFlags = MTPmessages_SendMessage::Flags(0);
|
||||
if (action.replyTo) {
|
||||
flags |= MTPDmessage::Flag::f_reply_to;
|
||||
flags |= MessageFlag::HasReplyInfo;
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_reply_to_msg_id;
|
||||
}
|
||||
const auto replyHeader = NewMessageReplyHeader(action);
|
||||
@@ -4198,7 +4023,6 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
MTP_webPagePending(
|
||||
MTP_long(page->id),
|
||||
MTP_int(page->pendingTill)));
|
||||
flags |= MTPDmessage::Flag::f_media;
|
||||
}
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||
@@ -4206,10 +4030,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
if (silentPost) {
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_silent;
|
||||
}
|
||||
auto localEntities = Api::EntitiesToMTP(
|
||||
_session,
|
||||
sending.entities);
|
||||
auto sentEntities = Api::EntitiesToMTP(
|
||||
const auto sentEntities = Api::EntitiesToMTP(
|
||||
_session,
|
||||
sending.entities,
|
||||
Api::ConvertOption::SkipLocal);
|
||||
@@ -4227,39 +4048,23 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||
? _session->user()->name
|
||||
: QString();
|
||||
if (action.options.scheduled) {
|
||||
flags |= MTPDmessage::Flag::f_from_scheduled;
|
||||
flags |= MessageFlag::IsOrWasScheduled;
|
||||
sendFlags |= MTPmessages_SendMessage::Flag::f_schedule_date;
|
||||
} else {
|
||||
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
|
||||
flags |= MessageFlag::LocalHistoryEntry;
|
||||
}
|
||||
const auto views = 1;
|
||||
const auto forwards = 0;
|
||||
lastMessage = history->addNewMessage(
|
||||
MTP_message(
|
||||
MTP_flags(flags),
|
||||
MTP_int(newId.msg),
|
||||
peerToMTP(messageFromId),
|
||||
peerToMTP(peer->id),
|
||||
MTPMessageFwdHeader(),
|
||||
MTPint(), // via_bot_id
|
||||
replyHeader,
|
||||
MTP_int(
|
||||
HistoryItem::NewMessageDate(action.options.scheduled)),
|
||||
msgText,
|
||||
media,
|
||||
MTPReplyMarkup(),
|
||||
localEntities,
|
||||
MTP_int(views),
|
||||
MTP_int(forwards),
|
||||
MTPMessageReplies(),
|
||||
MTPint(), // edit_date
|
||||
MTP_string(messagePostAuthor),
|
||||
MTPlong(),
|
||||
//MTPMessageReactions(),
|
||||
MTPVector<MTPRestrictionReason>(),
|
||||
MTPint()), // ttl_period
|
||||
clientFlags,
|
||||
NewMessageType::Unread);
|
||||
const auto viaBotId = UserId();
|
||||
lastMessage = history->addNewLocalMessage(
|
||||
newId.msg,
|
||||
flags,
|
||||
viaBotId,
|
||||
action.replyTo,
|
||||
HistoryItem::NewMessageDate(action.options.scheduled),
|
||||
messageFromId,
|
||||
messagePostAuthor,
|
||||
sending,
|
||||
media,
|
||||
MTPReplyMarkup());
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
history->sendRequestId = request(MTPmessages_SendMessage(
|
||||
MTP_flags(sendFlags),
|
||||
@@ -4346,11 +4151,10 @@ void ApiWrap::sendInlineResult(
|
||||
_session->data().nextLocalMessageId());
|
||||
const auto randomId = openssl::RandomValue<uint64>();
|
||||
|
||||
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
|
||||
auto clientFlags = NewMessageClientFlags();
|
||||
auto flags = NewMessageFlags(peer);
|
||||
auto sendFlags = MTPmessages_SendInlineBotResult::Flag::f_clear_draft | 0;
|
||||
if (action.replyTo) {
|
||||
flags |= MTPDmessage::Flag::f_reply_to;
|
||||
flags |= MessageFlag::HasReplyInfo;
|
||||
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_reply_to_msg_id;
|
||||
}
|
||||
const auto anonymousPost = peer->amAnonymous();
|
||||
@@ -4360,13 +4164,13 @@ void ApiWrap::sendInlineResult(
|
||||
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_silent;
|
||||
}
|
||||
if (bot) {
|
||||
flags |= MTPDmessage::Flag::f_via_bot_id;
|
||||
flags |= MessageFlag::HasViaBot;
|
||||
}
|
||||
if (action.options.scheduled) {
|
||||
flags |= MTPDmessage::Flag::f_from_scheduled;
|
||||
flags |= MessageFlag::IsOrWasScheduled;
|
||||
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_schedule_date;
|
||||
} else {
|
||||
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
|
||||
flags |= MessageFlag::LocalHistoryEntry;
|
||||
}
|
||||
|
||||
const auto messageFromId = anonymousPost ? 0 : _session->userPeerId();
|
||||
@@ -4379,10 +4183,9 @@ void ApiWrap::sendInlineResult(
|
||||
data->addToHistory(
|
||||
history,
|
||||
flags,
|
||||
clientFlags,
|
||||
newId.msg,
|
||||
messageFromId,
|
||||
MTP_int(HistoryItem::NewMessageDate(action.options.scheduled)),
|
||||
HistoryItem::NewMessageDate(action.options.scheduled),
|
||||
bot ? peerToUser(bot->id) : 0,
|
||||
action.replyTo,
|
||||
messagePostAuthor);
|
||||
@@ -4784,52 +4587,6 @@ void ApiWrap::clearPeerPhoto(not_null<PhotoData*> photo) {
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::reloadPasswordState() {
|
||||
if (_passwordRequestId) {
|
||||
return;
|
||||
}
|
||||
_passwordRequestId = request(MTPaccount_GetPassword(
|
||||
)).done([=](const MTPaccount_Password &result) {
|
||||
_passwordRequestId = 0;
|
||||
result.match([&](const MTPDaccount_password &data) {
|
||||
openssl::AddRandomSeed(bytes::make_span(data.vsecure_random().v));
|
||||
if (_passwordState) {
|
||||
*_passwordState = Core::ParseCloudPasswordState(data);
|
||||
} else {
|
||||
_passwordState = std::make_unique<Core::CloudPasswordState>(
|
||||
Core::ParseCloudPasswordState(data));
|
||||
}
|
||||
_passwordStateChanges.fire_copy(*_passwordState);
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_passwordRequestId = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
void ApiWrap::clearUnconfirmedPassword() {
|
||||
_passwordRequestId = request(MTPaccount_CancelPasswordEmail(
|
||||
)).done([=](const MTPBool &result) {
|
||||
_passwordRequestId = 0;
|
||||
reloadPasswordState();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_passwordRequestId = 0;
|
||||
reloadPasswordState();
|
||||
}).send();
|
||||
}
|
||||
|
||||
rpl::producer<Core::CloudPasswordState> ApiWrap::passwordState() const {
|
||||
return _passwordState
|
||||
? _passwordStateChanges.events_starting_with_copy(*_passwordState)
|
||||
: (_passwordStateChanges.events() | rpl::type_erased());
|
||||
}
|
||||
|
||||
auto ApiWrap::passwordStateCurrent() const
|
||||
-> std::optional<Core::CloudPasswordState> {
|
||||
return _passwordState
|
||||
? base::make_optional(*_passwordState)
|
||||
: std::nullopt;
|
||||
}
|
||||
|
||||
void ApiWrap::reloadContactSignupSilent() {
|
||||
if (_contactSignupSilentRequestId) {
|
||||
return;
|
||||
@@ -4903,176 +4660,6 @@ void ApiWrap::saveSelfBio(const QString &text, FnMut<void()> done) {
|
||||
}).send();
|
||||
}
|
||||
|
||||
void ApiWrap::reloadPrivacy(Privacy::Key key) {
|
||||
if (_privacyRequestIds.contains(key)) {
|
||||
return;
|
||||
}
|
||||
const auto requestId = request(MTPaccount_GetPrivacy(
|
||||
Privacy::Input(key)
|
||||
)).done([=](const MTPaccount_PrivacyRules &result) {
|
||||
_privacyRequestIds.erase(key);
|
||||
result.match([&](const MTPDaccount_privacyRules &data) {
|
||||
_session->data().processUsers(data.vusers());
|
||||
_session->data().processChats(data.vchats());
|
||||
pushPrivacy(key, data.vrules().v);
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_privacyRequestIds.erase(key);
|
||||
}).send();
|
||||
_privacyRequestIds.emplace(key, requestId);
|
||||
}
|
||||
|
||||
auto ApiWrap::parsePrivacy(const QVector<MTPPrivacyRule> &rules)
|
||||
-> Privacy {
|
||||
using Option = Privacy::Option;
|
||||
|
||||
// This is simplified version of privacy rules interpretation.
|
||||
// But it should be fine for all the apps
|
||||
// that use the same subset of features.
|
||||
auto result = Privacy();
|
||||
auto optionSet = false;
|
||||
const auto SetOption = [&](Option option) {
|
||||
if (optionSet) return;
|
||||
optionSet = true;
|
||||
result.option = option;
|
||||
};
|
||||
auto &always = result.always;
|
||||
auto &never = result.never;
|
||||
const auto Feed = [&](const MTPPrivacyRule &rule) {
|
||||
rule.match([&](const MTPDprivacyValueAllowAll &) {
|
||||
SetOption(Option::Everyone);
|
||||
}, [&](const MTPDprivacyValueAllowContacts &) {
|
||||
SetOption(Option::Contacts);
|
||||
}, [&](const MTPDprivacyValueAllowUsers &data) {
|
||||
const auto &users = data.vusers().v;
|
||||
always.reserve(always.size() + users.size());
|
||||
for (const auto userId : users) {
|
||||
const auto user = _session->data().user(UserId(userId.v));
|
||||
if (!base::contains(never, user)
|
||||
&& !base::contains(always, user)) {
|
||||
always.emplace_back(user);
|
||||
}
|
||||
}
|
||||
}, [&](const MTPDprivacyValueAllowChatParticipants &data) {
|
||||
const auto &chats = data.vchats().v;
|
||||
always.reserve(always.size() + chats.size());
|
||||
for (const auto &chatId : chats) {
|
||||
const auto chat = _session->data().chatLoaded(chatId);
|
||||
const auto peer = chat
|
||||
? static_cast<PeerData*>(chat)
|
||||
: _session->data().channelLoaded(chatId);
|
||||
if (peer
|
||||
&& !base::contains(never, peer)
|
||||
&& !base::contains(always, peer)) {
|
||||
always.emplace_back(peer);
|
||||
}
|
||||
}
|
||||
}, [&](const MTPDprivacyValueDisallowContacts &) {
|
||||
// not supported
|
||||
}, [&](const MTPDprivacyValueDisallowAll &) {
|
||||
SetOption(Option::Nobody);
|
||||
}, [&](const MTPDprivacyValueDisallowUsers &data) {
|
||||
const auto &users = data.vusers().v;
|
||||
never.reserve(never.size() + users.size());
|
||||
for (const auto userId : users) {
|
||||
const auto user = _session->data().user(UserId(userId.v));
|
||||
if (!base::contains(always, user)
|
||||
&& !base::contains(never, user)) {
|
||||
never.emplace_back(user);
|
||||
}
|
||||
}
|
||||
}, [&](const MTPDprivacyValueDisallowChatParticipants &data) {
|
||||
const auto &chats = data.vchats().v;
|
||||
never.reserve(never.size() + chats.size());
|
||||
for (const auto &chatId : chats) {
|
||||
const auto chat = _session->data().chatLoaded(chatId);
|
||||
const auto peer = chat
|
||||
? static_cast<PeerData*>(chat)
|
||||
: _session->data().channelLoaded(chatId);
|
||||
if (peer
|
||||
&& !base::contains(always, peer)
|
||||
&& !base::contains(never, peer)) {
|
||||
never.emplace_back(peer);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
for (const auto &rule : rules) {
|
||||
Feed(rule);
|
||||
}
|
||||
Feed(MTP_privacyValueDisallowAll()); // disallow by default.
|
||||
return result;
|
||||
}
|
||||
|
||||
void ApiWrap::pushPrivacy(
|
||||
Privacy::Key key,
|
||||
const QVector<MTPPrivacyRule> &rules) {
|
||||
const auto &saved = (_privacyValues[key] = parsePrivacy(rules));
|
||||
const auto i = _privacyChanges.find(key);
|
||||
if (i != end(_privacyChanges)) {
|
||||
i->second.fire_copy(saved);
|
||||
}
|
||||
}
|
||||
|
||||
auto ApiWrap::privacyValue(Privacy::Key key) -> rpl::producer<Privacy> {
|
||||
if (const auto i = _privacyValues.find(key); i != end(_privacyValues)) {
|
||||
return _privacyChanges[key].events_starting_with_copy(i->second);
|
||||
} else {
|
||||
return _privacyChanges[key].events();
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::reloadBlockedPeers() {
|
||||
if (_blockedPeersRequestId) {
|
||||
return;
|
||||
}
|
||||
_blockedPeersRequestId = request(MTPcontacts_GetBlocked(
|
||||
MTP_int(0),
|
||||
MTP_int(kBlockedFirstSlice)
|
||||
)).done([=](const MTPcontacts_Blocked &result) {
|
||||
_blockedPeersRequestId = 0;
|
||||
const auto push = [&](
|
||||
int count,
|
||||
const QVector<MTPPeerBlocked> &list) {
|
||||
auto slice = BlockedPeersSlice();
|
||||
slice.total = std::max(count, list.size());
|
||||
slice.list.reserve(list.size());
|
||||
for (const auto &contact : list) {
|
||||
contact.match([&](const MTPDpeerBlocked &data) {
|
||||
const auto peer = _session->data().peerLoaded(
|
||||
peerFromMTP(data.vpeer_id()));
|
||||
if (peer) {
|
||||
peer->setIsBlocked(true);
|
||||
slice.list.push_back({ peer, data.vdate().v });
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!_blockedPeersSlice || *_blockedPeersSlice != slice) {
|
||||
_blockedPeersSlice = slice;
|
||||
_blockedPeersChanges.fire(std::move(slice));
|
||||
}
|
||||
};
|
||||
result.match([&](const MTPDcontacts_blockedSlice &data) {
|
||||
_session->data().processUsers(data.vusers());
|
||||
push(data.vcount().v, data.vblocked().v);
|
||||
}, [&](const MTPDcontacts_blocked &data) {
|
||||
_session->data().processUsers(data.vusers());
|
||||
push(0, data.vblocked().v);
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_blockedPeersRequestId = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
auto ApiWrap::blockedPeersSlice() -> rpl::producer<BlockedPeersSlice> {
|
||||
if (!_blockedPeersSlice) {
|
||||
reloadBlockedPeers();
|
||||
}
|
||||
return _blockedPeersSlice
|
||||
? _blockedPeersChanges.events_starting_with_copy(*_blockedPeersSlice)
|
||||
: (_blockedPeersChanges.events() | rpl::type_erased());
|
||||
}
|
||||
|
||||
Api::Authorizations &ApiWrap::authorizations() {
|
||||
return *_authorizations;
|
||||
}
|
||||
@@ -5081,6 +4668,14 @@ Api::AttachedStickers &ApiWrap::attachedStickers() {
|
||||
return *_attachedStickers;
|
||||
}
|
||||
|
||||
Api::BlockedPeers &ApiWrap::blockedPeers() {
|
||||
return *_blockedPeers;
|
||||
}
|
||||
|
||||
Api::CloudPassword &ApiWrap::cloudPassword() {
|
||||
return *_cloudPassword;
|
||||
}
|
||||
|
||||
Api::SelfDestruct &ApiWrap::selfDestruct() {
|
||||
return *_selfDestruct;
|
||||
}
|
||||
@@ -5093,6 +4688,10 @@ Api::GlobalPrivacy &ApiWrap::globalPrivacy() {
|
||||
return *_globalPrivacy;
|
||||
}
|
||||
|
||||
Api::UserPrivacy &ApiWrap::userPrivacy() {
|
||||
return *_userPrivacy;
|
||||
}
|
||||
|
||||
Api::InviteLinks &ApiWrap::inviteLinks() {
|
||||
return *_inviteLinks;
|
||||
}
|
||||
|
||||
@@ -45,10 +45,6 @@ namespace Dialogs {
|
||||
class Key;
|
||||
} // namespace Dialogs
|
||||
|
||||
namespace Core {
|
||||
struct CloudPasswordState;
|
||||
} // namespace Core
|
||||
|
||||
namespace Ui {
|
||||
struct PreparedList;
|
||||
} // namespace Ui
|
||||
@@ -58,9 +54,12 @@ namespace Api {
|
||||
class Updates;
|
||||
class Authorizations;
|
||||
class AttachedStickers;
|
||||
class BlockedPeers;
|
||||
class CloudPassword;
|
||||
class SelfDestruct;
|
||||
class SensitiveContent;
|
||||
class GlobalPrivacy;
|
||||
class UserPrivacy;
|
||||
class InviteLinks;
|
||||
|
||||
namespace details {
|
||||
@@ -113,46 +112,6 @@ public:
|
||||
using SendAction = Api::SendAction;
|
||||
using MessageToSend = Api::MessageToSend;
|
||||
|
||||
struct Privacy {
|
||||
enum class Key {
|
||||
PhoneNumber,
|
||||
AddedByPhone,
|
||||
LastSeen,
|
||||
Calls,
|
||||
Invites,
|
||||
CallsPeer2Peer,
|
||||
Forwards,
|
||||
ProfilePhoto,
|
||||
};
|
||||
enum class Option {
|
||||
Everyone,
|
||||
Contacts,
|
||||
Nobody,
|
||||
};
|
||||
Option option = Option::Everyone;
|
||||
std::vector<not_null<PeerData*>> always;
|
||||
std::vector<not_null<PeerData*>> never;
|
||||
|
||||
static MTPInputPrivacyKey Input(Key key);
|
||||
static std::optional<Key> KeyFromMTP(mtpTypeId type);
|
||||
};
|
||||
|
||||
struct BlockedPeersSlice {
|
||||
struct Item {
|
||||
PeerData *peer = nullptr;
|
||||
TimeId date = 0;
|
||||
|
||||
bool operator==(const Item &other) const;
|
||||
bool operator!=(const Item &other) const;
|
||||
};
|
||||
|
||||
QVector<Item> list;
|
||||
int total = 0;
|
||||
|
||||
bool operator==(const BlockedPeersSlice &other) const;
|
||||
bool operator!=(const BlockedPeersSlice &other) const;
|
||||
};
|
||||
|
||||
explicit ApiWrap(not_null<Main::Session*> session);
|
||||
~ApiWrap();
|
||||
|
||||
@@ -295,19 +254,10 @@ public:
|
||||
void joinChannel(not_null<ChannelData*> channel);
|
||||
void leaveChannel(not_null<ChannelData*> channel);
|
||||
|
||||
void blockPeer(not_null<PeerData*> peer);
|
||||
void unblockPeer(not_null<PeerData*> peer, Fn<void()> onDone = nullptr);
|
||||
|
||||
void requestNotifySettings(const MTPInputNotifyPeer &peer);
|
||||
void updateNotifySettingsDelayed(not_null<const PeerData*> peer);
|
||||
void saveDraftToCloudDelayed(not_null<History*> history);
|
||||
|
||||
void savePrivacy(
|
||||
const MTPInputPrivacyKey &key,
|
||||
QVector<MTPInputPrivacyRule> &&rules);
|
||||
void handlePrivacyChange(
|
||||
Privacy::Key key,
|
||||
const MTPVector<MTPPrivacyRule> &rules);
|
||||
static int OnlineTillFromStatus(
|
||||
const MTPUserStatus &status,
|
||||
int currentOnlineTill);
|
||||
@@ -433,11 +383,6 @@ public:
|
||||
void uploadPeerPhoto(not_null<PeerData*> peer, QImage &&image);
|
||||
void clearPeerPhoto(not_null<PhotoData*> photo);
|
||||
|
||||
void reloadPasswordState();
|
||||
void clearUnconfirmedPassword();
|
||||
rpl::producer<Core::CloudPasswordState> passwordState() const;
|
||||
std::optional<Core::CloudPasswordState> passwordStateCurrent() const;
|
||||
|
||||
void reloadContactSignupSilent();
|
||||
rpl::producer<bool> contactSignupSilent() const;
|
||||
std::optional<bool> contactSignupSilentCurrent() const;
|
||||
@@ -445,17 +390,14 @@ public:
|
||||
|
||||
void saveSelfBio(const QString &text, FnMut<void()> done);
|
||||
|
||||
void reloadPrivacy(Privacy::Key key);
|
||||
rpl::producer<Privacy> privacyValue(Privacy::Key key);
|
||||
|
||||
void reloadBlockedPeers();
|
||||
rpl::producer<BlockedPeersSlice> blockedPeersSlice();
|
||||
|
||||
[[nodiscard]] Api::Authorizations &authorizations();
|
||||
[[nodiscard]] Api::AttachedStickers &attachedStickers();
|
||||
[[nodiscard]] Api::BlockedPeers &blockedPeers();
|
||||
[[nodiscard]] Api::CloudPassword &cloudPassword();
|
||||
[[nodiscard]] Api::SelfDestruct &selfDestruct();
|
||||
[[nodiscard]] Api::SensitiveContent &sensitiveContent();
|
||||
[[nodiscard]] Api::GlobalPrivacy &globalPrivacy();
|
||||
[[nodiscard]] Api::UserPrivacy &userPrivacy();
|
||||
[[nodiscard]] Api::InviteLinks &inviteLinks();
|
||||
|
||||
void createPoll(
|
||||
@@ -469,6 +411,8 @@ public:
|
||||
void closePoll(not_null<HistoryItem*> item);
|
||||
void reloadPollResults(not_null<HistoryItem*> item);
|
||||
|
||||
void updatePrivacyLastSeens();
|
||||
|
||||
private:
|
||||
struct MessageDataRequest {
|
||||
using Callbacks = QList<RequestMessageDataCallback>;
|
||||
@@ -625,12 +569,6 @@ private:
|
||||
|
||||
void photoUploadReady(const FullMsgId &msgId, const MTPInputFile &file);
|
||||
|
||||
Privacy parsePrivacy(const QVector<MTPPrivacyRule> &rules);
|
||||
void pushPrivacy(
|
||||
Privacy::Key key,
|
||||
const QVector<MTPPrivacyRule> &rules);
|
||||
void updatePrivacyLastSeens(const QVector<MTPPrivacyRule> &rules);
|
||||
|
||||
void migrateDone(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<ChannelData*> channel);
|
||||
@@ -675,7 +613,6 @@ private:
|
||||
QMap<uint64, QPair<uint64, mtpRequestId> > _stickerSetRequests;
|
||||
|
||||
QMap<ChannelData*, mtpRequestId> _channelAmInRequests;
|
||||
base::flat_map<not_null<PeerData*>, mtpRequestId> _blockRequests;
|
||||
base::flat_map<PeerId, mtpRequestId> _notifySettingRequests;
|
||||
base::flat_map<not_null<History*>, mtpRequestId> _draftsSaveRequestIds;
|
||||
base::Timer _draftsSaveTimer;
|
||||
@@ -700,8 +637,6 @@ private:
|
||||
|
||||
base::flat_map<not_null<EmojiPtr>, StickersByEmoji> _stickersByEmoji;
|
||||
|
||||
base::flat_map<mtpTypeId, mtpRequestId> _privacySaveRequests;
|
||||
|
||||
mtpRequestId _contactsRequestId = 0;
|
||||
mtpRequestId _contactsStatusesRequestId = 0;
|
||||
|
||||
@@ -764,27 +699,18 @@ private:
|
||||
|
||||
base::flat_map<FullMsgId, not_null<PeerData*>> _peerPhotoUploads;
|
||||
|
||||
mtpRequestId _passwordRequestId = 0;
|
||||
std::unique_ptr<Core::CloudPasswordState> _passwordState;
|
||||
rpl::event_stream<Core::CloudPasswordState> _passwordStateChanges;
|
||||
|
||||
mtpRequestId _saveBioRequestId = 0;
|
||||
FnMut<void()> _saveBioDone;
|
||||
QString _saveBioText;
|
||||
|
||||
base::flat_map<Privacy::Key, mtpRequestId> _privacyRequestIds;
|
||||
base::flat_map<Privacy::Key, Privacy> _privacyValues;
|
||||
std::map<Privacy::Key, rpl::event_stream<Privacy>> _privacyChanges;
|
||||
|
||||
mtpRequestId _blockedPeersRequestId = 0;
|
||||
std::optional<BlockedPeersSlice> _blockedPeersSlice;
|
||||
rpl::event_stream<BlockedPeersSlice> _blockedPeersChanges;
|
||||
|
||||
const std::unique_ptr<Api::Authorizations> _authorizations;
|
||||
const std::unique_ptr<Api::AttachedStickers> _attachedStickers;
|
||||
const std::unique_ptr<Api::BlockedPeers> _blockedPeers;
|
||||
const std::unique_ptr<Api::CloudPassword> _cloudPassword;
|
||||
const std::unique_ptr<Api::SelfDestruct> _selfDestruct;
|
||||
const std::unique_ptr<Api::SensitiveContent> _sensitiveContent;
|
||||
const std::unique_ptr<Api::GlobalPrivacy> _globalPrivacy;
|
||||
const std::unique_ptr<Api::UserPrivacy> _userPrivacy;
|
||||
const std::unique_ptr<Api::InviteLinks> _inviteLinks;
|
||||
|
||||
base::flat_map<FullMsgId, mtpRequestId> _pollVotesRequestIds;
|
||||
|
||||
@@ -7,53 +7,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "app.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_abstract_structure.h"
|
||||
#include "data/data_media_types.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_document.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_location_manager.h"
|
||||
#include "history/history_item_components.h"
|
||||
#include "history/view/history_view_element.h"
|
||||
#include "media/audio/media_audio.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/cached_round_corners.h"
|
||||
#include "inline_bots/inline_bot_layout_item.h"
|
||||
#include "core/crash_reports.h"
|
||||
#include "core/update_checker.h"
|
||||
#include "core/sandbox.h"
|
||||
#include "core/application.h"
|
||||
#include "window/notifications_manager.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "platform/platform_notifications_manager.h"
|
||||
#include "storage/file_upload.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "storage/storage_facade.h"
|
||||
#include "storage/storage_shared_media.h"
|
||||
#include "mainwindow.h"
|
||||
#include "mainwidget.h"
|
||||
#include "apiwrap.h"
|
||||
#include "numbers.h"
|
||||
#include "main/main_session.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_overview.h"
|
||||
#include "styles/style_media_view.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_layers.h"
|
||||
|
||||
#include <QtCore/QBuffer>
|
||||
#include <QtGui/QFontDatabase>
|
||||
|
||||
#ifdef OS_MAC_OLD
|
||||
#include <libexif/exif-data.h>
|
||||
#endif // OS_MAC_OLD
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kImageAreaLimit = 12'032 * 9'024;
|
||||
@@ -70,41 +32,6 @@ HistoryView::Element *hoveredItem = nullptr,
|
||||
|
||||
namespace App {
|
||||
|
||||
QString formatPhone(QString phone) {
|
||||
if (phone.isEmpty()) return QString();
|
||||
if (phone.at(0) == '0') return phone;
|
||||
|
||||
QString number = phone;
|
||||
for (const QChar *ch = phone.constData(), *e = ch + phone.size(); ch != e; ++ch) {
|
||||
if (ch->unicode() < '0' || ch->unicode() > '9') {
|
||||
number = phone.replace(QRegularExpression(qsl("[^\\d]")), QString());
|
||||
}
|
||||
}
|
||||
QVector<int> groups = phoneNumberParse(number);
|
||||
if (groups.isEmpty()) return '+' + number;
|
||||
|
||||
QString result;
|
||||
result.reserve(number.size() + groups.size() + 1);
|
||||
result.append('+');
|
||||
int32 sum = 0;
|
||||
for (int32 i = 0, l = groups.size(); i < l; ++i) {
|
||||
result.append(number.midRef(sum, groups.at(i)));
|
||||
sum += groups.at(i);
|
||||
if (sum < number.size()) result.append(' ');
|
||||
}
|
||||
if (sum < number.size()) result.append(number.midRef(sum));
|
||||
return result;
|
||||
}
|
||||
|
||||
void initMedia() {
|
||||
Ui::StartCachedCorners();
|
||||
}
|
||||
|
||||
void deinitMedia() {
|
||||
Ui::FinishCachedCorners();
|
||||
Data::clearGlobalStructures();
|
||||
}
|
||||
|
||||
void hoveredItem(HistoryView::Element *item) {
|
||||
::hoveredItem = item;
|
||||
}
|
||||
@@ -195,80 +122,4 @@ namespace App {
|
||||
App::quit();
|
||||
}
|
||||
|
||||
QImage readImage(QByteArray data, QByteArray *format, bool opaque, bool *animated) {
|
||||
if (data.isEmpty()) {
|
||||
return QImage();
|
||||
}
|
||||
QByteArray tmpFormat;
|
||||
QImage result;
|
||||
QBuffer buffer(&data);
|
||||
if (!format) {
|
||||
format = &tmpFormat;
|
||||
}
|
||||
{
|
||||
QImageReader reader(&buffer, *format);
|
||||
#ifndef OS_MAC_OLD
|
||||
reader.setAutoTransform(true);
|
||||
#endif // OS_MAC_OLD
|
||||
if (animated) *animated = reader.supportsAnimation() && reader.imageCount() > 1;
|
||||
if (!reader.canRead()) {
|
||||
return QImage();
|
||||
}
|
||||
const auto imageSize = reader.size();
|
||||
if (imageSize.width() * imageSize.height() > kImageAreaLimit) {
|
||||
return QImage();
|
||||
}
|
||||
QByteArray fmt = reader.format();
|
||||
if (!fmt.isEmpty()) *format = fmt;
|
||||
if (!reader.read(&result)) {
|
||||
return QImage();
|
||||
}
|
||||
fmt = reader.format();
|
||||
if (!fmt.isEmpty()) *format = fmt;
|
||||
}
|
||||
buffer.seek(0);
|
||||
auto fmt = QString::fromUtf8(*format).toLower();
|
||||
if (fmt == "jpg" || fmt == "jpeg") {
|
||||
#ifdef OS_MAC_OLD
|
||||
if (auto exifData = exif_data_new_from_data((const uchar*)(data.constData()), data.size())) {
|
||||
auto byteOrder = exif_data_get_byte_order(exifData);
|
||||
if (auto exifEntry = exif_data_get_entry(exifData, EXIF_TAG_ORIENTATION)) {
|
||||
auto orientationFix = [exifEntry, byteOrder] {
|
||||
auto orientation = exif_get_short(exifEntry->data, byteOrder);
|
||||
switch (orientation) {
|
||||
case 2: return QTransform(-1, 0, 0, 1, 0, 0);
|
||||
case 3: return QTransform(-1, 0, 0, -1, 0, 0);
|
||||
case 4: return QTransform(1, 0, 0, -1, 0, 0);
|
||||
case 5: return QTransform(0, -1, -1, 0, 0, 0);
|
||||
case 6: return QTransform(0, 1, -1, 0, 0, 0);
|
||||
case 7: return QTransform(0, 1, 1, 0, 0, 0);
|
||||
case 8: return QTransform(0, -1, 1, 0, 0, 0);
|
||||
}
|
||||
return QTransform();
|
||||
};
|
||||
result = result.transformed(orientationFix());
|
||||
}
|
||||
exif_data_free(exifData);
|
||||
}
|
||||
#endif // OS_MAC_OLD
|
||||
} else if (opaque) {
|
||||
result = Images::prepareOpaque(std::move(result));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QImage readImage(const QString &file, QByteArray *format, bool opaque, bool *animated, QByteArray *content) {
|
||||
QFile f(file);
|
||||
if (f.size() > kImageSizeLimit || !f.open(QIODevice::ReadOnly)) {
|
||||
if (animated) *animated = false;
|
||||
return QImage();
|
||||
}
|
||||
auto imageBytes = f.readAll();
|
||||
auto result = readImage(imageBytes, format, opaque, animated);
|
||||
if (content && !result.isNull()) {
|
||||
*content = imageBytes;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,15 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "data/data_types.h"
|
||||
|
||||
namespace HistoryView {
|
||||
class Element;
|
||||
} // namespace HistoryView
|
||||
|
||||
namespace App {
|
||||
QString formatPhone(QString phone);
|
||||
|
||||
void hoveredItem(HistoryView::Element *item);
|
||||
HistoryView::Element *hoveredItem();
|
||||
void pressedItem(HistoryView::Element *item);
|
||||
@@ -28,9 +24,6 @@ namespace App {
|
||||
HistoryView::Element *mousedItem();
|
||||
void clearMousedItems();
|
||||
|
||||
void initMedia();
|
||||
void deinitMedia();
|
||||
|
||||
enum LaunchState {
|
||||
Launched = 0,
|
||||
QuitRequested = 1,
|
||||
@@ -42,8 +35,4 @@ namespace App {
|
||||
void setLaunchState(LaunchState state);
|
||||
void restart();
|
||||
|
||||
constexpr auto kImageSizeLimit = 64 * 1024 * 1024; // Open images up to 64mb jpg/png/gif
|
||||
QImage readImage(QByteArray data, QByteArray *format = nullptr, bool opaque = true, bool *animated = nullptr);
|
||||
QImage readImage(const QString &file, QByteArray *format = nullptr, bool opaque = true, bool *animated = nullptr, QByteArray *content = 0);
|
||||
|
||||
};
|
||||
|
||||
@@ -93,13 +93,9 @@ void AboutBox::showVersionHistory() {
|
||||
url += qsl("win/%1.zip");
|
||||
} else if (Platform::IsWindows64Bit()) {
|
||||
url += qsl("win64/%1.zip");
|
||||
} else if (Platform::IsOSXBuild()) {
|
||||
url += qsl("osx/%1.zip");
|
||||
} else if (Platform::IsMac()) {
|
||||
url += qsl("mac/%1.zip");
|
||||
} else if (Platform::IsLinux32Bit()) {
|
||||
url += qsl("linux32/%1.tar.xz");
|
||||
} else if (Platform::IsLinux64Bit()) {
|
||||
} else if (Platform::IsLinux()) {
|
||||
url += qsl("linux/%1.tar.xz");
|
||||
} else {
|
||||
Unexpected("Platform value.");
|
||||
|
||||
@@ -9,7 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "app.h"
|
||||
|
||||
namespace Ui {
|
||||
namespace internal {
|
||||
|
||||
@@ -7,41 +7,139 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "boxes/auto_lock_box.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "core/application.h"
|
||||
#include "mainwindow.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/time_input.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
AutoLockBox::AutoLockBox(QWidget*, not_null<Main::Session*> session)
|
||||
: _session(session) {
|
||||
namespace {
|
||||
|
||||
constexpr auto kCustom = std::numeric_limits<int>::max();
|
||||
constexpr auto kOptions = { 60, 300, 3600, 18000, kCustom };
|
||||
constexpr auto kDefaultCustom = "10:00"_cs;
|
||||
|
||||
auto TimeString(int seconds) {
|
||||
const auto hours = seconds / 3600;
|
||||
const auto minutes = (seconds - hours * 3600) / 60;
|
||||
return QString("%1:%2").arg(hours).arg(minutes, 2, 10, QLatin1Char('0'));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AutoLockBox::AutoLockBox(QWidget*) {
|
||||
}
|
||||
|
||||
void AutoLockBox::prepare() {
|
||||
setTitle(tr::lng_passcode_autolock());
|
||||
|
||||
addButton(tr::lng_box_ok(), [this] { closeBox(); });
|
||||
addButton(tr::lng_box_ok(), [=] { closeBox(); });
|
||||
|
||||
auto options = { 60, 300, 3600, 18000 };
|
||||
const auto currentTime = Core::App().settings().autoLock();
|
||||
|
||||
auto group = std::make_shared<Ui::RadiobuttonGroup>(
|
||||
Core::App().settings().autoLock());
|
||||
const auto group = std::make_shared<Ui::RadiobuttonGroup>(
|
||||
ranges::contains(kOptions, currentTime) ? currentTime : kCustom);
|
||||
|
||||
const auto x = st::boxPadding.left() + st::boxOptionListPadding.left();
|
||||
auto y = st::boxOptionListPadding.top() + st::autolockButton.margin.top();
|
||||
auto count = int(options.size());
|
||||
const auto count = int(kOptions.size());
|
||||
_options.reserve(count);
|
||||
for (auto seconds : options) {
|
||||
_options.emplace_back(this, group, seconds, (seconds % 3600) ? tr::lng_passcode_autolock_minutes(tr::now, lt_count, seconds / 60) : tr::lng_passcode_autolock_hours(tr::now, lt_count, seconds / 3600), st::autolockButton);
|
||||
_options.back()->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), y);
|
||||
for (const auto seconds : kOptions) {
|
||||
const auto text = [&] {
|
||||
if (seconds == kCustom) {
|
||||
return QString();
|
||||
}
|
||||
const auto minutes = (seconds % 3600);
|
||||
return (minutes
|
||||
? tr::lng_passcode_autolock_minutes
|
||||
: tr::lng_passcode_autolock_hours)(
|
||||
tr::now,
|
||||
lt_count,
|
||||
minutes ? (seconds / 60) : (seconds / 3600));
|
||||
}();
|
||||
_options.emplace_back(
|
||||
this,
|
||||
group,
|
||||
seconds,
|
||||
text,
|
||||
st::autolockButton);
|
||||
_options.back()->moveToLeft(x, y);
|
||||
y += _options.back()->heightNoMargins() + st::boxOptionListSkip;
|
||||
}
|
||||
group->setChangedCallback([this](int value) { durationChanged(value); });
|
||||
|
||||
setDimensions(st::autolockWidth, st::boxOptionListPadding.top() + count * _options.back()->heightNoMargins() + (count - 1) * st::boxOptionListSkip + st::boxOptionListPadding.bottom() + st::boxPadding.bottom());
|
||||
const auto timeInput = [&] {
|
||||
const auto &last = _options.back();
|
||||
const auto &st = st::autolockButton;
|
||||
|
||||
const auto textLeft = st.checkPosition.x()
|
||||
+ last->checkRect().width()
|
||||
+ st.textPosition.x();
|
||||
const auto textTop = st.margin.top() + st.textPosition.y();
|
||||
|
||||
const auto timeInput = Ui::CreateChild<Ui::TimeInput>(
|
||||
this,
|
||||
(group->value() == kCustom)
|
||||
? TimeString(currentTime)
|
||||
: kDefaultCustom.utf8(),
|
||||
st::autolockTimeField,
|
||||
st::autolockDateField,
|
||||
st::scheduleTimeSeparator,
|
||||
st::scheduleTimeSeparatorPadding);
|
||||
timeInput->resizeToWidth(st::autolockTimeWidth);
|
||||
timeInput->moveToLeft(last->x() + textLeft, last->y() + textTop);
|
||||
return timeInput;
|
||||
}();
|
||||
|
||||
const auto collect = [=] {
|
||||
const auto timeValue = timeInput->valueCurrent().split(':');
|
||||
if (timeValue.size() != 2) {
|
||||
return 0;
|
||||
}
|
||||
return timeValue[0].toInt() * 3600 + timeValue[1].toInt() * 60;
|
||||
};
|
||||
|
||||
timeInput->focuses(
|
||||
) | rpl::start_with_next([=] {
|
||||
group->setValue(kCustom);
|
||||
}, lifetime());
|
||||
|
||||
group->setChangedCallback([=](int value) {
|
||||
if (value != kCustom) {
|
||||
durationChanged(value);
|
||||
} else {
|
||||
timeInput->setFocusFast();
|
||||
}
|
||||
});
|
||||
|
||||
rpl::merge(
|
||||
boxClosing() | rpl::filter([=] { return group->value() == kCustom; }),
|
||||
timeInput->submitRequests()
|
||||
) | rpl::start_with_next([=] {
|
||||
if (const auto result = collect()) {
|
||||
durationChanged(result);
|
||||
} else {
|
||||
timeInput->showError();
|
||||
}
|
||||
}, lifetime());
|
||||
|
||||
const auto timeInputBottom = timeInput->y() + timeInput->height();
|
||||
setDimensions(
|
||||
st::autolockWidth,
|
||||
st::boxOptionListPadding.top()
|
||||
+ (timeInputBottom - _options.back()->bottomNoMargins())
|
||||
+ count * _options.back()->heightNoMargins()
|
||||
+ (count - 1) * st::boxOptionListSkip
|
||||
+ st::boxOptionListPadding.bottom()
|
||||
+ st::boxPadding.bottom());
|
||||
}
|
||||
|
||||
void AutoLockBox::durationChanged(int seconds) {
|
||||
if (Core::App().settings().autoLock() == seconds) {
|
||||
closeBox();
|
||||
return;
|
||||
}
|
||||
Core::App().settings().setAutoLock(seconds);
|
||||
Core::App().saveSettingsDelayed();
|
||||
|
||||
|
||||
@@ -9,17 +9,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Ui {
|
||||
class Radiobutton;
|
||||
} // namespace Ui
|
||||
|
||||
class AutoLockBox : public Ui::BoxContent {
|
||||
public:
|
||||
AutoLockBox(QWidget*, not_null<Main::Session*> session);
|
||||
AutoLockBox(QWidget*);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
@@ -27,8 +23,6 @@ protected:
|
||||
private:
|
||||
void durationChanged(int seconds);
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
std::vector<object_ptr<Ui::Radiobutton>> _options;
|
||||
|
||||
};
|
||||
|
||||
@@ -239,8 +239,10 @@ void BackgroundBox::Inner::sortPapers() {
|
||||
return std::make_tuple(
|
||||
data.id() == current,
|
||||
night ? data.isDark() : !data.isDark(),
|
||||
!data.isDefault() && !data.isLocal(),
|
||||
!data.isDefault() && data.isLocal());
|
||||
Data::IsDefaultWallPaper(data),
|
||||
!data.isDefault() && !Data::IsLegacy1DefaultWallPaper(data),
|
||||
Data::IsLegacy2DefaultWallPaper(data),
|
||||
Data::IsLegacy1DefaultWallPaper(data));
|
||||
});
|
||||
if (!_papers.empty() && _papers.front().data.id() == current) {
|
||||
_papers.front().data = _papers.front().data.withParamsFrom(
|
||||
@@ -253,7 +255,7 @@ void BackgroundBox::Inner::updatePapers() {
|
||||
|
||||
_papers = _session->data().wallpapers(
|
||||
) | ranges::views::filter([](const Data::WallPaper &paper) {
|
||||
return !paper.isPattern() || paper.backgroundColor().has_value();
|
||||
return !paper.isPattern() || !paper.backgroundColors().empty();
|
||||
}) | ranges::views::transform([](const Data::WallPaper &paper) {
|
||||
return Paper{ paper };
|
||||
}) | ranges::to_vector;
|
||||
@@ -324,8 +326,18 @@ void BackgroundBox::Inner::validatePaperThumbnail(
|
||||
paper.dataMedia = document->createMediaView();
|
||||
paper.dataMedia->thumbnailWanted(paper.data.fileOrigin());
|
||||
}
|
||||
}
|
||||
if (!paper.dataMedia || !paper.dataMedia->thumbnail()) {
|
||||
if (!paper.dataMedia->thumbnail()) {
|
||||
return;
|
||||
}
|
||||
} else if (!paper.data.backgroundColors().empty()) {
|
||||
paper.thumbnail = Ui::PixmapFromImage(
|
||||
Data::GenerateWallPaper(
|
||||
st::backgroundSize * cIntRetinaFactor(),
|
||||
paper.data.backgroundColors(),
|
||||
paper.data.gradientRotation()));
|
||||
paper.thumbnail.setDevicePixelRatio(cRetinaFactor());
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -334,12 +346,11 @@ void BackgroundBox::Inner::validatePaperThumbnail(
|
||||
: paper.dataMedia->thumbnail();
|
||||
auto original = thumbnail->original();
|
||||
if (paper.data.isPattern()) {
|
||||
const auto color = *paper.data.backgroundColor();
|
||||
original = Data::PreparePatternImage(
|
||||
std::move(original),
|
||||
color,
|
||||
Data::PatternColor(color),
|
||||
paper.data.patternIntensity());
|
||||
paper.data.backgroundColors(),
|
||||
paper.data.gradientRotation(),
|
||||
paper.data.patternOpacity());
|
||||
}
|
||||
paper.thumbnail = Ui::PixmapFromImage(TakeMiddleSample(
|
||||
original,
|
||||
@@ -366,6 +377,7 @@ void BackgroundBox::Inner::paintPaper(
|
||||
_check->paint(p, checkLeft, checkTop, width());
|
||||
} else if (Data::IsCloudWallPaper(paper.data)
|
||||
&& !Data::IsDefaultWallPaper(paper.data)
|
||||
&& !Data::IsLegacy2DefaultWallPaper(paper.data)
|
||||
&& !v::is_null(over)
|
||||
&& (&paper == &_papers[getSelectionIndex(over)])) {
|
||||
const auto deleteSelected = v::is<DeleteSelected>(over);
|
||||
@@ -395,6 +407,7 @@ void BackgroundBox::Inner::mouseMoveEvent(QMouseEvent *e) {
|
||||
} else if (result >= _papers.size()) {
|
||||
return Selection();
|
||||
}
|
||||
auto &data = _papers[result].data;
|
||||
const auto deleteLeft = (column + 1) * (width + skip)
|
||||
- st::stickerPanDeleteIconBg.width();
|
||||
const auto deleteBottom = row * (height + skip) + skip
|
||||
@@ -402,9 +415,10 @@ void BackgroundBox::Inner::mouseMoveEvent(QMouseEvent *e) {
|
||||
const auto currentId = Window::Theme::Background()->id();
|
||||
const auto inDelete = (x >= deleteLeft)
|
||||
&& (y < deleteBottom)
|
||||
&& Data::IsCloudWallPaper(_papers[result].data)
|
||||
&& !Data::IsDefaultWallPaper(_papers[result].data)
|
||||
&& (currentId != _papers[result].data.id());
|
||||
&& Data::IsCloudWallPaper(data)
|
||||
&& !Data::IsDefaultWallPaper(data)
|
||||
&& !Data::IsLegacy2DefaultWallPaper(data)
|
||||
&& (currentId != data.id());
|
||||
return (result >= _papers.size())
|
||||
? Selection()
|
||||
: inDelete
|
||||
|
||||
@@ -279,35 +279,36 @@ bool ServiceCheck::checkRippleStartPosition(QPoint position) const {
|
||||
});
|
||||
}
|
||||
|
||||
AdminLog::OwnedItem GenerateTextItem(
|
||||
[[nodiscard]] AdminLog::OwnedItem GenerateTextItem(
|
||||
not_null<HistoryView::ElementDelegate*> delegate,
|
||||
not_null<History*> history,
|
||||
const QString &text,
|
||||
bool out) {
|
||||
Expects(history->peer->isUser());
|
||||
|
||||
using Flag = MTPDmessage::Flag;
|
||||
static auto id = ServerMaxMsgId + (ServerMaxMsgId / 3);
|
||||
const auto flags = Flag::f_entities
|
||||
| Flag::f_from_id
|
||||
| (out ? Flag::f_out : Flag(0));
|
||||
const auto clientFlags = MTPDmessage_ClientFlag::f_fake_history_item;
|
||||
const auto replyTo = 0;
|
||||
const auto viaBotId = UserId(0);
|
||||
const auto flags = MessageFlag::FakeHistoryItem
|
||||
| MessageFlag::HasFromId
|
||||
| (out ? MessageFlag::Outgoing : MessageFlag(0));
|
||||
const auto replyTo = MsgId();
|
||||
const auto viaBotId = UserId();
|
||||
const auto groupedId = uint64();
|
||||
const auto item = history->makeMessage(
|
||||
++id,
|
||||
flags,
|
||||
clientFlags,
|
||||
replyTo,
|
||||
viaBotId,
|
||||
base::unixtime::now(),
|
||||
out ? history->session().userId() : peerToUser(history->peer->id),
|
||||
QString(),
|
||||
TextWithEntities{ TextUtilities::Clean(text) });
|
||||
TextWithEntities{ TextUtilities::Clean(text) },
|
||||
MTP_messageMediaEmpty(),
|
||||
MTPReplyMarkup(),
|
||||
groupedId);
|
||||
return AdminLog::OwnedItem(delegate, item);
|
||||
}
|
||||
|
||||
QImage PrepareScaledNonPattern(
|
||||
[[nodiscard]] QImage PrepareScaledNonPattern(
|
||||
const QImage &image,
|
||||
Images::Option blur) {
|
||||
const auto size = st::boxWideWidth;
|
||||
@@ -330,66 +331,31 @@ QImage PrepareScaledNonPattern(
|
||||
size);
|
||||
}
|
||||
|
||||
QImage ColorizePattern(QImage image, QColor color) {
|
||||
if (image.format() != QImage::Format_ARGB32_Premultiplied) {
|
||||
image = std::move(image).convertToFormat(
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
}
|
||||
// Similar to style::colorizeImage.
|
||||
// But style::colorizeImage takes pattern with all pixels having the
|
||||
// same components value, from (0, 0, 0, 0) to (255, 255, 255, 255).
|
||||
//
|
||||
// While in patterns we have different value ranges, usually they are
|
||||
// from (0, 0, 0, 0) to (0, 0, 0, 255), so we should use only 'alpha'.
|
||||
|
||||
const auto width = image.width();
|
||||
const auto height = image.height();
|
||||
const auto pattern = anim::shifted(color);
|
||||
|
||||
constexpr auto resultIntsPerPixel = 1;
|
||||
const auto resultIntsPerLine = (image.bytesPerLine() >> 2);
|
||||
const auto resultIntsAdded = resultIntsPerLine - width * resultIntsPerPixel;
|
||||
auto resultInts = reinterpret_cast<uint32*>(image.bits());
|
||||
Assert(resultIntsAdded >= 0);
|
||||
Assert(image.depth() == static_cast<int>((resultIntsPerPixel * sizeof(uint32)) << 3));
|
||||
Assert(image.bytesPerLine() == (resultIntsPerLine << 2));
|
||||
|
||||
const auto maskBytesPerPixel = (image.depth() >> 3);
|
||||
const auto maskBytesPerLine = image.bytesPerLine();
|
||||
const auto maskBytesAdded = maskBytesPerLine - width * maskBytesPerPixel;
|
||||
|
||||
// We want to read the last byte of four available.
|
||||
// This is the difference with style::colorizeImage.
|
||||
auto maskBytes = image.constBits() + (maskBytesPerPixel - 1);
|
||||
Assert(maskBytesAdded >= 0);
|
||||
Assert(image.depth() == (maskBytesPerPixel << 3));
|
||||
for (auto y = 0; y != height; ++y) {
|
||||
for (auto x = 0; x != width; ++x) {
|
||||
auto maskOpacity = static_cast<anim::ShiftedMultiplier>(*maskBytes) + 1;
|
||||
*resultInts = anim::unshifted(pattern * maskOpacity);
|
||||
maskBytes += maskBytesPerPixel;
|
||||
resultInts += resultIntsPerPixel;
|
||||
}
|
||||
maskBytes += maskBytesAdded;
|
||||
resultInts += resultIntsAdded;
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
QImage PrepareScaledFromFull(
|
||||
[[nodiscard]] QImage PrepareScaledFromFull(
|
||||
const QImage &image,
|
||||
std::optional<QColor> patternBackground,
|
||||
bool isPattern,
|
||||
const std::vector<QColor> &background,
|
||||
int gradientRotation,
|
||||
float64 patternOpacity,
|
||||
Images::Option blur = Images::Option(0)) {
|
||||
auto result = PrepareScaledNonPattern(image, blur);
|
||||
if (patternBackground) {
|
||||
result = ColorizePattern(
|
||||
if (isPattern) {
|
||||
result = Data::PreparePatternImage(
|
||||
std::move(result),
|
||||
Data::PatternColor(*patternBackground));
|
||||
background,
|
||||
gradientRotation,
|
||||
patternOpacity);
|
||||
}
|
||||
return std::move(result).convertToFormat(
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
}
|
||||
|
||||
[[nodiscard]] QImage BlackImage(QSize size) {
|
||||
auto result = QImage(size, QImage::Format_ARGB32_Premultiplied);
|
||||
result.fill(Qt::black);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BackgroundPreviewBox::BackgroundPreviewBox(
|
||||
@@ -414,12 +380,28 @@ BackgroundPreviewBox::BackgroundPreviewBox(
|
||||
if (_media) {
|
||||
_media->thumbnailWanted(_paper.fileOrigin());
|
||||
}
|
||||
generateBackground();
|
||||
_controller->session().downloaderTaskFinished(
|
||||
) | rpl::start_with_next([=] {
|
||||
update();
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::generateBackground() {
|
||||
if (_paper.backgroundColors().empty()) {
|
||||
return;
|
||||
}
|
||||
const auto size = QSize(st::boxWideWidth, st::boxWideWidth)
|
||||
* cIntRetinaFactor();
|
||||
_generated = Ui::PixmapFromImage((_paper.patternOpacity() >= 0.)
|
||||
? Data::GenerateWallPaper(
|
||||
size,
|
||||
_paper.backgroundColors(),
|
||||
_paper.gradientRotation())
|
||||
: BlackImage(size));
|
||||
_generated.setDevicePixelRatio(cRetinaFactor());
|
||||
}
|
||||
|
||||
not_null<HistoryView::ElementDelegate*> BackgroundPreviewBox::delegate() {
|
||||
return static_cast<HistoryView::ElementDelegate*>(this);
|
||||
}
|
||||
@@ -432,7 +414,7 @@ void BackgroundPreviewBox::prepare() {
|
||||
if (_paper.hasShareUrl()) {
|
||||
addLeftButton(tr::lng_background_share(), [=] { share(); });
|
||||
}
|
||||
updateServiceBg(_paper.backgroundColor());
|
||||
updateServiceBg(_paper.backgroundColors());
|
||||
|
||||
_paper.loadDocument();
|
||||
const auto document = _paper.document();
|
||||
@@ -520,21 +502,23 @@ void BackgroundPreviewBox::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
const auto ms = crl::now();
|
||||
const auto color = _paper.backgroundColor();
|
||||
if (color) {
|
||||
p.fillRect(e->rect(), *color);
|
||||
if (_scaled.isNull()) {
|
||||
setScaledFromThumb();
|
||||
}
|
||||
if (!color || _paper.isPattern()) {
|
||||
if (!_scaled.isNull() || setScaledFromThumb()) {
|
||||
paintImage(p);
|
||||
paintRadial(p);
|
||||
} else if (!color) {
|
||||
p.fillRect(e->rect(), st::boxBg);
|
||||
return;
|
||||
} else {
|
||||
// Progress of pattern loading.
|
||||
paintRadial(p);
|
||||
}
|
||||
if (!_generated.isNull()
|
||||
&& (_scaled.isNull()
|
||||
|| (_fadeOutThumbnail.isNull() && _fadeIn.animating()))) {
|
||||
p.drawPixmap(0, 0, _generated);
|
||||
}
|
||||
if (!_scaled.isNull()) {
|
||||
paintImage(p);
|
||||
paintRadial(p);
|
||||
} else if (_generated.isNull()) {
|
||||
p.fillRect(e->rect(), st::boxBg);
|
||||
return;
|
||||
} else {
|
||||
// Progress of pattern loading.
|
||||
paintRadial(p);
|
||||
}
|
||||
paintTexts(p, ms);
|
||||
}
|
||||
@@ -542,10 +526,6 @@ void BackgroundPreviewBox::paintEvent(QPaintEvent *e) {
|
||||
void BackgroundPreviewBox::paintImage(Painter &p) {
|
||||
Expects(!_scaled.isNull());
|
||||
|
||||
const auto master = _paper.isPattern()
|
||||
? std::clamp(_paper.patternIntensity() / 100., 0., 1.)
|
||||
: 1.;
|
||||
|
||||
const auto factor = cIntRetinaFactor();
|
||||
const auto size = st::boxWideWidth;
|
||||
const auto from = QRect(
|
||||
@@ -562,7 +542,7 @@ void BackgroundPreviewBox::paintImage(Painter &p) {
|
||||
const auto &pixmap = (!_blurred.isNull() && _paper.isBlurred())
|
||||
? _blurred
|
||||
: _scaled;
|
||||
p.setOpacity(master * fade);
|
||||
p.setOpacity(fade);
|
||||
p.drawPixmap(rect(), pixmap, from);
|
||||
checkBlurAnimationStart();
|
||||
}
|
||||
@@ -609,11 +589,18 @@ QRect BackgroundPreviewBox::radialRect() const {
|
||||
void BackgroundPreviewBox::paintTexts(Painter &p, crl::time ms) {
|
||||
const auto height1 = _text1->height();
|
||||
const auto height2 = _text2->height();
|
||||
const auto context = HistoryView::PaintContext{
|
||||
.bubblesPattern = nullptr, // #TODO bubbles
|
||||
.viewport = rect(),
|
||||
.clip = rect(),
|
||||
.selection = TextSelection(),
|
||||
.now = ms,
|
||||
};
|
||||
p.translate(0, textsTop());
|
||||
paintDate(p);
|
||||
_text1->draw(p, rect(), TextSelection(), ms);
|
||||
_text1->draw(p, context);
|
||||
p.translate(0, height1);
|
||||
_text2->draw(p, rect(), TextSelection(), ms);
|
||||
_text2->draw(p, context);
|
||||
p.translate(0, height2);
|
||||
}
|
||||
|
||||
@@ -622,6 +609,7 @@ void BackgroundPreviewBox::paintDate(Painter &p) {
|
||||
if (!date || !_serviceBg) {
|
||||
return;
|
||||
}
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
const auto text = date->text;
|
||||
const auto bubbleHeight = st::msgServicePadding.top() + st::msgServiceFont->height + st::msgServicePadding.bottom();
|
||||
const auto bubbleTop = st::msgServiceMargin.top();
|
||||
@@ -653,7 +641,10 @@ void BackgroundPreviewBox::radialAnimationCallback(crl::time now) {
|
||||
checkLoadedDocument();
|
||||
}
|
||||
|
||||
bool BackgroundPreviewBox::setScaledFromThumb() {
|
||||
void BackgroundPreviewBox::setScaledFromThumb() {
|
||||
if (!_scaled.isNull()) {
|
||||
return;
|
||||
}
|
||||
const auto localThumbnail = _paper.localThumbnail();
|
||||
const auto thumbnail = localThumbnail
|
||||
? localThumbnail
|
||||
@@ -661,13 +652,16 @@ bool BackgroundPreviewBox::setScaledFromThumb() {
|
||||
? _media->thumbnail()
|
||||
: nullptr;
|
||||
if (!thumbnail) {
|
||||
return false;
|
||||
return;
|
||||
} else if (_paper.isPattern() && _paper.document() != nullptr) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
auto scaled = PrepareScaledFromFull(
|
||||
thumbnail->original(),
|
||||
patternBackgroundColor(),
|
||||
_paper.isPattern(),
|
||||
_paper.backgroundColors(),
|
||||
_paper.gradientRotation(),
|
||||
_paper.patternOpacity(),
|
||||
_paper.document() ? Images::Option::Blurred : Images::Option(0));
|
||||
auto blurred = (_paper.document() || _paper.isPattern())
|
||||
? QImage()
|
||||
@@ -675,13 +669,12 @@ bool BackgroundPreviewBox::setScaledFromThumb() {
|
||||
Data::PrepareBlurredBackground(thumbnail->original()),
|
||||
Images::Option(0));
|
||||
setScaledFromImage(std::move(scaled), std::move(blurred));
|
||||
return true;
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::setScaledFromImage(
|
||||
QImage &&image,
|
||||
QImage &&blurred) {
|
||||
updateServiceBg(Window::Theme::CountAverageColor(image));
|
||||
updateServiceBg({ Window::Theme::CountAverageColor(image) });
|
||||
if (!_full.isNull()) {
|
||||
startFadeInFrom(std::move(_scaled));
|
||||
}
|
||||
@@ -708,16 +701,20 @@ void BackgroundPreviewBox::checkBlurAnimationStart() {
|
||||
startFadeInFrom(_paper.isBlurred() ? _scaled : _blurred);
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::updateServiceBg(std::optional<QColor> background) {
|
||||
if (background) {
|
||||
_serviceBg = Window::Theme::AdjustedColor(
|
||||
st::msgServiceBg->c,
|
||||
*background);
|
||||
void BackgroundPreviewBox::updateServiceBg(const std::vector<QColor> &bg) {
|
||||
const auto count = int(bg.size());
|
||||
if (!count) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<QColor> BackgroundPreviewBox::patternBackgroundColor() const {
|
||||
return _paper.isPattern() ? _paper.backgroundColor() : std::nullopt;
|
||||
auto red = 0, green = 0, blue = 0;
|
||||
for (const auto &color : bg) {
|
||||
red += color.red();
|
||||
green += color.green();
|
||||
blue += color.blue();
|
||||
}
|
||||
_serviceBg = Window::Theme::AdjustedColor(
|
||||
st::msgServiceBg->c,
|
||||
QColor(red / count, green / count, blue / count));
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::checkLoadedDocument() {
|
||||
@@ -735,15 +732,23 @@ void BackgroundPreviewBox::checkLoadedDocument() {
|
||||
crl::async([
|
||||
this,
|
||||
image = std::move(image),
|
||||
patternBackground = patternBackgroundColor(),
|
||||
isPattern = _paper.isPattern(),
|
||||
background = _paper.backgroundColors(),
|
||||
gradientRotation = _paper.gradientRotation(),
|
||||
patternOpacity = _paper.patternOpacity(),
|
||||
guard = _generating.make_guard()
|
||||
]() mutable {
|
||||
auto scaled = PrepareScaledFromFull(image, patternBackground);
|
||||
auto blurred = patternBackground
|
||||
? QImage()
|
||||
: PrepareScaledNonPattern(
|
||||
auto scaled = PrepareScaledFromFull(
|
||||
image,
|
||||
isPattern,
|
||||
background,
|
||||
gradientRotation,
|
||||
patternOpacity);
|
||||
auto blurred = !isPattern
|
||||
? PrepareScaledNonPattern(
|
||||
Data::PrepareBlurredBackground(image),
|
||||
Images::Option(0));
|
||||
Images::Option(0))
|
||||
: QImage();
|
||||
crl::on_main(std::move(guard), [
|
||||
this,
|
||||
image = std::move(image),
|
||||
@@ -758,7 +763,7 @@ void BackgroundPreviewBox::checkLoadedDocument() {
|
||||
};
|
||||
_generating = Data::ReadImageAsync(
|
||||
_media.get(),
|
||||
Window::Theme::ProcessBackgroundImage,
|
||||
Window::Theme::PreprocessBackgroundImage,
|
||||
generateCallback);
|
||||
}
|
||||
|
||||
@@ -766,7 +771,7 @@ bool BackgroundPreviewBox::Start(
|
||||
not_null<Window::SessionController*> controller,
|
||||
const QString &slug,
|
||||
const QMap<QString, QString> ¶ms) {
|
||||
if (const auto paper = Data::WallPaper::FromColorSlug(slug)) {
|
||||
if (const auto paper = Data::WallPaper::FromColorsSlug(slug)) {
|
||||
controller->show(Box<BackgroundPreviewBox>(
|
||||
controller,
|
||||
paper->withUrlParams(params)));
|
||||
|
||||
@@ -56,11 +56,11 @@ private:
|
||||
void radialAnimationCallback(crl::time now);
|
||||
QRect radialRect() const;
|
||||
|
||||
void generateBackground();
|
||||
void checkLoadedDocument();
|
||||
bool setScaledFromThumb();
|
||||
void setScaledFromThumb();
|
||||
void setScaledFromImage(QImage &&image, QImage &&blurred);
|
||||
void updateServiceBg(std::optional<QColor> background);
|
||||
std::optional<QColor> patternBackgroundColor() const;
|
||||
void updateServiceBg(const std::vector<QColor> &bg);
|
||||
void paintImage(Painter &p);
|
||||
void paintRadial(Painter &p);
|
||||
void paintTexts(Painter &p, crl::time ms);
|
||||
@@ -76,7 +76,7 @@ private:
|
||||
Data::WallPaper _paper;
|
||||
std::shared_ptr<Data::DocumentMedia> _media;
|
||||
QImage _full;
|
||||
QPixmap _scaled, _blurred, _fadeOutThumbnail;
|
||||
QPixmap _generated, _scaled, _blurred, _fadeOutThumbnail;
|
||||
Ui::Animations::Simple _fadeIn;
|
||||
Ui::RadialAnimation _radial;
|
||||
base::binary_guard _generating;
|
||||
|
||||
@@ -324,7 +324,7 @@ passcodePadding: margins(0px, 0px, 0px, 5px);
|
||||
passcodeTextLine: 28px;
|
||||
passcodeLittleSkip: 5px;
|
||||
passcodeAboutSkip: 7px;
|
||||
passcodeSkip: 20px;
|
||||
passcodeSkip: 23px;
|
||||
|
||||
newGroupAboutFg: windowSubTextFg;
|
||||
newGroupPadding: margins(4px, 6px, 4px, 3px);
|
||||
@@ -965,3 +965,11 @@ scheduleTimeSeparatorPadding: margins(2px, 0px, 2px, 0px);
|
||||
boxAttentionDividerLabel: FlatLabel(boxDividerLabel) {
|
||||
textFg: boxTextFgError;
|
||||
}
|
||||
|
||||
autolockDateField: InputField(scheduleDateField) {
|
||||
heightMin: 22px;
|
||||
}
|
||||
autolockTimeField: InputField(scheduleTimeField) {
|
||||
heightMin: 20px;
|
||||
}
|
||||
autolockTimeWidth: 52px;
|
||||
|
||||
@@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/text/format_values.h" // Ui::FormatPhone
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/special_fields.h"
|
||||
#include "boxes/confirm_phone_box.h"
|
||||
@@ -21,7 +22,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_user.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "apiwrap.h"
|
||||
#include "app.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
@@ -235,7 +235,7 @@ void ChangePhoneBox::EnterPhone::sendPhoneFail(const MTP::Error &error, const QS
|
||||
tr::lng_change_phone_occupied(
|
||||
tr::now,
|
||||
lt_phone,
|
||||
App::formatPhone(phoneNumber)),
|
||||
Ui::FormatPhone(phoneNumber)),
|
||||
tr::lng_box_ok(tr::now)));
|
||||
} else {
|
||||
showError(Lang::Hard::ServerError());
|
||||
@@ -271,7 +271,7 @@ void ChangePhoneBox::EnterCode::prepare() {
|
||||
auto descriptionText = tr::lng_change_phone_code_description(
|
||||
tr::now,
|
||||
lt_phone,
|
||||
Ui::Text::Bold(App::formatPhone(_phone)),
|
||||
Ui::Text::Bold(Ui::FormatPhone(_phone)),
|
||||
Ui::Text::WithEntities);
|
||||
auto description = object_ptr<Ui::FlatLabel>(this, rpl::single(descriptionText), st::changePhoneLabel);
|
||||
description->moveToLeft(st::boxPadding.left(), 0);
|
||||
|
||||
@@ -41,7 +41,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "main/main_session.h"
|
||||
#include "mtproto/mtproto_config.h"
|
||||
#include "facades.h" // Ui::showChatsList
|
||||
#include "app.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/text/format_values.h" // Ui::FormatPhone
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "core/click_handler_types.h" // UrlClickHandler
|
||||
#include "base/qthelp_url.h" // qthelp::url_encode
|
||||
@@ -18,7 +19,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "main/main_session.h"
|
||||
#include "mainwidget.h"
|
||||
#include "numbers.h"
|
||||
#include "app.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "mtproto/facade.h"
|
||||
#include "styles/style_layers.h"
|
||||
@@ -296,7 +296,7 @@ void ConfirmPhoneBox::prepare() {
|
||||
this,
|
||||
tr::lng_confirm_phone_about(
|
||||
lt_phone,
|
||||
rpl::single(Ui::Text::Bold(App::formatPhone(_phone))),
|
||||
rpl::single(Ui::Text::Bold(Ui::FormatPhone(_phone))),
|
||||
Ui::Text::WithEntities),
|
||||
st::confirmPhoneAboutLabel);
|
||||
|
||||
@@ -347,7 +347,7 @@ void ConfirmPhoneBox::sendCode() {
|
||||
|
||||
void ConfirmPhoneBox::confirmDone(const MTPBool &result) {
|
||||
_sendCodeRequestId = 0;
|
||||
Ui::show(Box<InformBox>(tr::lng_confirm_phone_success(tr::now, lt_phone, App::formatPhone(_phone))));
|
||||
Ui::show(Box<InformBox>(tr::lng_confirm_phone_success(tr::now, lt_phone, Ui::FormatPhone(_phone))));
|
||||
}
|
||||
|
||||
void ConfirmPhoneBox::confirmFail(const MTP::Error &error) {
|
||||
|
||||
@@ -67,10 +67,7 @@ auto ListFromMimeData(not_null<const QMimeData*> data) {
|
||||
if (result.error == Error::None) {
|
||||
return result;
|
||||
} else if (data->hasImage()) {
|
||||
auto image = Platform::GetImageFromClipboard();
|
||||
if (image.isNull()) {
|
||||
image = qvariant_cast<QImage>(data->imageData());
|
||||
}
|
||||
auto image = qvariant_cast<QImage>(data->imageData());
|
||||
if (!image.isNull()) {
|
||||
return Storage::PrepareMediaFromImage(
|
||||
std::move(image),
|
||||
@@ -101,6 +98,11 @@ Ui::AlbumType ComputeAlbumType(not_null<HistoryItem*> item) {
|
||||
return Ui::AlbumType();
|
||||
}
|
||||
|
||||
bool CanBeCompressed(Ui::AlbumType type) {
|
||||
return (type == Ui::AlbumType::None)
|
||||
|| (type == Ui::AlbumType::PhotoVideo);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
EditCaptionBox::EditCaptionBox(
|
||||
@@ -170,7 +172,7 @@ void EditCaptionBox::rebuildPreview() {
|
||||
const auto photo = media->photo();
|
||||
const auto document = media->document();
|
||||
if (photo || document->isVideoFile() || document->isAnimation()) {
|
||||
_isPhoto = true;
|
||||
_isPhoto = (photo != nullptr);
|
||||
const auto media = Ui::CreateChild<Ui::ItemSingleMediaPreview>(
|
||||
this,
|
||||
gifPaused,
|
||||
@@ -230,6 +232,8 @@ void EditCaptionBox::rebuildPreview() {
|
||||
_scroll->setOwnedWidget(
|
||||
object_ptr<Ui::RpWidget>::fromRaw(_content.get()));
|
||||
|
||||
_previewRebuilds.fire({});
|
||||
|
||||
captionResized();
|
||||
}
|
||||
|
||||
@@ -302,10 +306,11 @@ void EditCaptionBox::setupShadows() {
|
||||
}
|
||||
|
||||
void EditCaptionBox::setupControls() {
|
||||
auto hintLabelToggleOn = _isPhoto.value(
|
||||
) | rpl::map([=](bool value) {
|
||||
auto hintLabelToggleOn = _previewRebuilds.events_starting_with(
|
||||
rpl::empty_value()
|
||||
) | rpl::map([=] {
|
||||
return _controller->session().settings().photoEditorHintShown()
|
||||
? value
|
||||
? _isPhoto
|
||||
: false;
|
||||
});
|
||||
|
||||
@@ -327,9 +332,12 @@ void EditCaptionBox::setupControls() {
|
||||
st::defaultBoxCheckbox),
|
||||
st::editMediaCheckboxMargins)
|
||||
)->toggleOn(
|
||||
_isPhoto.value(
|
||||
) | rpl::map([=](bool value) {
|
||||
return value && (_albumType == Ui::AlbumType::None);
|
||||
_previewRebuilds.events_starting_with(
|
||||
rpl::empty_value()
|
||||
) | rpl::map([=] {
|
||||
return _isPhoto
|
||||
&& CanBeCompressed(_albumType)
|
||||
&& !_preparedList.files.empty();
|
||||
}),
|
||||
anim::type::instant
|
||||
)->entity()->checkedChanges(
|
||||
@@ -610,6 +618,7 @@ void EditCaptionBox::resizeEvent(QResizeEvent *e) {
|
||||
_emojiToggle->update();
|
||||
|
||||
if (!_controls->isHidden()) {
|
||||
_controls->resizeToWidth(width());
|
||||
_controls->moveToLeft(
|
||||
st::boxPhotoPadding.left(),
|
||||
bottom - _controls->heightNoMargins());
|
||||
@@ -661,7 +670,7 @@ void EditCaptionBox::save() {
|
||||
|
||||
_controller->session().api().editMedia(
|
||||
std::move(_preparedList),
|
||||
(!_asFile && _isPhoto.current())
|
||||
(!_asFile && _isPhoto && CanBeCompressed(_albumType))
|
||||
? SendMediaType::Photo
|
||||
: SendMediaType::File,
|
||||
_field->getTextWithAppliedMarkdown(),
|
||||
|
||||
@@ -74,14 +74,14 @@ private:
|
||||
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
const not_null<HistoryItem*> _historyItem;
|
||||
const bool _isAllowedEditMedia = false;
|
||||
const bool _isAllowedEditMedia;
|
||||
const Ui::AlbumType _albumType;
|
||||
|
||||
const base::unique_qptr<Ui::VerticalLayout> _controls;
|
||||
const base::unique_qptr<Ui::ScrollArea> _scroll;
|
||||
const base::unique_qptr<Ui::InputField> _field;
|
||||
const base::unique_qptr<Ui::EmojiButton> _emojiToggle;
|
||||
const base::unique_qptr<Ui::FadeShadow> _topShadow,_bottomShadow;
|
||||
const base::unique_qptr<Ui::FadeShadow> _topShadow, _bottomShadow;
|
||||
|
||||
base::unique_qptr<Ui::AbstractSinglePreview> _content;
|
||||
base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel;
|
||||
@@ -93,15 +93,16 @@ private:
|
||||
|
||||
mtpRequestId _saveRequestId = 0;
|
||||
|
||||
bool _isPhoto = false;
|
||||
bool _asFile = false;
|
||||
|
||||
QString _error;
|
||||
|
||||
rpl::variable<bool> _isPhoto = false;
|
||||
rpl::variable<int> _footerHeight = 0;
|
||||
|
||||
rpl::event_stream<> _editMediaClicks;
|
||||
rpl::event_stream<> _photoEditorOpens;
|
||||
rpl::event_stream<> _previewRebuilds;
|
||||
rpl::event_stream<int> _contentHeight;
|
||||
|
||||
};
|
||||
|
||||
@@ -170,63 +170,6 @@ void EditPrivacyBox::editExceptions(
|
||||
Ui::LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
QVector<MTPInputPrivacyRule> EditPrivacyBox::collectResult() {
|
||||
const auto collectInputUsers = [](const auto &peers) {
|
||||
auto result = QVector<MTPInputUser>();
|
||||
result.reserve(peers.size());
|
||||
for (const auto peer : peers) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
result.push_back(user->inputUser);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
const auto collectInputChats = [](const auto &peers) {
|
||||
auto result = QVector<MTPint>(); // #TODO ids
|
||||
result.reserve(peers.size());
|
||||
for (const auto peer : peers) {
|
||||
if (!peer->isUser()) {
|
||||
result.push_back(peerToBareMTPInt(peer->id));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
constexpr auto kMaxRules = 3; // allow users, disallow users, option
|
||||
auto result = QVector<MTPInputPrivacyRule>();
|
||||
result.reserve(kMaxRules);
|
||||
if (showExceptionLink(Exception::Always)) {
|
||||
const auto users = collectInputUsers(_value.always);
|
||||
const auto chats = collectInputChats(_value.always);
|
||||
if (!users.empty()) {
|
||||
result.push_back(MTP_inputPrivacyValueAllowUsers(MTP_vector<MTPInputUser>(users)));
|
||||
}
|
||||
if (!chats.empty()) {
|
||||
result.push_back(MTP_inputPrivacyValueAllowChatParticipants(MTP_vector<MTPint>(chats)));
|
||||
}
|
||||
}
|
||||
if (showExceptionLink(Exception::Never)) {
|
||||
const auto users = collectInputUsers(_value.never);
|
||||
const auto chats = collectInputChats(_value.never);
|
||||
if (!users.empty()) {
|
||||
result.push_back(MTP_inputPrivacyValueDisallowUsers(MTP_vector<MTPInputUser>(users)));
|
||||
}
|
||||
if (!chats.empty()) {
|
||||
result.push_back(MTP_inputPrivacyValueDisallowChatParticipants(MTP_vector<MTPint>(chats)));
|
||||
}
|
||||
}
|
||||
result.push_back([&] {
|
||||
switch (_value.option) {
|
||||
case Option::Everyone: return MTP_inputPrivacyValueAllowAll();
|
||||
case Option::Contacts: return MTP_inputPrivacyValueAllowContacts();
|
||||
case Option::Nobody: return MTP_inputPrivacyValueDisallowAll();
|
||||
}
|
||||
Unexpected("Option value in EditPrivacyBox::collectResult.");
|
||||
}());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<not_null<PeerData*>> &EditPrivacyBox::exceptions(Exception exception) {
|
||||
switch (exception) {
|
||||
case Exception::Always: return _value.always;
|
||||
@@ -379,10 +322,13 @@ void EditPrivacyBox::setupContent() {
|
||||
const auto someAreDisallowed = (_value.option != Option::Everyone)
|
||||
|| !_value.never.empty();
|
||||
_controller->confirmSave(someAreDisallowed, crl::guard(this, [=] {
|
||||
_value.ignoreAlways = !showExceptionLink(Exception::Always);
|
||||
_value.ignoreNever = !showExceptionLink(Exception::Never);
|
||||
|
||||
_controller->saveAdditional();
|
||||
_window->session().api().savePrivacy(
|
||||
_controller->apiKey(),
|
||||
collectResult());
|
||||
_window->session().api().userPrivacy().save(
|
||||
_controller->key(),
|
||||
_value);
|
||||
closeBox();
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_user_privacy.h"
|
||||
|
||||
namespace Ui {
|
||||
class VerticalLayout;
|
||||
@@ -31,15 +31,14 @@ class EditPrivacyBox;
|
||||
|
||||
class EditPrivacyController {
|
||||
public:
|
||||
using Key = ApiWrap::Privacy::Key;
|
||||
using Option = ApiWrap::Privacy::Option;
|
||||
using Key = Api::UserPrivacy::Key;
|
||||
using Option = Api::UserPrivacy::Option;
|
||||
enum class Exception {
|
||||
Always,
|
||||
Never,
|
||||
};
|
||||
|
||||
[[nodiscard]] virtual Key key() = 0;
|
||||
[[nodiscard]] virtual MTPInputPrivacyKey apiKey() = 0;
|
||||
|
||||
[[nodiscard]] virtual rpl::producer<QString> title() = 0;
|
||||
[[nodiscard]] virtual bool hasOption(Option option) {
|
||||
@@ -102,8 +101,8 @@ private:
|
||||
|
||||
class EditPrivacyBox : public Ui::BoxContent {
|
||||
public:
|
||||
using Value = ApiWrap::Privacy;
|
||||
using Option = Value::Option;
|
||||
using Value = Api::UserPrivacy::Rule;
|
||||
using Option = Api::UserPrivacy::Option;
|
||||
using Exception = EditPrivacyController::Exception;
|
||||
|
||||
EditPrivacyBox(
|
||||
@@ -124,7 +123,6 @@ protected:
|
||||
private:
|
||||
bool showExceptionLink(Exception exception) const;
|
||||
void setupContent();
|
||||
QVector<MTPInputPrivacyRule> collectResult();
|
||||
|
||||
Ui::FlatLabel *addLabel(
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
|
||||
@@ -115,12 +115,12 @@ private:
|
||||
const Rows::Row &rowBySelection(Selection selected) const;
|
||||
std::unique_ptr<Ui::RippleAnimation> &rippleBySelection(
|
||||
Selection selected);
|
||||
const std::unique_ptr<Ui::RippleAnimation> &rippleBySelection(
|
||||
[[maybe_unused]] const std::unique_ptr<Ui::RippleAnimation> &rippleBySelection(
|
||||
Selection selected) const;
|
||||
std::unique_ptr<Ui::RippleAnimation> &rippleBySelection(
|
||||
not_null<Row*> row,
|
||||
Selection selected);
|
||||
const std::unique_ptr<Ui::RippleAnimation> &rippleBySelection(
|
||||
[[maybe_unused]] const std::unique_ptr<Ui::RippleAnimation> &rippleBySelection(
|
||||
not_null<const Row*> row,
|
||||
Selection selected) const;
|
||||
void addRipple(Selection selected, QPoint position);
|
||||
|
||||
@@ -14,7 +14,6 @@ Copyright (C) 2017, Nicholas Guriev <guriev-ns@ya.ru>
|
||||
#include "ui/special_buttons.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "app.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
|
||||
@@ -11,8 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "lang/lang_keys.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "boxes/confirm_phone_box.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "mainwindow.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_cloud_password.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_domain.h"
|
||||
#include "core/application.h"
|
||||
@@ -42,7 +44,7 @@ enum class PasswordErrorType {
|
||||
void SetCloudPassword(
|
||||
not_null<Ui::GenericBox*> box,
|
||||
not_null<Main::Session*> session) {
|
||||
session->api().passwordState(
|
||||
session->api().cloudPassword().state(
|
||||
) | rpl::start_with_next([=] {
|
||||
using namespace Settings;
|
||||
const auto weak = Ui::MakeWeak(box);
|
||||
@@ -95,6 +97,60 @@ void TransferPasswordError(
|
||||
}
|
||||
}
|
||||
|
||||
void StartPendingReset(
|
||||
not_null<Main::Session*> session,
|
||||
not_null<Ui::BoxContent*> context,
|
||||
Fn<void()> close) {
|
||||
const auto weak = Ui::MakeWeak(context.get());
|
||||
auto lifetime = std::make_shared<rpl::lifetime>();
|
||||
|
||||
auto finish = [=](const QString &message) mutable {
|
||||
if (const auto strong = weak.data()) {
|
||||
if (!message.isEmpty()) {
|
||||
strong->getDelegate()->show(Box<InformBox>(message));
|
||||
}
|
||||
strong->closeBox();
|
||||
}
|
||||
close();
|
||||
if (lifetime) {
|
||||
base::take(lifetime)->destroy();
|
||||
}
|
||||
};
|
||||
|
||||
session->api().cloudPassword().resetPassword(
|
||||
) | rpl::start_with_next_error_done([=](
|
||||
Api::CloudPassword::ResetRetryDate retryDate) {
|
||||
constexpr auto kMinute = 60;
|
||||
constexpr auto kHour = 3600;
|
||||
constexpr auto kDay = 86400;
|
||||
const auto left = std::max(
|
||||
retryDate - base::unixtime::now(),
|
||||
kMinute);
|
||||
const auto days = (left / kDay);
|
||||
const auto hours = (left / kHour);
|
||||
const auto minutes = (left / kMinute);
|
||||
const auto duration = days
|
||||
? tr::lng_group_call_duration_days(tr::now, lt_count, days)
|
||||
: hours
|
||||
? tr::lng_group_call_duration_hours(tr::now, lt_count, hours)
|
||||
: tr::lng_group_call_duration_minutes(
|
||||
tr::now,
|
||||
lt_count,
|
||||
minutes);
|
||||
if (const auto strong = weak.data()) {
|
||||
strong->getDelegate()->show(Box<InformBox>(
|
||||
tr::lng_cloud_password_reset_later(
|
||||
tr::now,
|
||||
lt_duration,
|
||||
duration)));
|
||||
}
|
||||
}, [=](const QString &error) mutable {
|
||||
finish("Error: " + error);
|
||||
}, [=]() mutable {
|
||||
finish({});
|
||||
}, *lifetime);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
PasscodeBox::CloudFields PasscodeBox::CloudFields::From(
|
||||
@@ -106,6 +162,7 @@ PasscodeBox::CloudFields PasscodeBox::CloudFields::From(
|
||||
result.hasRecovery = current.hasRecovery;
|
||||
result.notEmptyPassport = current.notEmptyPassport;
|
||||
result.hint = current.hint;
|
||||
result.pendingResetDate = current.pendingResetDate;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -132,20 +189,33 @@ PasscodeBox::PasscodeBox(
|
||||
|
||||
PasscodeBox::PasscodeBox(
|
||||
QWidget*,
|
||||
not_null<Main::Session*> session,
|
||||
not_null<MTP::Instance*> mtp,
|
||||
Main::Session *session,
|
||||
const CloudFields &fields)
|
||||
: _session(session)
|
||||
, _api(&_session->mtp())
|
||||
, _api(mtp)
|
||||
, _turningOff(fields.turningOff)
|
||||
, _cloudPwd(true)
|
||||
, _cloudFields(fields)
|
||||
, _about(st::boxWidth - st::boxPadding.left() * 1.5)
|
||||
, _oldPasscode(this, st::defaultInputField, tr::lng_cloud_password_enter_old())
|
||||
, _newPasscode(this, st::defaultInputField, fields.curRequest ? tr::lng_cloud_password_enter_new() : tr::lng_cloud_password_enter_first())
|
||||
, _newPasscode(
|
||||
this,
|
||||
st::defaultInputField,
|
||||
(fields.curRequest
|
||||
? tr::lng_cloud_password_enter_new()
|
||||
: tr::lng_cloud_password_enter_first()))
|
||||
, _reenterPasscode(this, st::defaultInputField, tr::lng_cloud_password_confirm_new())
|
||||
, _passwordHint(this, st::defaultInputField, fields.curRequest ? tr::lng_cloud_password_change_hint() : tr::lng_cloud_password_hint())
|
||||
, _passwordHint(
|
||||
this,
|
||||
st::defaultInputField,
|
||||
(fields.curRequest
|
||||
? tr::lng_cloud_password_change_hint()
|
||||
: tr::lng_cloud_password_hint()))
|
||||
, _recoverEmail(this, st::defaultInputField, tr::lng_cloud_password_email())
|
||||
, _recover(this, tr::lng_signin_recover(tr::now)) {
|
||||
, _recover(this, tr::lng_signin_recover(tr::now))
|
||||
, _showRecoverLink(_cloudFields.hasRecovery || !_cloudFields.pendingResetDate) {
|
||||
Expects(session != nullptr || !fields.fromRecoveryCode.isEmpty());
|
||||
Expects(!_turningOff || _cloudFields.curRequest);
|
||||
|
||||
if (!_cloudFields.hint.isEmpty()) {
|
||||
@@ -155,6 +225,13 @@ PasscodeBox::PasscodeBox(
|
||||
}
|
||||
}
|
||||
|
||||
PasscodeBox::PasscodeBox(
|
||||
QWidget*,
|
||||
not_null<Main::Session*> session,
|
||||
const CloudFields &fields)
|
||||
: PasscodeBox(nullptr, &session->mtp(), session, fields) {
|
||||
}
|
||||
|
||||
rpl::producer<QByteArray> PasscodeBox::newPasswordSet() const {
|
||||
return _newPasswordSet.events();
|
||||
}
|
||||
@@ -167,6 +244,10 @@ rpl::producer<> PasscodeBox::clearUnconfirmedPassword() const {
|
||||
return _clearUnconfirmedPassword.events();
|
||||
}
|
||||
|
||||
rpl::producer<MTPauth_Authorization> PasscodeBox::newAuthorization() const {
|
||||
return _newAuthorization.events();
|
||||
}
|
||||
|
||||
bool PasscodeBox::currentlyHave() const {
|
||||
return _cloudPwd
|
||||
? (!!_cloudFields.curRequest)
|
||||
@@ -203,20 +284,22 @@ void PasscodeBox::prepare() {
|
||||
: _cloudPwd
|
||||
? tr::lng_cloud_password_remove()
|
||||
: tr::lng_passcode_remove());
|
||||
setDimensions(st::boxWidth, st::passcodePadding.top() + _oldPasscode->height() + st::passcodeTextLine + ((_cloudFields.hasRecovery && !_hintText.isEmpty()) ? st::passcodeTextLine : 0) + st::passcodeAboutSkip + _aboutHeight + st::passcodePadding.bottom());
|
||||
setDimensions(st::boxWidth, st::passcodePadding.top() + _oldPasscode->height() + st::passcodeTextLine + ((_showRecoverLink && !_hintText.isEmpty()) ? st::passcodeTextLine : 0) + st::passcodeAboutSkip + _aboutHeight + st::passcodePadding.bottom());
|
||||
} else {
|
||||
if (currentlyHave()) {
|
||||
_oldPasscode->show();
|
||||
setTitle(_cloudPwd
|
||||
? tr::lng_cloud_password_change()
|
||||
: tr::lng_passcode_change());
|
||||
setDimensions(st::boxWidth, st::passcodePadding.top() + _oldPasscode->height() + st::passcodeTextLine + ((_cloudFields.hasRecovery && !_hintText.isEmpty()) ? st::passcodeTextLine : 0) + _newPasscode->height() + st::passcodeLittleSkip + _reenterPasscode->height() + st::passcodeSkip + (_cloudPwd ? _passwordHint->height() + st::passcodeLittleSkip : 0) + st::passcodeAboutSkip + _aboutHeight + st::passcodePadding.bottom());
|
||||
setDimensions(st::boxWidth, st::passcodePadding.top() + _oldPasscode->height() + st::passcodeTextLine + ((_showRecoverLink && !_hintText.isEmpty()) ? st::passcodeTextLine : 0) + _newPasscode->height() + st::passcodeLittleSkip + _reenterPasscode->height() + st::passcodeSkip + (_cloudPwd ? _passwordHint->height() + st::passcodeLittleSkip : 0) + st::passcodeAboutSkip + _aboutHeight + st::passcodePadding.bottom());
|
||||
} else {
|
||||
_oldPasscode->hide();
|
||||
setTitle(_cloudPwd
|
||||
? tr::lng_cloud_password_create()
|
||||
? (_cloudFields.fromRecoveryCode.isEmpty()
|
||||
? tr::lng_cloud_password_create()
|
||||
: tr::lng_cloud_password_change())
|
||||
: tr::lng_passcode_create());
|
||||
setDimensions(st::boxWidth, st::passcodePadding.top() + _newPasscode->height() + st::passcodeLittleSkip + _reenterPasscode->height() + st::passcodeSkip + (_cloudPwd ? _passwordHint->height() + st::passcodeLittleSkip : 0) + st::passcodeAboutSkip + _aboutHeight + (_cloudPwd ? (st::passcodeLittleSkip + _recoverEmail->height() + st::passcodeSkip) : st::passcodePadding.bottom()));
|
||||
setDimensions(st::boxWidth, st::passcodePadding.top() + _newPasscode->height() + st::passcodeLittleSkip + _reenterPasscode->height() + st::passcodeSkip + (_cloudPwd ? _passwordHint->height() + st::passcodeLittleSkip : 0) + st::passcodeAboutSkip + _aboutHeight + ((_cloudPwd && _cloudFields.fromRecoveryCode.isEmpty()) ? (st::passcodeLittleSkip + _recoverEmail->height() + st::passcodeSkip) : st::passcodePadding.bottom()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,11 +320,16 @@ void PasscodeBox::prepare() {
|
||||
|
||||
const auto has = currentlyHave();
|
||||
_oldPasscode->setVisible(onlyCheck || has);
|
||||
_recover->setVisible((onlyCheck || has) && _cloudPwd && _cloudFields.hasRecovery);
|
||||
_recover->setVisible((onlyCheck || has)
|
||||
&& _cloudPwd
|
||||
&& _showRecoverLink);
|
||||
_newPasscode->setVisible(!onlyCheck);
|
||||
_reenterPasscode->setVisible(!onlyCheck);
|
||||
_passwordHint->setVisible(!onlyCheck && _cloudPwd);
|
||||
_recoverEmail->setVisible(!onlyCheck && _cloudPwd && !has);
|
||||
_recoverEmail->setVisible(!onlyCheck
|
||||
&& _cloudPwd
|
||||
&& !has
|
||||
&& _cloudFields.fromRecoveryCode.isEmpty());
|
||||
}
|
||||
|
||||
void PasscodeBox::submit() {
|
||||
@@ -285,7 +373,7 @@ void PasscodeBox::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
int32 w = st::boxWidth - st::boxPadding.left() * 1.5;
|
||||
int32 abouty = (_passwordHint->isHidden() ? ((_reenterPasscode->isHidden() ? (_oldPasscode->y() + (_cloudFields.hasRecovery && !_hintText.isEmpty() ? st::passcodeTextLine : 0)) : _reenterPasscode->y()) + st::passcodeSkip) : _passwordHint->y()) + _oldPasscode->height() + st::passcodeLittleSkip + st::passcodeAboutSkip;
|
||||
int32 abouty = (_passwordHint->isHidden() ? ((_reenterPasscode->isHidden() ? (_oldPasscode->y() + (_showRecoverLink && !_hintText.isEmpty() ? st::passcodeTextLine : 0)) : _reenterPasscode->y()) + st::passcodeSkip) : _passwordHint->y()) + _oldPasscode->height() + st::passcodeLittleSkip + st::passcodeAboutSkip;
|
||||
p.setPen(st::boxTextFg);
|
||||
_about.drawLeft(p, st::boxPadding.left(), abouty, w, width());
|
||||
|
||||
@@ -317,7 +405,7 @@ void PasscodeBox::resizeEvent(QResizeEvent *e) {
|
||||
_oldPasscode->resize(w, _oldPasscode->height());
|
||||
_oldPasscode->moveToLeft(st::boxPadding.left(), st::passcodePadding.top());
|
||||
_newPasscode->resize(w, _newPasscode->height());
|
||||
_newPasscode->moveToLeft(st::boxPadding.left(), _oldPasscode->y() + ((_turningOff || has) ? (_oldPasscode->height() + st::passcodeTextLine + ((_cloudFields.hasRecovery && !_hintText.isEmpty()) ? st::passcodeTextLine : 0)) : 0));
|
||||
_newPasscode->moveToLeft(st::boxPadding.left(), _oldPasscode->y() + ((_turningOff || has) ? (_oldPasscode->height() + st::passcodeTextLine + ((_showRecoverLink && !_hintText.isEmpty()) ? st::passcodeTextLine : 0)) : 0));
|
||||
_reenterPasscode->resize(w, _reenterPasscode->height());
|
||||
_reenterPasscode->moveToLeft(st::boxPadding.left(), _newPasscode->y() + _newPasscode->height() + st::passcodeLittleSkip);
|
||||
_passwordHint->resize(w, _passwordHint->height());
|
||||
@@ -340,21 +428,44 @@ void PasscodeBox::setInnerFocus() {
|
||||
}
|
||||
}
|
||||
|
||||
void PasscodeBox::recoverPasswordDone(
|
||||
const QByteArray &newPasswordBytes,
|
||||
const MTPauth_Authorization &result) {
|
||||
if (_replacedBy) {
|
||||
_replacedBy->closeBox();
|
||||
}
|
||||
_setRequest = 0;
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
_newAuthorization.fire_copy(result);
|
||||
if (weak) {
|
||||
_newPasswordSet.fire_copy(newPasswordBytes);
|
||||
if (weak) {
|
||||
getDelegate()->show(Box<InformBox>(
|
||||
tr::lng_cloud_password_updated(tr::now)));
|
||||
if (weak) {
|
||||
closeBox();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PasscodeBox::setPasswordDone(const QByteArray &newPasswordBytes) {
|
||||
if (_replacedBy) {
|
||||
_replacedBy->closeBox();
|
||||
}
|
||||
_setRequest = 0;
|
||||
_newPasswordSet.fire_copy(newPasswordBytes);
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
const auto text = _reenterPasscode->isHidden()
|
||||
? tr::lng_cloud_password_removed(tr::now)
|
||||
: _oldPasscode->isHidden()
|
||||
? tr::lng_cloud_password_was_set(tr::now)
|
||||
: tr::lng_cloud_password_updated(tr::now);
|
||||
getDelegate()->show(Box<InformBox>(text));
|
||||
_newPasswordSet.fire_copy(newPasswordBytes);
|
||||
if (weak) {
|
||||
closeBox();
|
||||
const auto text = _reenterPasscode->isHidden()
|
||||
? tr::lng_cloud_password_removed(tr::now)
|
||||
: _oldPasscode->isHidden()
|
||||
? tr::lng_cloud_password_was_set(tr::now)
|
||||
: tr::lng_cloud_password_updated(tr::now);
|
||||
getDelegate()->show(Box<InformBox>(text));
|
||||
if (weak) {
|
||||
closeBox();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,7 +490,7 @@ void PasscodeBox::setPasswordFail(const QString &type) {
|
||||
_oldPasscode->setFocus();
|
||||
_oldPasscode->showError();
|
||||
_oldError = tr::lng_flood_error(tr::now);
|
||||
if (_cloudFields.hasRecovery && _hintText.isEmpty()) {
|
||||
if (_showRecoverLink && _hintText.isEmpty()) {
|
||||
_recover->hide();
|
||||
}
|
||||
update();
|
||||
@@ -739,25 +850,44 @@ void PasscodeBox::setNewCloudPassword(const QString &newPassword) {
|
||||
}
|
||||
const auto hint = _passwordHint->getLastText();
|
||||
const auto email = _recoverEmail->getLastText().trimmed();
|
||||
const auto flags = MTPDaccount_passwordInputSettings::Flag::f_new_algo
|
||||
| MTPDaccount_passwordInputSettings::Flag::f_new_password_hash
|
||||
| MTPDaccount_passwordInputSettings::Flag::f_hint
|
||||
| MTPDaccount_passwordInputSettings::Flag::f_email;
|
||||
using Flag = MTPDaccount_passwordInputSettings::Flag;
|
||||
const auto flags = Flag::f_new_algo
|
||||
| Flag::f_new_password_hash
|
||||
| Flag::f_hint
|
||||
| (_cloudFields.fromRecoveryCode.isEmpty() ? Flag::f_email : Flag(0));
|
||||
_checkPasswordCallback = nullptr;
|
||||
_setRequest = _api.request(MTPaccount_UpdatePasswordSettings(
|
||||
MTP_inputCheckPasswordEmpty(),
|
||||
MTP_account_passwordInputSettings(
|
||||
MTP_flags(flags),
|
||||
Core::PrepareCloudPasswordAlgo(_cloudFields.newAlgo),
|
||||
MTP_bytes(newPasswordHash.modpow),
|
||||
MTP_string(hint),
|
||||
MTP_string(email),
|
||||
MTPSecureSecretSettings())
|
||||
)).done([=](const MTPBool &result) {
|
||||
setPasswordDone(newPasswordBytes);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
setPasswordFail(newPasswordBytes, email, error);
|
||||
}).handleFloodErrors().send();
|
||||
|
||||
const auto settings = MTP_account_passwordInputSettings(
|
||||
MTP_flags(flags),
|
||||
Core::PrepareCloudPasswordAlgo(_cloudFields.newAlgo),
|
||||
MTP_bytes(newPasswordHash.modpow),
|
||||
MTP_string(hint),
|
||||
MTP_string(email),
|
||||
MTPSecureSecretSettings());
|
||||
if (_cloudFields.fromRecoveryCode.isEmpty()) {
|
||||
_setRequest = _api.request(MTPaccount_UpdatePasswordSettings(
|
||||
MTP_inputCheckPasswordEmpty(),
|
||||
settings
|
||||
)).done([=](const MTPBool &result) {
|
||||
setPasswordDone(newPasswordBytes);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
setPasswordFail(newPasswordBytes, email, error);
|
||||
}).handleFloodErrors().send();
|
||||
} else {
|
||||
_setRequest = _api.request(MTPauth_RecoverPassword(
|
||||
MTP_flags(MTPauth_RecoverPassword::Flag::f_new_settings),
|
||||
MTP_string(_cloudFields.fromRecoveryCode),
|
||||
settings
|
||||
)).done([=](const MTPauth_Authorization &result) {
|
||||
recoverPasswordDone(newPasswordBytes, result);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
if (MTP::IsFloodError(error)) {
|
||||
_newError = tr::lng_flood_error(tr::now);
|
||||
update();
|
||||
}
|
||||
setPasswordFail(newPasswordBytes, email, error);
|
||||
}).handleFloodErrors().send();
|
||||
}
|
||||
}
|
||||
|
||||
void PasscodeBox::changeCloudPassword(
|
||||
@@ -913,7 +1043,7 @@ void PasscodeBox::badOldPasscode() {
|
||||
_oldError = _cloudPwd
|
||||
? tr::lng_cloud_password_wrong(tr::now)
|
||||
: tr::lng_passcode_wrong(tr::now);
|
||||
if (_cloudFields.hasRecovery && _hintText.isEmpty()) {
|
||||
if (_showRecoverLink && _hintText.isEmpty()) {
|
||||
_recover->hide();
|
||||
}
|
||||
update();
|
||||
@@ -922,7 +1052,7 @@ void PasscodeBox::badOldPasscode() {
|
||||
void PasscodeBox::oldChanged() {
|
||||
if (!_oldError.isEmpty()) {
|
||||
_oldError = QString();
|
||||
if (_cloudFields.hasRecovery && _hintText.isEmpty()) {
|
||||
if (_showRecoverLink && _hintText.isEmpty()) {
|
||||
_recover->show();
|
||||
}
|
||||
update();
|
||||
@@ -944,7 +1074,22 @@ void PasscodeBox::emailChanged() {
|
||||
}
|
||||
|
||||
void PasscodeBox::recoverByEmail() {
|
||||
if (_pattern.isEmpty()) {
|
||||
if (!_cloudFields.hasRecovery) {
|
||||
Assert(_session != nullptr);
|
||||
const auto session = _session;
|
||||
const auto confirmBox = std::make_shared<QPointer<BoxContent>>();
|
||||
const auto reset = crl::guard(this, [=] {
|
||||
StartPendingReset(session, this, [=] {
|
||||
if (const auto box = *confirmBox) {
|
||||
box->closeBox();
|
||||
}
|
||||
});
|
||||
});
|
||||
*confirmBox = getDelegate()->show(Box<ConfirmBox>(
|
||||
tr::lng_cloud_password_reset_no_email(tr::now),
|
||||
tr::lng_cloud_password_reset_ok(tr::now),
|
||||
reset));
|
||||
} else if (_pattern.isEmpty()) {
|
||||
_pattern = "-";
|
||||
_api.request(MTPauth_RequestPasswordRecovery(
|
||||
)).done([=](const MTPauth_PasswordRecovery &result) {
|
||||
@@ -962,16 +1107,19 @@ void PasscodeBox::recoverExpired() {
|
||||
}
|
||||
|
||||
void PasscodeBox::recover() {
|
||||
if (_pattern == "-") return;
|
||||
if (_pattern == "-" || !_session) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
const auto box = getDelegate()->show(Box<RecoverBox>(
|
||||
&_api.instance(),
|
||||
_session,
|
||||
_pattern,
|
||||
_cloudFields.notEmptyPassport));
|
||||
_cloudFields,
|
||||
[weak] { if (weak) { weak->closeBox(); } }));
|
||||
|
||||
box->passwordCleared(
|
||||
) | rpl::map_to(
|
||||
QByteArray()
|
||||
box->newPasswordSet(
|
||||
) | rpl::start_to_stream(_newPasswordSet, lifetime());
|
||||
|
||||
box->recoveryExpired(
|
||||
@@ -994,17 +1142,44 @@ void PasscodeBox::recoverStartFail(const MTP::Error &error) {
|
||||
|
||||
RecoverBox::RecoverBox(
|
||||
QWidget*,
|
||||
not_null<Main::Session*> session,
|
||||
not_null<MTP::Instance*> mtp,
|
||||
Main::Session *session,
|
||||
const QString &pattern,
|
||||
bool notEmptyPassport)
|
||||
: _api(&session->mtp())
|
||||
const PasscodeBox::CloudFields &fields,
|
||||
Fn<void()> closeParent)
|
||||
: _session(session)
|
||||
, _api(mtp)
|
||||
, _pattern(st::normalFont->elided(tr::lng_signin_recover_hint(tr::now, lt_recover_email, pattern), st::boxWidth - st::boxPadding.left() * 1.5))
|
||||
, _notEmptyPassport(notEmptyPassport)
|
||||
, _recoverCode(this, st::defaultInputField, tr::lng_signin_code()) {
|
||||
, _cloudFields(fields)
|
||||
, _recoverCode(this, st::defaultInputField, tr::lng_signin_code())
|
||||
, _noEmailAccess(this, tr::lng_signin_try_password(tr::now))
|
||||
, _closeParent(std::move(closeParent)) {
|
||||
if (_cloudFields.pendingResetDate != 0 || !session) {
|
||||
_noEmailAccess.destroy();
|
||||
} else {
|
||||
_noEmailAccess->setClickedCallback([=] {
|
||||
const auto confirmBox = std::make_shared<QPointer<BoxContent>>();
|
||||
const auto reset = crl::guard(this, [=] {
|
||||
const auto closeParent = _closeParent;
|
||||
StartPendingReset(session, this, [=] {
|
||||
if (closeParent) {
|
||||
closeParent();
|
||||
}
|
||||
if (const auto box = *confirmBox) {
|
||||
box->closeBox();
|
||||
}
|
||||
});
|
||||
});
|
||||
*confirmBox = getDelegate()->show(Box<ConfirmBox>(
|
||||
tr::lng_cloud_password_reset_with_email(tr::now),
|
||||
tr::lng_cloud_password_reset_ok(tr::now),
|
||||
reset));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
rpl::producer<> RecoverBox::passwordCleared() const {
|
||||
return _passwordCleared.events();
|
||||
rpl::producer<QByteArray> RecoverBox::newPasswordSet() const {
|
||||
return _newPasswordSet.events();
|
||||
}
|
||||
|
||||
rpl::producer<> RecoverBox::recoveryExpired() const {
|
||||
@@ -1017,7 +1192,13 @@ void RecoverBox::prepare() {
|
||||
addButton(tr::lng_passcode_submit(), [=] { submit(); });
|
||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||
|
||||
setDimensions(st::boxWidth, st::passcodePadding.top() + st::passcodePadding.bottom() + st::passcodeTextLine + _recoverCode->height() + st::passcodeTextLine);
|
||||
setDimensions(
|
||||
st::boxWidth,
|
||||
(st::passcodePadding.top()
|
||||
+ st::passcodePadding.bottom()
|
||||
+ st::passcodeTextLine
|
||||
+ _recoverCode->height()
|
||||
+ st::passcodeTextLine));
|
||||
|
||||
connect(_recoverCode, &Ui::InputField::changed, [=] { codeChanged(); });
|
||||
connect(_recoverCode, &Ui::InputField::submitted, [=] { submit(); });
|
||||
@@ -1044,6 +1225,9 @@ void RecoverBox::resizeEvent(QResizeEvent *e) {
|
||||
|
||||
_recoverCode->resize(st::boxWidth - st::boxPadding.left() - st::boxPadding.right(), _recoverCode->height());
|
||||
_recoverCode->moveToLeft(st::boxPadding.left(), st::passcodePadding.top() + st::passcodePadding.bottom() + st::passcodeTextLine);
|
||||
if (_noEmailAccess) {
|
||||
_noEmailAccess->moveToLeft(st::boxPadding.left(), _recoverCode->y() + _recoverCode->height() + (st::passcodeTextLine - _noEmailAccess->height()) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
void RecoverBox::setInnerFocus() {
|
||||
@@ -1061,17 +1245,29 @@ void RecoverBox::submit() {
|
||||
}
|
||||
|
||||
const auto send = crl::guard(this, [=] {
|
||||
_submitRequest = _api.request(MTPauth_RecoverPassword(
|
||||
MTP_flags(0),
|
||||
MTP_string(code),
|
||||
MTPaccount_PasswordInputSettings()
|
||||
)).done([=](const MTPauth_Authorization &result) {
|
||||
codeSubmitDone(result);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
codeSubmitFail(error);
|
||||
}).handleFloodErrors().send();
|
||||
if (_cloudFields.turningOff) {
|
||||
// From "Disable cloud password".
|
||||
_submitRequest = _api.request(MTPauth_RecoverPassword(
|
||||
MTP_flags(0),
|
||||
MTP_string(code),
|
||||
MTPaccount_PasswordInputSettings()
|
||||
)).done([=](const MTPauth_Authorization &result) {
|
||||
proceedToClear();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
checkSubmitFail(error);
|
||||
}).handleFloodErrors().send();
|
||||
} else {
|
||||
// From "Change cloud password".
|
||||
_submitRequest = _api.request(MTPauth_CheckRecoveryPassword(
|
||||
MTP_string(code)
|
||||
)).done([=](const MTPBool &result) {
|
||||
proceedToChange(code);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
checkSubmitFail(error);
|
||||
}).handleFloodErrors().send();
|
||||
}
|
||||
});
|
||||
if (_notEmptyPassport) {
|
||||
if (_cloudFields.notEmptyPassport) {
|
||||
const auto confirmed = [=](Fn<void()> &&close) {
|
||||
send();
|
||||
close();
|
||||
@@ -1085,25 +1281,61 @@ void RecoverBox::submit() {
|
||||
}
|
||||
}
|
||||
|
||||
void RecoverBox::codeChanged() {
|
||||
_error = QString();
|
||||
void RecoverBox::setError(const QString &error) {
|
||||
_error = error;
|
||||
if (_noEmailAccess) {
|
||||
_noEmailAccess->setVisible(error.isEmpty());
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void RecoverBox::codeSubmitDone(const MTPauth_Authorization &result) {
|
||||
_submitRequest = 0;
|
||||
void RecoverBox::codeChanged() {
|
||||
setError(QString());
|
||||
}
|
||||
|
||||
_passwordCleared.fire({});
|
||||
void RecoverBox::proceedToClear() {
|
||||
_submitRequest = 0;
|
||||
_newPasswordSet.fire({});
|
||||
getDelegate()->show(
|
||||
Box<InformBox>(tr::lng_cloud_password_removed(tr::now)),
|
||||
Ui::LayerOption::CloseOther);
|
||||
}
|
||||
|
||||
void RecoverBox::codeSubmitFail(const MTP::Error &error) {
|
||||
void RecoverBox::proceedToChange(const QString &code) {
|
||||
Expects(!_cloudFields.turningOff);
|
||||
_submitRequest = 0;
|
||||
|
||||
auto fields = _cloudFields;
|
||||
fields.fromRecoveryCode = code;
|
||||
fields.hasRecovery = false;
|
||||
// we could've been turning off, no need to force new password then
|
||||
// like if (_cloudFields.turningOff) { just RecoverPassword else Check }
|
||||
fields.curRequest = {};
|
||||
auto box = Box<PasscodeBox>(_session, fields);
|
||||
|
||||
box->boxClosing(
|
||||
) | rpl::start_with_next([=] {
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
if (const auto onstack = _closeParent) {
|
||||
onstack();
|
||||
}
|
||||
if (weak) {
|
||||
weak->closeBox();
|
||||
}
|
||||
}, lifetime());
|
||||
|
||||
box->newPasswordSet(
|
||||
) | rpl::start_with_next([=](QByteArray &&password) {
|
||||
_newPasswordSet.fire(std::move(password));
|
||||
}, lifetime());
|
||||
|
||||
getDelegate()->show(std::move(box));
|
||||
}
|
||||
|
||||
void RecoverBox::checkSubmitFail(const MTP::Error &error) {
|
||||
if (MTP::IsFloodError(error)) {
|
||||
_submitRequest = 0;
|
||||
_error = tr::lng_flood_error(tr::now);
|
||||
update();
|
||||
setError(tr::lng_flood_error(tr::now));
|
||||
_recoverCode->showError();
|
||||
return;
|
||||
}
|
||||
@@ -1111,7 +1343,7 @@ void RecoverBox::codeSubmitFail(const MTP::Error &error) {
|
||||
|
||||
const QString &err = error.type();
|
||||
if (err == qstr("PASSWORD_EMPTY")) {
|
||||
_passwordCleared.fire({});
|
||||
_newPasswordSet.fire(QByteArray());
|
||||
getDelegate()->show(
|
||||
Box<InformBox>(tr::lng_cloud_password_removed(tr::now)),
|
||||
Ui::LayerOption::CloseOther);
|
||||
@@ -1121,18 +1353,14 @@ void RecoverBox::codeSubmitFail(const MTP::Error &error) {
|
||||
_recoveryExpired.fire({});
|
||||
closeBox();
|
||||
} else if (err == qstr("CODE_INVALID")) {
|
||||
_error = tr::lng_signin_wrong_code(tr::now);
|
||||
update();
|
||||
setError(tr::lng_signin_wrong_code(tr::now));
|
||||
_recoverCode->selectAll();
|
||||
_recoverCode->setFocus();
|
||||
_recoverCode->showError();
|
||||
} else {
|
||||
if (Logs::DebugEnabled()) { // internal server error
|
||||
_error = err + ": " + error.description();
|
||||
} else {
|
||||
_error = Lang::Hard::ServerError();
|
||||
}
|
||||
update();
|
||||
setError(Logs::DebugEnabled() // internal server error
|
||||
? (err + ": " + error.description())
|
||||
: Lang::Hard::ServerError());
|
||||
_recoverCode->setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "mtproto/sender.h"
|
||||
#include "core/core_cloud_password.h"
|
||||
|
||||
namespace MTP {
|
||||
class Instance;
|
||||
} // namespace MTP
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
@@ -35,10 +39,12 @@ public:
|
||||
Core::CloudPasswordCheckRequest curRequest;
|
||||
Core::CloudPasswordAlgo newAlgo;
|
||||
bool hasRecovery = false;
|
||||
QString fromRecoveryCode;
|
||||
bool notEmptyPassport = false;
|
||||
QString hint;
|
||||
Core::SecureSecretAlgo newSecureSecretAlgo;
|
||||
bool turningOff = false;
|
||||
TimeId pendingResetDate = 0;
|
||||
|
||||
// Check cloud password for some action.
|
||||
Fn<void(const Core::CloudPasswordResult &)> customCheckCallback;
|
||||
@@ -46,6 +52,11 @@ public:
|
||||
std::optional<QString> customDescription;
|
||||
rpl::producer<QString> customSubmitButton;
|
||||
};
|
||||
PasscodeBox(
|
||||
QWidget*,
|
||||
not_null<MTP::Instance*> mtp,
|
||||
Main::Session *session,
|
||||
const CloudFields &fields);
|
||||
PasscodeBox(
|
||||
QWidget*,
|
||||
not_null<Main::Session*> session,
|
||||
@@ -55,6 +66,8 @@ public:
|
||||
rpl::producer<> passwordReloadNeeded() const;
|
||||
rpl::producer<> clearUnconfirmedPassword() const;
|
||||
|
||||
rpl::producer<MTPauth_Authorization> newAuthorization() const;
|
||||
|
||||
bool handleCustomCheckError(const MTP::Error &error);
|
||||
bool handleCustomCheckError(const QString &type);
|
||||
|
||||
@@ -82,6 +95,9 @@ private:
|
||||
bool onlyCheckCurrent() const;
|
||||
|
||||
void setPasswordDone(const QByteArray &newPasswordBytes);
|
||||
void recoverPasswordDone(
|
||||
const QByteArray &newPasswordBytes,
|
||||
const MTPauth_Authorization &result);
|
||||
void setPasswordFail(const MTP::Error &error);
|
||||
void setPasswordFail(const QString &type);
|
||||
void setPasswordFail(
|
||||
@@ -131,7 +147,7 @@ private:
|
||||
void passwordChecked();
|
||||
void serverError();
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
Main::Session *_session = nullptr;
|
||||
MTP::Sender _api;
|
||||
|
||||
QString _pattern;
|
||||
@@ -157,10 +173,12 @@ private:
|
||||
object_ptr<Ui::InputField> _passwordHint;
|
||||
object_ptr<Ui::InputField> _recoverEmail;
|
||||
object_ptr<Ui::LinkButton> _recover;
|
||||
bool _showRecoverLink = false;
|
||||
|
||||
QString _oldError, _newError, _emailError;
|
||||
|
||||
rpl::event_stream<QByteArray> _newPasswordSet;
|
||||
rpl::event_stream<MTPauth_Authorization> _newAuthorization;
|
||||
rpl::event_stream<> _passwordReloadNeeded;
|
||||
rpl::event_stream<> _clearUnconfirmedPassword;
|
||||
|
||||
@@ -170,12 +188,14 @@ class RecoverBox final : public Ui::BoxContent {
|
||||
public:
|
||||
RecoverBox(
|
||||
QWidget*,
|
||||
not_null<Main::Session*> session,
|
||||
not_null<MTP::Instance*> mtp,
|
||||
Main::Session *session,
|
||||
const QString &pattern,
|
||||
bool notEmptyPassport);
|
||||
const PasscodeBox::CloudFields &fields,
|
||||
Fn<void()> closeParent = nullptr);
|
||||
|
||||
rpl::producer<> passwordCleared() const;
|
||||
rpl::producer<> recoveryExpired() const;
|
||||
[[nodiscard]] rpl::producer<QByteArray> newPasswordSet() const;
|
||||
[[nodiscard]] rpl::producer<> recoveryExpired() const;
|
||||
|
||||
//void reloadPassword();
|
||||
//void recoveryExpired();
|
||||
@@ -190,20 +210,26 @@ protected:
|
||||
private:
|
||||
void submit();
|
||||
void codeChanged();
|
||||
void codeSubmitDone(const MTPauth_Authorization &result);
|
||||
void codeSubmitFail(const MTP::Error &error);
|
||||
void proceedToClear();
|
||||
void proceedToChange(const QString &code);
|
||||
void checkSubmitFail(const MTP::Error &error);
|
||||
void setError(const QString &error);
|
||||
|
||||
Main::Session *_session = nullptr;
|
||||
MTP::Sender _api;
|
||||
mtpRequestId _submitRequest = 0;
|
||||
|
||||
QString _pattern;
|
||||
bool _notEmptyPassport = false;
|
||||
|
||||
PasscodeBox::CloudFields _cloudFields;
|
||||
|
||||
object_ptr<Ui::InputField> _recoverCode;
|
||||
object_ptr<Ui::LinkButton> _noEmailAccess;
|
||||
Fn<void()> _closeParent;
|
||||
|
||||
QString _error;
|
||||
|
||||
rpl::event_stream<> _passwordCleared;
|
||||
rpl::event_stream<QByteArray> _newPasswordSet;
|
||||
rpl::event_stream<> _recoveryExpired;
|
||||
|
||||
};
|
||||
|
||||
@@ -30,7 +30,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "info/profile/info_profile_icon.h"
|
||||
#include "apiwrap.h"
|
||||
#include "facades.h" // Ui::showPeerHistory
|
||||
#include "app.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/text/format_values.h" // Ui::FormatPhone
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "info/profile/info_profile_cover.h"
|
||||
#include "lang/lang_keys.h"
|
||||
@@ -19,7 +20,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/toast/toast.h"
|
||||
#include "main/main_session.h"
|
||||
#include "apiwrap.h"
|
||||
#include "app.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_info.h"
|
||||
@@ -145,7 +145,7 @@ void Controller::setupCover() {
|
||||
_window,
|
||||
(_phone.isEmpty()
|
||||
? tr::lng_contact_mobile_hidden()
|
||||
: rpl::single(App::formatPhone(_phone)))),
|
||||
: rpl::single(Ui::FormatPhone(_phone)))),
|
||||
style::margins())->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/unixtime.h"
|
||||
#include "base/qt_adapters.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_cloud_password.h"
|
||||
#include "main/main_session.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
@@ -444,7 +445,7 @@ void EditAdminBox::transferOwnership() {
|
||||
? peer()->asChannel()->inputChannel
|
||||
: MTP_inputChannelEmpty();
|
||||
const auto api = &peer()->session().api();
|
||||
api->reloadPasswordState();
|
||||
api->cloudPassword().reload();
|
||||
_checkTransferRequestId = api->request(MTPchannels_EditCreator(
|
||||
channel,
|
||||
MTP_inputUserEmpty(),
|
||||
@@ -495,7 +496,7 @@ void EditAdminBox::transferOwnershipChecked() {
|
||||
}
|
||||
|
||||
void EditAdminBox::requestTransferPassword(not_null<ChannelData*> channel) {
|
||||
peer()->session().api().passwordState(
|
||||
peer()->session().api().cloudPassword().state(
|
||||
) | rpl::take(
|
||||
1
|
||||
) | rpl::start_with_next([=](const Core::CloudPasswordState &state) {
|
||||
|
||||