Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1704cb345a | ||
|
|
0b85d0f185 | ||
|
|
348dfefbaa | ||
|
|
7508980f62 | ||
|
|
e11efe483e | ||
|
|
b23e4fa491 | ||
|
|
b6b7f5706f | ||
|
|
613bf98283 | ||
|
|
0bdb38753b | ||
|
|
d557e0f2b7 | ||
|
|
e81f4e8545 | ||
|
|
3b7d5d3c80 | ||
|
|
0c37990ccd | ||
|
|
0fbea454bc | ||
|
|
d4d688d494 | ||
|
|
b3892f49fa | ||
|
|
daa3a2f62f | ||
|
|
5affb168a2 | ||
|
|
99af2a7058 | ||
|
|
b9acea9cef | ||
|
|
8fb6ece796 | ||
|
|
15a9842b9f | ||
|
|
b28da30038 | ||
|
|
8ce0bd5575 | ||
|
|
5d68d224e5 | ||
|
|
373635a765 | ||
|
|
0ecd4d3b40 | ||
|
|
3fd62d51aa | ||
|
|
818624e051 | ||
|
|
a6eb241ec1 | ||
|
|
1d7fb6c4ce | ||
|
|
2af63ec48f | ||
|
|
0709bc6d70 | ||
|
|
3a34881488 | ||
|
|
39f9147790 | ||
|
|
19a5dcbffc | ||
|
|
e864aa2ff2 | ||
|
|
fe85a8256a | ||
|
|
f24b0c6237 | ||
|
|
3940d57c3d | ||
|
|
8da33113a2 | ||
|
|
f66cfb5684 | ||
|
|
d648d294ca | ||
|
|
0c8033414e | ||
|
|
28f29b51c0 | ||
|
|
8142e83395 | ||
|
|
e247be7e33 | ||
|
|
e594b75f4c | ||
|
|
28f857f763 |
16
.github/workflows/copyright_year_updater.yml
vendored
Normal file
16
.github/workflows/copyright_year_updater.yml
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
name: Copyright year updater.
|
||||
|
||||
on:
|
||||
repository_dispatch:
|
||||
types: ["Restart copyright_year_updater workflow."]
|
||||
schedule:
|
||||
# At 03:00 on January 1.
|
||||
- cron: "0 3 1 1 *"
|
||||
|
||||
jobs:
|
||||
Copyright-year:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: desktop-app/action_code_updater@master
|
||||
with:
|
||||
type: "license-year"
|
||||
4
.github/workflows/mac.yml
vendored
4
.github/workflows/mac.yml
vendored
@@ -102,6 +102,8 @@ jobs:
|
||||
cd Libraries/macos
|
||||
echo "LibrariesPath=`pwd`" >> $GITHUB_ENV
|
||||
|
||||
curl -o tg_owt-version.json https://api.github.com/repos/desktop-app/tg_owt/git/refs/heads/master
|
||||
|
||||
- name: Patches.
|
||||
run: |
|
||||
echo "Find necessary commit from doc."
|
||||
@@ -475,7 +477,7 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ env.LibrariesPath }}/tg_owt
|
||||
key: ${{ runner.OS }}-webrtc-${{ env.CACHE_KEY }}
|
||||
key: ${{ runner.OS }}-webrtc-${{ env.CACHE_KEY }}-${{ hashFiles('**/tg_owt-version.json') }}
|
||||
- name: WebRTC.
|
||||
if: steps.cache-webrtc.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
|
||||
144
.github/workflows/user_agent_updater.yml
vendored
144
.github/workflows/user_agent_updater.yml
vendored
@@ -5,152 +5,14 @@ on:
|
||||
types: ["Restart user_agent_updater workflow."]
|
||||
schedule:
|
||||
# At 00:00 on day-of-month 1.
|
||||
- cron: '0 0 1 * *'
|
||||
- cron: "0 0 1 * *"
|
||||
pull_request_target:
|
||||
types: [closed]
|
||||
|
||||
jobs:
|
||||
User-agent:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
codeFile: "Telegram/SourceFiles/mtproto/details/mtproto_domain_resolver.cpp"
|
||||
headBranchPrefix: "chrome_"
|
||||
baseBranch: "dev"
|
||||
isPull: "0"
|
||||
|
||||
steps:
|
||||
- name: Set env.
|
||||
if: startsWith(github.event_name, 'pull_request')
|
||||
run: |
|
||||
echo "isPull=1" >> $GITHUB_ENV
|
||||
|
||||
- name: Clone.
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up git.
|
||||
run: |
|
||||
token=${{ secrets.TOKEN_FOR_MASTER_UPDATER }}
|
||||
if [ -z "${token}" ]; then
|
||||
echo "Token is unset. Nothing to do."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
url=https://x-access-token:$token@github.com/$GITHUB_REPOSITORY
|
||||
|
||||
git config --global user.email "action@github.com"
|
||||
git config --global user.name "GitHub Action"
|
||||
|
||||
git remote set-url origin $url
|
||||
|
||||
- name: Delete branch.
|
||||
env:
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
if: |
|
||||
env.isPull == '1'
|
||||
&& github.event.action == 'closed'
|
||||
&& startsWith(env.ref, env.headBranchPrefix)
|
||||
run: |
|
||||
git push origin --delete $ref
|
||||
|
||||
- name: Write a new version of Google Chrome to the user-agent for DNS.
|
||||
if: env.isPull == '0'
|
||||
shell: python
|
||||
run: |
|
||||
import subprocess, os, re;
|
||||
|
||||
regExpVersion = "[0-9]+.[0-9]+.[0-9]+.[0-9]+";
|
||||
chrome = "Chrome/";
|
||||
|
||||
def newVersion():
|
||||
output = subprocess.check_output(["google-chrome", "--version"]);
|
||||
version = re.search(regExpVersion, output);
|
||||
if not version:
|
||||
print("Can't find a Chrome version.");
|
||||
exit();
|
||||
return version.group(0);
|
||||
|
||||
newChromeVersion = newVersion();
|
||||
print(newChromeVersion);
|
||||
|
||||
def setEnv(value):
|
||||
open(os.environ['GITHUB_ENV'], "a").write(value);
|
||||
|
||||
def writeUserAgent():
|
||||
p = os.environ['codeFile'];
|
||||
w = open(p, "r");
|
||||
content = w.read();
|
||||
w.close();
|
||||
|
||||
regExpChrome = chrome + regExpVersion;
|
||||
|
||||
version = re.search(regExpChrome, content);
|
||||
if not version:
|
||||
print("Can't find an user-agent in the code.");
|
||||
exit();
|
||||
content = re.sub(regExpChrome, chrome + newChromeVersion, content);
|
||||
|
||||
w = open(p, "w");
|
||||
w.write(content);
|
||||
|
||||
setEnv("ChromeVersion=" + newChromeVersion);
|
||||
|
||||
writeUserAgent();
|
||||
|
||||
- name: Push to a new branch.
|
||||
if: env.isPull == '0' && env.ChromeVersion != ''
|
||||
run: |
|
||||
git diff > git_diff.txt
|
||||
if [[ ! -s git_diff.txt ]]; then
|
||||
echo "Nothing to commit."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git checkout -b $headBranchPrefix$ChromeVersion
|
||||
git add $codeFile
|
||||
git commit -m "Update User-Agent for DNS to Chrome $ChromeVersion."
|
||||
|
||||
git push origin $headBranchPrefix$ChromeVersion
|
||||
echo "Done!"
|
||||
|
||||
- name: Close previous pull requests.
|
||||
if: env.isPull == '0' && env.ChromeVersion != ''
|
||||
uses: actions/github-script@0.4.0
|
||||
- uses: desktop-app/action_code_updater@master
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const common = {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
};
|
||||
|
||||
github.pulls.list(common).then(response => {
|
||||
response.data.forEach((item, _) => {
|
||||
if (item.head.ref.startsWith(process.env.headBranchPrefix)) {
|
||||
console.log(`Close ${item.title} #${item.number}.`);
|
||||
github.pulls.update({
|
||||
pull_number: item.number,
|
||||
state: "closed",
|
||||
...common
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
- name: Create a new pull request.
|
||||
if: env.isPull == '0' && env.ChromeVersion != ''
|
||||
uses: actions/github-script@0.4.0
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const version = process.env.ChromeVersion;
|
||||
const title = `Update User-Agent for DNS to Chrome ${version}.`;
|
||||
|
||||
github.pulls.create({
|
||||
title: title,
|
||||
body: "",
|
||||
head: `${process.env.headBranchPrefix}${version}`,
|
||||
base: process.env.baseBranch,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
});
|
||||
type: "user-agent"
|
||||
|
||||
3
.github/workflows/win.yml
vendored
3
.github/workflows/win.yml
vendored
@@ -103,6 +103,7 @@ jobs:
|
||||
- name: Generate cache key.
|
||||
shell: bash
|
||||
run: |
|
||||
curl -o $LibrariesPath/tg_owt-version.json https://api.github.com/repos/desktop-app/tg_owt/git/refs/heads/master
|
||||
echo $MANUAL_CACHING >> CACHE_KEY.txt
|
||||
if [ "$AUTO_CACHING" == "1" ]; then
|
||||
thisFile=$REPO_NAME/.github/workflows/win.yml
|
||||
@@ -359,7 +360,7 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ env.LibrariesPath }}/tg_owt
|
||||
key: ${{ runner.OS }}-webrtc-${{ env.CACHE_KEY }}
|
||||
key: ${{ runner.OS }}-webrtc-${{ env.CACHE_KEY }}-${{ hashFiles('**/tg_owt-version.json') }}
|
||||
- name: WebRTC.
|
||||
if: steps.cache-webrtc.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
|
||||
2
LEGAL
2
LEGAL
@@ -1,7 +1,7 @@
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
Copyright (c) 2014-2020 The Telegram Desktop Authors.
|
||||
Copyright (c) 2014-2021 The Telegram Desktop Authors.
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -17,13 +17,17 @@ The latest version is available for
|
||||
|
||||
* [Windows 7 and above](https://telegram.org/dl/desktop/win) ([portable](https://telegram.org/dl/desktop/win_portable))
|
||||
* [macOS 10.12 and above](https://telegram.org/dl/desktop/mac)
|
||||
* [OS X 10.10 and 10.11](https://telegram.org/dl/desktop/osx)
|
||||
* [Linux static build for 64 bit](https://telegram.org/dl/desktop/linux) ([32 bit](https://telegram.org/dl/desktop/linux32))
|
||||
* [Linux static build for 64 bit](https://telegram.org/dl/desktop/linux)
|
||||
* [Snap](https://snapcraft.io/telegram-desktop)
|
||||
* [Flatpak](https://flathub.org/apps/details/org.telegram.desktop)
|
||||
|
||||
## Old system versions
|
||||
|
||||
Version **2.4.4** was the last that supports older systems
|
||||
|
||||
* [OS X 10.10 and 10.11](https://updates.tdesktop.com/tosx/tsetup-osx.2.4.4.dmg)
|
||||
* [Linux static build for 32 bit](https://updates.tdesktop.com/tlinux32/tsetup32.2.4.4.tar.xz)
|
||||
|
||||
Version **1.8.15** was the last that supports older systems
|
||||
|
||||
* [Windows XP and Vista](https://updates.tdesktop.com/tsetup/tsetup.1.8.15.exe) ([portable](https://updates.tdesktop.com/tsetup/tportable.1.8.15.zip))
|
||||
|
||||
@@ -84,6 +84,13 @@ if (LINUX)
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT DESKTOP_APP_DISABLE_WAYLAND_INTEGRATION)
|
||||
target_link_libraries(Telegram
|
||||
PRIVATE
|
||||
desktop-app::external_kwayland
|
||||
)
|
||||
endif()
|
||||
|
||||
if (DESKTOP_APP_USE_PACKAGED
|
||||
AND NOT DESKTOP_APP_DISABLE_WAYLAND_INTEGRATION
|
||||
AND Qt5WaylandClient_VERSION VERSION_LESS 5.13.0)
|
||||
@@ -812,6 +819,8 @@ 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_libs.cpp
|
||||
platform/linux/linux_libs.h
|
||||
platform/linux/linux_wayland_integration.cpp
|
||||
@@ -1101,6 +1110,19 @@ if (NOT LINUX)
|
||||
)
|
||||
endif()
|
||||
|
||||
if (LINUX AND 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/notifications_manager_linux.cpp
|
||||
)
|
||||
|
||||
nice_target_sources(Telegram ${src_loc}
|
||||
PRIVATE
|
||||
platform/linux/notifications_manager_linux_dummy.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if (LINUX AND DESKTOP_APP_DISABLE_WAYLAND_INTEGRATION)
|
||||
remove_target_sources(Telegram ${src_loc} platform/linux/linux_wayland_integration.cpp)
|
||||
nice_target_sources(Telegram ${src_loc} PRIVATE platform/linux/linux_wayland_integration_dummy.cpp)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="2.5.2.0" />
|
||||
Version="2.5.4.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram FZ-LLC</PublisherDisplayName>
|
||||
|
||||
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,5,2,0
|
||||
PRODUCTVERSION 2,5,2,0
|
||||
FILEVERSION 2,5,4,0
|
||||
PRODUCTVERSION 2,5,4,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -62,10 +62,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "2.5.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2020"
|
||||
VALUE "FileVersion", "2.5.4.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2021"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "2.5.2.0"
|
||||
VALUE "ProductVersion", "2.5.4.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,5,2,0
|
||||
PRODUCTVERSION 2,5,2,0
|
||||
FILEVERSION 2,5,4,0
|
||||
PRODUCTVERSION 2,5,4,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -53,10 +53,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop Updater"
|
||||
VALUE "FileVersion", "2.5.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2020"
|
||||
VALUE "FileVersion", "2.5.4.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2021"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "2.5.2.0"
|
||||
VALUE "ProductVersion", "2.5.4.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -358,7 +358,7 @@ bool ParticipantsAdditionalData::canRemoveUser(
|
||||
if (canRestrictUser(user)) {
|
||||
return true;
|
||||
} else if (const auto chat = _peer->asChat()) {
|
||||
return chat->invitedByMe.contains(user);
|
||||
return !user->isSelf() && chat->invitedByMe.contains(user);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1212,6 +1212,9 @@ void ParticipantsBoxController::rebuildChatAdmins(
|
||||
return true;
|
||||
}();
|
||||
if (same) {
|
||||
if (!_allLoaded && !delegate()->peerListFullRowsCount()) {
|
||||
chatListReady();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "calls/calls_panel.h"
|
||||
#include "webrtc/webrtc_video_track.h"
|
||||
#include "webrtc/webrtc_media_devices.h"
|
||||
#include "webrtc/webrtc_create_adm.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_session.h"
|
||||
#include "facades.h"
|
||||
@@ -779,6 +780,8 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
|
||||
sendSignalingData(bytes);
|
||||
});
|
||||
},
|
||||
.createAudioDeviceModule = Webrtc::AudioDeviceModuleCreator(
|
||||
settings.callAudioBackend()),
|
||||
};
|
||||
if (Logs::DebugEnabled()) {
|
||||
auto callLogFolder = cWorkingDir() + qsl("DebugLogs");
|
||||
|
||||
@@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_session.h"
|
||||
#include "base/global_shortcuts.h"
|
||||
#include "webrtc/webrtc_media_devices.h"
|
||||
#include "webrtc/webrtc_create_adm.h"
|
||||
|
||||
#include <tgcalls/group/GroupInstanceImpl.h>
|
||||
|
||||
@@ -581,6 +582,8 @@ void GroupCall::createAndStartController() {
|
||||
},
|
||||
.initialInputDeviceId = _audioInputId.toStdString(),
|
||||
.initialOutputDeviceId = _audioOutputId.toStdString(),
|
||||
.createAudioDeviceModule = Webrtc::AudioDeviceModuleCreator(
|
||||
settings.callAudioBackend()),
|
||||
};
|
||||
if (Logs::DebugEnabled()) {
|
||||
auto callLogFolder = cWorkingDir() + qsl("DebugLogs");
|
||||
|
||||
@@ -273,6 +273,8 @@ private:
|
||||
rpl::event_stream<MuteRequest> _toggleMuteRequests;
|
||||
rpl::event_stream<not_null<UserData*>> _kickMemberRequests;
|
||||
rpl::variable<int> _fullCount = 1;
|
||||
rpl::variable<int> _fullCountMin = 0;
|
||||
rpl::variable<int> _fullCountMax = std::numeric_limits<int>::max();
|
||||
|
||||
not_null<QWidget*> _menuParent;
|
||||
base::unique_qptr<Ui::PopupMenu> _menu;
|
||||
@@ -682,9 +684,12 @@ void MembersController::subscribeToChanges(not_null<Data::GroupCall*> real) {
|
||||
_realCallRawValue = real;
|
||||
_realId = real->id();
|
||||
|
||||
_fullCount = real->fullCountValue(
|
||||
) | rpl::map([](int value) {
|
||||
return std::max(value, 1);
|
||||
_fullCount = rpl::combine(
|
||||
real->fullCountValue(),
|
||||
_fullCountMin.value(),
|
||||
_fullCountMax.value()
|
||||
) | rpl::map([](int value, int min, int max) {
|
||||
return std::max(std::clamp(value, min, max), 1);
|
||||
});
|
||||
|
||||
real->participantsSliceAdded(
|
||||
@@ -741,10 +746,14 @@ void MembersController::appendInvitedUsers() {
|
||||
void MembersController::updateRow(
|
||||
const std::optional<Data::GroupCall::Participant> &was,
|
||||
const Data::GroupCall::Participant &now) {
|
||||
auto countChange = 0;
|
||||
if (const auto row = findRow(now.user)) {
|
||||
if (now.speaking && (!was || !was->speaking)) {
|
||||
checkSpeakingRowPosition(row);
|
||||
}
|
||||
if (row->state() == Row::State::Invited) {
|
||||
countChange = 1;
|
||||
}
|
||||
updateRow(row, &now);
|
||||
} else if (auto row = createRow(now)) {
|
||||
if (row->speaking()) {
|
||||
@@ -767,6 +776,14 @@ void MembersController::updateRow(
|
||||
}
|
||||
}
|
||||
delegate()->peerListRefreshRows();
|
||||
countChange = 1;
|
||||
}
|
||||
if (countChange) {
|
||||
const auto fullCountMin = _fullCountMin.current() + countChange;
|
||||
if (_fullCountMax.current() < fullCountMin) {
|
||||
_fullCountMax = fullCountMin;
|
||||
}
|
||||
_fullCountMin = fullCountMin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -879,10 +896,11 @@ void MembersController::prepare() {
|
||||
setSearchNoResultsText(tr::lng_blocked_list_not_found(tr::now));
|
||||
|
||||
const auto call = _call.get();
|
||||
if (const auto real = _peer->groupCall();
|
||||
real && call && real->id() == call->id()) {
|
||||
if (const auto real = _peer->groupCall()
|
||||
; real && call && real->id() == call->id()) {
|
||||
prepareRows(real);
|
||||
} else if (auto row = createSelfRow()) {
|
||||
_fullCountMin = (row->state() == Row::State::Invited) ? 0 : 1;
|
||||
delegate()->peerListAppendRow(std::move(row));
|
||||
delegate()->peerListRefreshRows();
|
||||
}
|
||||
@@ -898,6 +916,7 @@ void MembersController::prepareRows(not_null<Data::GroupCall*> real) {
|
||||
auto foundSelf = false;
|
||||
auto changed = false;
|
||||
const auto &participants = real->participants();
|
||||
auto fullCountMin = 0;
|
||||
auto count = delegate()->peerListFullRowsCount();
|
||||
for (auto i = 0; i != count;) {
|
||||
auto row = delegate()->peerListRowAt(i);
|
||||
@@ -912,6 +931,7 @@ void MembersController::prepareRows(not_null<Data::GroupCall*> real) {
|
||||
not_null{ user },
|
||||
&Data::GroupCall::Participant::user);
|
||||
if (contains) {
|
||||
++fullCountMin;
|
||||
++i;
|
||||
} else {
|
||||
changed = true;
|
||||
@@ -927,18 +947,29 @@ void MembersController::prepareRows(not_null<Data::GroupCall*> real) {
|
||||
&Data::GroupCall::Participant::user);
|
||||
auto row = (i != end(participants)) ? createRow(*i) : createSelfRow();
|
||||
if (row) {
|
||||
if (row->state() != Row::State::Invited) {
|
||||
++fullCountMin;
|
||||
}
|
||||
changed = true;
|
||||
delegate()->peerListAppendRow(std::move(row));
|
||||
}
|
||||
}
|
||||
for (const auto &participant : participants) {
|
||||
if (auto row = createRow(participant)) {
|
||||
++fullCountMin;
|
||||
changed = true;
|
||||
delegate()->peerListAppendRow(std::move(row));
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
delegate()->peerListRefreshRows();
|
||||
if (_fullCountMax.current() < fullCountMin) {
|
||||
_fullCountMax = fullCountMin;
|
||||
}
|
||||
_fullCountMin = fullCountMin;
|
||||
if (real->participantsLoaded()) {
|
||||
_fullCountMax = fullCountMin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -480,6 +480,7 @@ void GroupCallSettingsBox(
|
||||
// Means we finished showing the box.
|
||||
crl::on_main(box, [=] {
|
||||
state->micTester = std::make_unique<Webrtc::AudioInputTester>(
|
||||
Core::App().settings().callAudioBackend(),
|
||||
Core::App().settings().callInputDeviceId());
|
||||
state->levelUpdateTimer.callEach(kMicTestUpdateInterval);
|
||||
});
|
||||
|
||||
@@ -62,7 +62,7 @@ std::map<int, const char*> BetaLogs() {
|
||||
"- Fix sticker pack opening.\n"
|
||||
|
||||
"- Fix group status display.\n"
|
||||
|
||||
|
||||
"- Fix group members display.\n"
|
||||
},
|
||||
{
|
||||
@@ -82,7 +82,23 @@ std::map<int, const char*> BetaLogs() {
|
||||
"- Fix possible crash in connecting to voice chats.\n"
|
||||
|
||||
"- Use different audio module code on Windows in calls.\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
2005003,
|
||||
"- Allow using mouse buttons in Push-to-Talk shortcut.\n"
|
||||
|
||||
"- Fix blurred thumbnails in Shared Links section.\n"
|
||||
},
|
||||
{
|
||||
2005004,
|
||||
"- Implement new audio module code for calls and voice chats.\n"
|
||||
|
||||
"- Allow retracting votes from polls in comments to channel posts.\n"
|
||||
|
||||
"- Show small voice chat button for empty voice chats.\n"
|
||||
|
||||
"- Fix media viewer updating when screen resolution is changed.\n"
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -13,12 +13,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "window/section_widget.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "webrtc/webrtc_create_adm.h"
|
||||
#include "facades.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
Settings::Settings()
|
||||
: _sendSubmitWay(Ui::InputSubmitSettings::Enter)
|
||||
: _callAudioBackend(Webrtc::Backend::OpenAL)
|
||||
, _sendSubmitWay(Ui::InputSubmitSettings::Enter)
|
||||
, _floatPlayerColumn(Window::Column::Second)
|
||||
, _floatPlayerCorner(RectPart::TopRight)
|
||||
, _dialogsWidthRatio(DefaultDialogsWidthRatio()) {
|
||||
@@ -112,7 +114,8 @@ QByteArray Settings::serialize() const {
|
||||
<< qint32(_ipRevealWarning ? 1 : 0)
|
||||
<< qint32(_groupCallPushToTalk ? 1 : 0)
|
||||
<< _groupCallPushToTalkShortcut
|
||||
<< qint64(_groupCallPushToTalkDelay);
|
||||
<< qint64(_groupCallPushToTalkDelay)
|
||||
<< qint32(_callAudioBackend);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -183,6 +186,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
||||
qint32 groupCallPushToTalk = _groupCallPushToTalk ? 1 : 0;
|
||||
QByteArray groupCallPushToTalkShortcut = _groupCallPushToTalkShortcut;
|
||||
qint64 groupCallPushToTalkDelay = _groupCallPushToTalkDelay;
|
||||
qint32 callAudioBackend = static_cast<qint32>(_callAudioBackend);
|
||||
|
||||
stream >> themesAccentColors;
|
||||
if (!stream.atEnd()) {
|
||||
@@ -275,6 +279,9 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
||||
>> groupCallPushToTalkShortcut
|
||||
>> groupCallPushToTalkDelay;
|
||||
}
|
||||
if (!stream.atEnd()) {
|
||||
stream >> callAudioBackend;
|
||||
}
|
||||
if (stream.status() != QDataStream::Ok) {
|
||||
LOG(("App Error: "
|
||||
"Bad data for Core::Settings::constructFromSerialized()"));
|
||||
@@ -369,6 +376,12 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
||||
_groupCallPushToTalk = (groupCallPushToTalk == 1);
|
||||
_groupCallPushToTalkShortcut = groupCallPushToTalkShortcut;
|
||||
_groupCallPushToTalkDelay = groupCallPushToTalkDelay;
|
||||
auto uncheckedBackend = static_cast<Webrtc::Backend>(callAudioBackend);
|
||||
switch (uncheckedBackend) {
|
||||
case Webrtc::Backend::OpenAL:
|
||||
case Webrtc::Backend::ADM:
|
||||
case Webrtc::Backend::ADM2: _callAudioBackend = uncheckedBackend; break;
|
||||
}
|
||||
}
|
||||
|
||||
bool Settings::chatWide() const {
|
||||
|
||||
@@ -21,6 +21,10 @@ namespace Window {
|
||||
enum class Column;
|
||||
} // namespace Window
|
||||
|
||||
namespace Webrtc {
|
||||
enum class Backend;
|
||||
} // namespace Webrtc
|
||||
|
||||
namespace Core {
|
||||
|
||||
class Settings final {
|
||||
@@ -217,6 +221,12 @@ public:
|
||||
void setCallAudioDuckingEnabled(bool value) {
|
||||
_callAudioDuckingEnabled = value;
|
||||
}
|
||||
[[nodiscard]] Webrtc::Backend callAudioBackend() const {
|
||||
return _callAudioBackend;
|
||||
}
|
||||
void setCallAudioBackend(Webrtc::Backend backend) {
|
||||
_callAudioBackend = backend;
|
||||
}
|
||||
[[nodiscard]] bool groupCallPushToTalk() const {
|
||||
return _groupCallPushToTalk;
|
||||
}
|
||||
@@ -531,13 +541,14 @@ private:
|
||||
int _callOutputVolume = 100;
|
||||
int _callInputVolume = 100;
|
||||
bool _callAudioDuckingEnabled = true;
|
||||
Webrtc::Backend _callAudioBackend = Webrtc::Backend();
|
||||
bool _groupCallPushToTalk = false;
|
||||
QByteArray _groupCallPushToTalkShortcut;
|
||||
crl::time _groupCallPushToTalkDelay = 20;
|
||||
Window::Theme::AccentColors _themesAccentColors;
|
||||
bool _lastSeenWarningSeen = false;
|
||||
Ui::SendFilesWay _sendFilesWay;
|
||||
Ui::InputSubmitSettings _sendSubmitWay;
|
||||
Ui::SendFilesWay _sendFilesWay = Ui::SendFilesWay();
|
||||
Ui::InputSubmitSettings _sendSubmitWay = Ui::InputSubmitSettings();
|
||||
base::flat_map<QString, QString> _soundOverrides;
|
||||
bool _exeLaunchWarning = true;
|
||||
bool _ipRevealWarning = true;
|
||||
@@ -553,8 +564,8 @@ private:
|
||||
rpl::variable<bool> _autoDownloadDictionaries = true;
|
||||
rpl::variable<bool> _mainMenuAccountsShown = true;
|
||||
bool _tabbedSelectorSectionEnabled = false; // per-window
|
||||
Window::Column _floatPlayerColumn; // per-window
|
||||
RectPart _floatPlayerCorner; // per-window
|
||||
Window::Column _floatPlayerColumn = Window::Column(); // per-window
|
||||
RectPart _floatPlayerCorner = RectPart(); // per-window
|
||||
bool _thirdSectionInfoEnabled = true; // per-window
|
||||
rpl::event_stream<bool> _thirdSectionInfoEnabledValue; // per-window
|
||||
int _thirdSectionExtendedBy = -1; // per-window
|
||||
|
||||
@@ -270,14 +270,10 @@ std::unique_ptr<Launcher> Launcher::Create(int argc, char *argv[]) {
|
||||
|
||||
Launcher::Launcher(
|
||||
int argc,
|
||||
char *argv[],
|
||||
const QString &deviceModel,
|
||||
const QString &systemVersion)
|
||||
char *argv[])
|
||||
: _argc(argc)
|
||||
, _argv(argv)
|
||||
, _baseIntegration(_argc, _argv)
|
||||
, _deviceModel(deviceModel)
|
||||
, _systemVersion(systemVersion) {
|
||||
, _baseIntegration(_argc, _argv) {
|
||||
base::Integration::Set(&_baseIntegration);
|
||||
}
|
||||
|
||||
@@ -328,6 +324,23 @@ int Launcher::exec() {
|
||||
// Must be started before Platform is started.
|
||||
Logs::start(this);
|
||||
|
||||
if (Logs::DebugEnabled()) {
|
||||
const auto openalLogPath = QDir::toNativeSeparators(
|
||||
cWorkingDir() + qsl("DebugLogs/last_openal_log.txt"));
|
||||
|
||||
qputenv("ALSOFT_LOGLEVEL", "3");
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
_wputenv_s(
|
||||
L"ALSOFT_LOGFILE",
|
||||
openalLogPath.toStdWString().c_str());
|
||||
#else // Q_OS_WIN
|
||||
qputenv(
|
||||
"ALSOFT_LOGFILE",
|
||||
QFile::encodeName(openalLogPath));
|
||||
#endif // !Q_OS_WIN
|
||||
}
|
||||
|
||||
// Must be started before Sandbox is created.
|
||||
Platform::start();
|
||||
Ui::DisableCustomScaling();
|
||||
@@ -419,14 +432,6 @@ void Launcher::prepareSettings() {
|
||||
processArguments();
|
||||
}
|
||||
|
||||
QString Launcher::deviceModel() const {
|
||||
return _deviceModel;
|
||||
}
|
||||
|
||||
QString Launcher::systemVersion() const {
|
||||
return _systemVersion;
|
||||
}
|
||||
|
||||
uint64 Launcher::installationTag() const {
|
||||
return InstallationTag;
|
||||
}
|
||||
|
||||
@@ -15,9 +15,7 @@ class Launcher {
|
||||
public:
|
||||
Launcher(
|
||||
int argc,
|
||||
char *argv[],
|
||||
const QString &deviceModel,
|
||||
const QString &systemVersion);
|
||||
char *argv[]);
|
||||
|
||||
static std::unique_ptr<Launcher> Create(int argc, char *argv[]);
|
||||
|
||||
@@ -26,8 +24,6 @@ public:
|
||||
QString argumentsString() const;
|
||||
bool customWorkingDir() const;
|
||||
|
||||
QString deviceModel() const;
|
||||
QString systemVersion() const;
|
||||
uint64 installationTag() const;
|
||||
|
||||
bool checkPortableVersionFolder();
|
||||
@@ -67,9 +63,6 @@ private:
|
||||
QStringList _arguments;
|
||||
BaseIntegration _baseIntegration;
|
||||
|
||||
const QString _deviceModel;
|
||||
const QString _systemVersion;
|
||||
|
||||
bool _customWorkingDir = false;
|
||||
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs;
|
||||
constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs;
|
||||
constexpr auto AppName = "Telegram Desktop"_cs;
|
||||
constexpr auto AppFile = "Telegram"_cs;
|
||||
constexpr auto AppVersion = 2005002;
|
||||
constexpr auto AppVersionStr = "2.5.2";
|
||||
constexpr auto AppVersion = 2005004;
|
||||
constexpr auto AppVersionStr = "2.5.4";
|
||||
constexpr auto AppBetaVersion = true;
|
||||
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
|
||||
|
||||
@@ -556,7 +556,7 @@ bool InnerWidget::elementUnderCursor(
|
||||
}
|
||||
|
||||
crl::time InnerWidget::elementHighlightTime(
|
||||
not_null<const HistoryView::Element*> element) {
|
||||
not_null<const HistoryItem*> item) {
|
||||
return crl::time(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
bool elementUnderCursor(
|
||||
not_null<const HistoryView::Element*> view) override;
|
||||
crl::time elementHighlightTime(
|
||||
not_null<const HistoryView::Element*> element) override;
|
||||
not_null<const HistoryItem*> item) override;
|
||||
bool elementInSelectionMode() override;
|
||||
bool elementIntersectsRange(
|
||||
not_null<const HistoryView::Element*> view,
|
||||
|
||||
@@ -838,7 +838,7 @@ void GenerateItems(
|
||||
data.vparticipant().match([&](const MTPDgroupCallParticipant &data) {
|
||||
const auto user = history->owner().user(data.vuser_id().v);
|
||||
const auto userLink = user->createOpenLink();
|
||||
const auto userLinkText = textcmdLink(1, user->name);
|
||||
const auto userLinkText = textcmdLink(2, user->name);
|
||||
auto text = tr::lng_admin_log_muted_participant(
|
||||
tr::now,
|
||||
lt_from,
|
||||
@@ -862,7 +862,7 @@ void GenerateItems(
|
||||
data.vparticipant().match([&](const MTPDgroupCallParticipant &data) {
|
||||
const auto user = history->owner().user(data.vuser_id().v);
|
||||
const auto userLink = user->createOpenLink();
|
||||
const auto userLinkText = textcmdLink(1, user->name);
|
||||
const auto userLinkText = textcmdLink(2, user->name);
|
||||
auto text = tr::lng_admin_log_unmuted_participant(
|
||||
tr::now,
|
||||
lt_from,
|
||||
|
||||
@@ -1751,18 +1751,11 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||
}
|
||||
if (const auto media = item->media()) {
|
||||
if (const auto poll = media->poll()) {
|
||||
if (!poll->closed()) {
|
||||
if (poll->voted() && !poll->quiz()) {
|
||||
_menu->addAction(tr::lng_polls_retract(tr::now), [=] {
|
||||
session->api().sendPollVotes(itemId, {});
|
||||
});
|
||||
}
|
||||
if (item->canStopPoll()) {
|
||||
_menu->addAction(tr::lng_polls_stop(tr::now), [=] {
|
||||
HistoryView::StopPoll(session, itemId);
|
||||
});
|
||||
}
|
||||
}
|
||||
HistoryView::AddPollActions(
|
||||
_menu,
|
||||
poll,
|
||||
item,
|
||||
HistoryView::Context::History);
|
||||
} else if (const auto contact = media->sharedContact()) {
|
||||
const auto phone = contact->phoneNumber;
|
||||
_menu->addAction(tr::lng_profile_copy_phone(tr::now), [=] {
|
||||
@@ -2520,9 +2513,9 @@ void HistoryInner::elementStartStickerLoop(
|
||||
_animatedStickersPlayed.emplace(view->data());
|
||||
}
|
||||
|
||||
crl::time HistoryInner::elementHighlightTime(not_null<const Element*> view) {
|
||||
const auto fullAnimMs = _controller->content()->highlightStartTime(
|
||||
view->data());
|
||||
crl::time HistoryInner::elementHighlightTime(
|
||||
not_null<const HistoryItem*> item) {
|
||||
const auto fullAnimMs = _controller->content()->highlightStartTime(item);
|
||||
if (fullAnimMs > 0) {
|
||||
const auto now = crl::now();
|
||||
if (fullAnimMs < now) {
|
||||
@@ -3421,8 +3414,8 @@ not_null<HistoryView::ElementDelegate*> HistoryInner::ElementDelegate() {
|
||||
return (App::hoveredItem() == view);
|
||||
}
|
||||
crl::time elementHighlightTime(
|
||||
not_null<const Element*> view) override {
|
||||
return Instance ? Instance->elementHighlightTime(view) : 0;
|
||||
not_null<const HistoryItem*> item) override {
|
||||
return Instance ? Instance->elementHighlightTime(item) : 0;
|
||||
}
|
||||
bool elementInSelectionMode() override {
|
||||
return Instance ? Instance->inSelectionMode() : false;
|
||||
|
||||
@@ -84,7 +84,7 @@ public:
|
||||
int till) const;
|
||||
void elementStartStickerLoop(not_null<const Element*> view);
|
||||
[[nodiscard]] crl::time elementHighlightTime(
|
||||
not_null<const Element*> view);
|
||||
not_null<const HistoryItem*> item);
|
||||
void elementShowPollResults(
|
||||
not_null<PollData*> poll,
|
||||
FullMsgId context);
|
||||
|
||||
@@ -1045,11 +1045,6 @@ void HistoryWidget::scrollToAnimationCallback(
|
||||
|
||||
void HistoryWidget::enqueueMessageHighlight(
|
||||
not_null<HistoryView::Element*> view) {
|
||||
if (const auto group = session().data().groups().find(view->data())) {
|
||||
if (const auto leader = group->items.front()->mainView()) {
|
||||
view = leader;
|
||||
}
|
||||
}
|
||||
auto enqueueMessageId = [this](MsgId universalId) {
|
||||
if (_highlightQueue.empty() && !_highlightTimer.isActive()) {
|
||||
highlightMessage(universalId);
|
||||
@@ -1096,7 +1091,7 @@ void HistoryWidget::checkNextHighlight() {
|
||||
|
||||
void HistoryWidget::updateHighlightedMessage() {
|
||||
const auto item = getItemFromHistoryOrMigrated(_highlightedMessageId);
|
||||
const auto view = item ? item->mainView() : nullptr;
|
||||
auto view = item ? item->mainView() : nullptr;
|
||||
if (!view) {
|
||||
return stopMessageHighlight();
|
||||
}
|
||||
@@ -1105,6 +1100,11 @@ void HistoryWidget::updateHighlightedMessage() {
|
||||
return stopMessageHighlight();
|
||||
}
|
||||
|
||||
if (const auto group = session().data().groups().find(view->data())) {
|
||||
if (const auto leader = group->items.front()->mainView()) {
|
||||
view = leader;
|
||||
}
|
||||
}
|
||||
session().data().requestViewRepaint(view);
|
||||
}
|
||||
|
||||
@@ -1661,6 +1661,7 @@ void HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) {
|
||||
_editMsgId = 0;
|
||||
_replyToId = readyToForward() ? 0 : _history->localDraft()->msgId;
|
||||
}
|
||||
updateCmdStartShown();
|
||||
updateControlsVisibility();
|
||||
updateControlsGeometry();
|
||||
refreshTopBarActiveChat();
|
||||
@@ -2228,11 +2229,7 @@ void HistoryWidget::updateControlsVisibility() {
|
||||
_botCommandStart->hide();
|
||||
} else {
|
||||
_botKeyboardShow->hide();
|
||||
if (_cmdStartShown) {
|
||||
_botCommandStart->show();
|
||||
} else {
|
||||
_botCommandStart->hide();
|
||||
}
|
||||
_botCommandStart->setVisible(_cmdStartShown);
|
||||
}
|
||||
}
|
||||
_attachToggle->show();
|
||||
@@ -3738,7 +3735,7 @@ void HistoryWidget::updateSendButtonType() {
|
||||
bool HistoryWidget::updateCmdStartShown() {
|
||||
bool cmdStartShown = false;
|
||||
if (_history && _peer && ((_peer->isChat() && _peer->asChat()->botStatus > 0) || (_peer->isMegagroup() && _peer->asChannel()->mgInfo->botStatus > 0) || (_peer->isUser() && _peer->asUser()->isBot()))) {
|
||||
if (!isBotStart() && !isBlocked() && !_keyboard->hasMarkup() && !_keyboard->forceReply()) {
|
||||
if (!isBotStart() && !isBlocked() && !_keyboard->hasMarkup() && !_keyboard->forceReply() && !_editMsgId) {
|
||||
if (!HasSendText(_field)) {
|
||||
cmdStartShown = true;
|
||||
}
|
||||
@@ -4081,8 +4078,8 @@ void HistoryWidget::checkFieldAutocomplete() {
|
||||
&& cRecentInlineBots().isEmpty()) {
|
||||
session().local().readRecentHashtagsAndBots();
|
||||
} else if (autocomplete.query[0] == '/'
|
||||
&& _peer->isUser()
|
||||
&& !_peer->asUser()->isBot()) {
|
||||
&& ((_peer->isUser() && !_peer->asUser()->isBot())
|
||||
|| _editMsgId)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -4845,7 +4842,7 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
|
||||
_tabbedSelectorToggle->show();
|
||||
_botKeyboardHide->hide();
|
||||
_botKeyboardShow->hide();
|
||||
_botCommandStart->show();
|
||||
_botCommandStart->setVisible(!_editMsgId);
|
||||
}
|
||||
_field->setMaxHeight(computeMaxFieldHeight());
|
||||
_kbShown = false;
|
||||
@@ -5652,7 +5649,7 @@ void HistoryWidget::editMessage(FullMsgId itemId) {
|
||||
}
|
||||
|
||||
void HistoryWidget::editMessage(not_null<HistoryItem*> item) {
|
||||
if (_voiceRecordBar->isListenState()) {
|
||||
if (_voiceRecordBar->isActive()) {
|
||||
Ui::show(Box<InformBox>(tr::lng_edit_caption_voice(tr::now)));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1814,7 +1814,7 @@ void ComposeControls::editMessage(not_null<HistoryItem*> item) {
|
||||
Expects(_history != nullptr);
|
||||
Expects(draftKeyCurrent() != Data::DraftKey::None());
|
||||
|
||||
if (_voiceRecordBar && _voiceRecordBar->isListenState()) {
|
||||
if (_voiceRecordBar->isActive()) {
|
||||
Ui::show(Box<InformBox>(tr::lng_edit_caption_voice(tr::now)));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -924,12 +924,9 @@ CancelButton::CancelButton(not_null<Ui::RpWidget*> parent, int height)
|
||||
|
||||
void CancelButton::init() {
|
||||
_showProgress.value(
|
||||
) | rpl::start_with_next([=](float64 progress) {
|
||||
const auto hasProgress = (progress > 0.);
|
||||
if (isHidden() == !hasProgress) {
|
||||
setVisible(hasProgress);
|
||||
}
|
||||
update();
|
||||
) | rpl::map(rpl::mappers::_1 > 0.) | rpl::distinct_until_changed(
|
||||
) | rpl::start_with_next([=](bool hasProgress) {
|
||||
setVisible(hasProgress);
|
||||
}, lifetime());
|
||||
|
||||
paintRequest(
|
||||
@@ -960,6 +957,7 @@ QPoint CancelButton::prepareRippleStartPosition() const {
|
||||
|
||||
void CancelButton::requestPaintProgress(float64 progress) {
|
||||
_showProgress = progress;
|
||||
update();
|
||||
}
|
||||
|
||||
VoiceRecordBar::VoiceRecordBar(
|
||||
|
||||
@@ -868,6 +868,9 @@ base::unique_qptr<Ui::PopupMenu> FillContextMenu(
|
||||
const auto document = linkDocument
|
||||
? linkDocument->document().get()
|
||||
: nullptr;
|
||||
const auto poll = item
|
||||
? (item->media() ? item->media()->poll() : nullptr)
|
||||
: nullptr;
|
||||
const auto hasSelection = !request.selectedItems.empty()
|
||||
|| !request.selectedText.empty();
|
||||
|
||||
@@ -897,6 +900,8 @@ base::unique_qptr<Ui::PopupMenu> FillContextMenu(
|
||||
// });
|
||||
// AddToggleGroupingAction(result, linkPeer->peer());
|
||||
// }
|
||||
} else if (poll) {
|
||||
AddPollActions(result, poll, item, list->elementContext());
|
||||
} else if (!request.overSelection && view && !hasSelection) {
|
||||
const auto owner = &view->data()->history()->owner();
|
||||
const auto media = view->media();
|
||||
@@ -979,4 +984,30 @@ void StopPoll(not_null<Main::Session*> session, FullMsgId itemId) {
|
||||
stop));
|
||||
}
|
||||
|
||||
void AddPollActions(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
not_null<PollData*> poll,
|
||||
not_null<HistoryItem*> item,
|
||||
Context context) {
|
||||
if ((context != Context::History)
|
||||
&& (context != Context::Replies)
|
||||
&& (context != Context::Pinned)) {
|
||||
return;
|
||||
}
|
||||
if (poll->closed()) {
|
||||
return;
|
||||
}
|
||||
const auto itemId = item->fullId();
|
||||
if (poll->voted() && !poll->quiz()) {
|
||||
menu->addAction(tr::lng_polls_retract(tr::now), [=] {
|
||||
poll->session().api().sendPollVotes(itemId, {});
|
||||
});
|
||||
}
|
||||
if (item->canStopPoll()) {
|
||||
menu->addAction(tr::lng_polls_stop(tr::now), [=] {
|
||||
StopPoll(&poll->session(), itemId);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace HistoryView
|
||||
|
||||
@@ -49,5 +49,10 @@ void CopyPostLink(
|
||||
FullMsgId itemId,
|
||||
Context context);
|
||||
void StopPoll(not_null<Main::Session*> session, FullMsgId itemId);
|
||||
void AddPollActions(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
not_null<PollData*> poll,
|
||||
not_null<HistoryItem*> item,
|
||||
Context context);
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -79,7 +79,7 @@ bool SimpleElementDelegate::elementUnderCursor(
|
||||
}
|
||||
|
||||
crl::time SimpleElementDelegate::elementHighlightTime(
|
||||
not_null<const Element*> element) {
|
||||
not_null<const HistoryItem*> item) {
|
||||
return crl::time(0);
|
||||
}
|
||||
|
||||
@@ -280,29 +280,44 @@ void Element::refreshDataIdHook() {
|
||||
void Element::paintHighlight(
|
||||
Painter &p,
|
||||
int geometryHeight) const {
|
||||
const auto animms = delegate()->elementHighlightTime(this);
|
||||
if (!animms
|
||||
|| animms >= st::activeFadeInDuration + st::activeFadeOutDuration) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto top = marginTop();
|
||||
const auto bottom = marginBottom();
|
||||
const auto fill = qMin(top, bottom);
|
||||
const auto skiptop = top - fill;
|
||||
const auto fillheight = fill + geometryHeight + fill;
|
||||
|
||||
const auto dt = (animms > st::activeFadeInDuration)
|
||||
paintCustomHighlight(p, skiptop, fillheight, data());
|
||||
}
|
||||
|
||||
float64 Element::highlightOpacity(not_null<const HistoryItem*> item) const {
|
||||
const auto animms = delegate()->elementHighlightTime(item);
|
||||
if (!animms
|
||||
|| animms >= st::activeFadeInDuration + st::activeFadeOutDuration) {
|
||||
return 0.;
|
||||
}
|
||||
|
||||
return (animms > st::activeFadeInDuration)
|
||||
? (1. - (animms - st::activeFadeInDuration)
|
||||
/ float64(st::activeFadeOutDuration))
|
||||
: (animms / float64(st::activeFadeInDuration));
|
||||
}
|
||||
|
||||
void Element::paintCustomHighlight(
|
||||
Painter &p,
|
||||
int y,
|
||||
int height,
|
||||
not_null<const HistoryItem*> item) const {
|
||||
const auto opacity = highlightOpacity(item);
|
||||
if (opacity == 0.) {
|
||||
return;
|
||||
}
|
||||
const auto o = p.opacity();
|
||||
p.setOpacity(o * dt);
|
||||
p.setOpacity(o * opacity);
|
||||
p.fillRect(
|
||||
0,
|
||||
skiptop,
|
||||
y,
|
||||
width(),
|
||||
fillheight,
|
||||
height,
|
||||
st::defaultTextPalette.selectOverlay);
|
||||
p.setOpacity(o);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
Element *replacing = nullptr) = 0;
|
||||
virtual bool elementUnderCursor(not_null<const Element*> view) = 0;
|
||||
virtual crl::time elementHighlightTime(
|
||||
not_null<const Element*> element) = 0;
|
||||
not_null<const HistoryItem*> item) = 0;
|
||||
virtual bool elementInSelectionMode() = 0;
|
||||
virtual bool elementIntersectsRange(
|
||||
not_null<const Element*> view,
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
Element *replacing = nullptr) override;
|
||||
bool elementUnderCursor(not_null<const Element*> view) override;
|
||||
crl::time elementHighlightTime(
|
||||
not_null<const Element*> element) override;
|
||||
not_null<const HistoryItem*> item) override;
|
||||
bool elementInSelectionMode() override;
|
||||
bool elementIntersectsRange(
|
||||
not_null<const Element*> view,
|
||||
@@ -301,6 +301,13 @@ public:
|
||||
virtual void unloadHeavyPart();
|
||||
void checkHeavyPart();
|
||||
|
||||
void paintCustomHighlight(
|
||||
Painter &p,
|
||||
int y,
|
||||
int height,
|
||||
not_null<const HistoryItem*> item) const;
|
||||
float64 highlightOpacity(not_null<const HistoryItem*> item) const;
|
||||
|
||||
// Legacy blocks structure.
|
||||
HistoryBlock *block();
|
||||
const HistoryBlock *block() const;
|
||||
|
||||
@@ -321,6 +321,7 @@ rpl::producer<Ui::GroupCallBarContent> GroupCallTracker::ContentByCall(
|
||||
call->fullCountValue(
|
||||
) | rpl::start_with_next([=](int count) {
|
||||
state->current.count = count;
|
||||
state->current.shown = (count > 0);
|
||||
consumer.put_next_copy(state->current);
|
||||
}, lifetime);
|
||||
|
||||
|
||||
@@ -482,7 +482,7 @@ void ListWidget::highlightMessage(FullMsgId itemId) {
|
||||
_highlightedMessageId = itemId;
|
||||
_highlightTimer.callEach(AnimationTimerDelta);
|
||||
|
||||
repaintItem(view);
|
||||
repaintHighlightedItem(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -496,10 +496,24 @@ void ListWidget::showAroundPosition(
|
||||
refreshViewer();
|
||||
}
|
||||
|
||||
void ListWidget::repaintHighlightedItem(not_null<const Element*> view) {
|
||||
if (view->isHiddenByGroup()) {
|
||||
if (const auto group = session().data().groups().find(view->data())) {
|
||||
if (const auto leader = viewForItem(group->items.front())) {
|
||||
if (!leader->isHiddenByGroup()) {
|
||||
repaintItem(leader);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
repaintItem(view);
|
||||
}
|
||||
|
||||
void ListWidget::updateHighlightedMessage() {
|
||||
if (const auto item = session().data().message(_highlightedMessageId)) {
|
||||
if (const auto view = viewForItem(item)) {
|
||||
repaintItem(view);
|
||||
repaintHighlightedItem(view);
|
||||
auto duration = st::activeFadeInDuration + st::activeFadeOutDuration;
|
||||
if (crl::now() - _highlightStart <= duration) {
|
||||
return;
|
||||
@@ -1244,8 +1258,8 @@ bool ListWidget::elementUnderCursor(
|
||||
}
|
||||
|
||||
crl::time ListWidget::elementHighlightTime(
|
||||
not_null<const HistoryView::Element*> element) {
|
||||
if (element->data()->fullId() == _highlightedMessageId) {
|
||||
not_null<const HistoryItem*> item) {
|
||||
if (item->fullId() == _highlightedMessageId) {
|
||||
if (_highlightTimer.isActive()) {
|
||||
return crl::now() - _highlightStart;
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ public:
|
||||
Element *replacing = nullptr) override;
|
||||
bool elementUnderCursor(not_null<const Element*> view) override;
|
||||
crl::time elementHighlightTime(
|
||||
not_null<const Element*> element) override;
|
||||
not_null<const HistoryItem*> item) override;
|
||||
bool elementInSelectionMode() override;
|
||||
bool elementIntersectsRange(
|
||||
not_null<const Element*> view,
|
||||
@@ -340,6 +340,7 @@ private:
|
||||
int itemTop(not_null<const Element*> view) const;
|
||||
void repaintItem(FullMsgId itemId);
|
||||
void repaintItem(const Element *view);
|
||||
void repaintHighlightedItem(not_null<const Element*> view);
|
||||
void resizeItem(not_null<Element*> view);
|
||||
void refreshItem(not_null<const Element*> view);
|
||||
void itemRemoved(not_null<const HistoryItem*> item);
|
||||
|
||||
@@ -570,7 +570,40 @@ void Message::draw(
|
||||
return;
|
||||
}
|
||||
|
||||
paintHighlight(p, g.height());
|
||||
auto entry = logEntryOriginal();
|
||||
auto mediaDisplayed = media && media->isDisplayed();
|
||||
|
||||
// Entry page is always a bubble bottom.
|
||||
auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || (entry/* && entry->isBubbleBottom()*/);
|
||||
auto mediaOnTop = (mediaDisplayed && media->isBubbleTop()) || (entry && entry->isBubbleTop());
|
||||
|
||||
auto mediaSelectionIntervals = (!selected && mediaDisplayed)
|
||||
? media->getBubbleSelectionIntervals(selection)
|
||||
: std::vector<BubbleSelectionInterval>();
|
||||
auto localMediaTop = 0;
|
||||
const auto customHighlight = mediaDisplayed && media->customHighlight();
|
||||
if (!mediaSelectionIntervals.empty() || customHighlight) {
|
||||
auto localMediaBottom = g.top() + g.height();
|
||||
if (data()->repliesAreComments() || data()->externalReply()) {
|
||||
localMediaBottom -= st::historyCommentsButtonHeight;
|
||||
}
|
||||
if (!mediaOnBottom) {
|
||||
localMediaBottom -= st::msgPadding.bottom();
|
||||
}
|
||||
if (entry) {
|
||||
localMediaBottom -= entry->height();
|
||||
}
|
||||
localMediaTop = localMediaBottom - media->height();
|
||||
for (auto &[top, height] : mediaSelectionIntervals) {
|
||||
top += localMediaTop;
|
||||
}
|
||||
}
|
||||
|
||||
if (customHighlight) {
|
||||
media->drawHighlight(p, localMediaTop);
|
||||
} else {
|
||||
paintHighlight(p, g.height());
|
||||
}
|
||||
|
||||
const auto roll = media ? media->bubbleRoll() : Media::BubbleRoll();
|
||||
if (roll) {
|
||||
@@ -602,34 +635,6 @@ void Message::draw(
|
||||
fromNameUpdated(g.width());
|
||||
}
|
||||
|
||||
auto entry = logEntryOriginal();
|
||||
auto mediaDisplayed = media && media->isDisplayed();
|
||||
|
||||
// Entry page is always a bubble bottom.
|
||||
auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || (entry/* && entry->isBubbleBottom()*/);
|
||||
auto mediaOnTop = (mediaDisplayed && media->isBubbleTop()) || (entry && entry->isBubbleTop());
|
||||
|
||||
|
||||
auto mediaSelectionIntervals = (!selected && mediaDisplayed)
|
||||
? media->getBubbleSelectionIntervals(selection)
|
||||
: std::vector<BubbleSelectionInterval>();
|
||||
if (!mediaSelectionIntervals.empty()) {
|
||||
auto localMediaBottom = g.top() + g.height();
|
||||
if (data()->repliesAreComments() || data()->externalReply()) {
|
||||
localMediaBottom -= st::historyCommentsButtonHeight;
|
||||
}
|
||||
if (!mediaOnBottom) {
|
||||
localMediaBottom -= st::msgPadding.bottom();
|
||||
}
|
||||
if (entry) {
|
||||
localMediaBottom -= entry->height();
|
||||
}
|
||||
const auto localMediaTop = localMediaBottom - media->height();
|
||||
for (auto &[top, height] : mediaSelectionIntervals) {
|
||||
top += localMediaTop;
|
||||
}
|
||||
}
|
||||
|
||||
auto skipTail = isAttachedToNext()
|
||||
|| (media && media->skipBubbleTail())
|
||||
|| (keyboard != nullptr)
|
||||
|
||||
@@ -525,12 +525,36 @@ void TopBarWidget::setActiveChat(
|
||||
_activeChat = activeChat;
|
||||
return;
|
||||
}
|
||||
const auto peerChanged = (_activeChat.key.history()
|
||||
!= activeChat.key.history());
|
||||
|
||||
_activeChat = activeChat;
|
||||
_sendAction = sendAction;
|
||||
_titlePeerText.clear();
|
||||
_back->clearState();
|
||||
update();
|
||||
|
||||
if (peerChanged) {
|
||||
_activeChatLifetime.destroy();
|
||||
if (const auto history = _activeChat.key.history()) {
|
||||
session().changes().peerFlagsValue(
|
||||
history->peer,
|
||||
Data::PeerUpdate::Flag::GroupCall
|
||||
) | rpl::map([=] {
|
||||
return history->peer->groupCall();
|
||||
}) | rpl::distinct_until_changed(
|
||||
) | rpl::map([](Data::GroupCall *call) {
|
||||
return call ? call->fullCountValue() : rpl::single(-1);
|
||||
}) | rpl::flatten_latest(
|
||||
) | rpl::map([](int count) {
|
||||
return (count == 0);
|
||||
}) | rpl::distinct_until_changed(
|
||||
) | rpl::start_with_next([=] {
|
||||
updateControlsVisibility();
|
||||
updateControlsGeometry();
|
||||
}, _activeChatLifetime);
|
||||
}
|
||||
}
|
||||
updateUnreadBadge();
|
||||
refreshInfoButton();
|
||||
if (_menu) {
|
||||
@@ -722,7 +746,12 @@ void TopBarWidget::updateControlsVisibility() {
|
||||
_call->setVisible(historyMode && callsEnabled);
|
||||
const auto groupCallsEnabled = [&] {
|
||||
if (const auto peer = _activeChat.key.peer()) {
|
||||
return peer->canManageGroupCall();
|
||||
if (peer->canManageGroupCall()) {
|
||||
return true;
|
||||
} else if (const auto call = peer->groupCall()) {
|
||||
return (call->fullCount() == 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}();
|
||||
|
||||
@@ -130,6 +130,7 @@ private:
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
ActiveChat _activeChat;
|
||||
QString _customTitleText;
|
||||
rpl::lifetime _activeChatLifetime;
|
||||
|
||||
int _selectedCount = 0;
|
||||
bool _canDelete = false;
|
||||
|
||||
@@ -951,6 +951,7 @@ void Document::drawGrouped(
|
||||
const QRect &geometry,
|
||||
RectParts sides,
|
||||
RectParts corners,
|
||||
float64 highlightOpacity,
|
||||
not_null<uint64*> cacheKey,
|
||||
not_null<QPixmap*> cache) const {
|
||||
p.translate(geometry.topLeft());
|
||||
|
||||
@@ -72,6 +72,7 @@ public:
|
||||
const QRect &geometry,
|
||||
RectParts sides,
|
||||
RectParts corners,
|
||||
float64 highlightOpacity,
|
||||
not_null<uint64*> cacheKey,
|
||||
not_null<QPixmap*> cache) const override;
|
||||
TextState getStateGrouped(
|
||||
|
||||
@@ -901,6 +901,7 @@ void Gif::drawGrouped(
|
||||
const QRect &geometry,
|
||||
RectParts sides,
|
||||
RectParts corners,
|
||||
float64 highlightOpacity,
|
||||
not_null<uint64*> cacheKey,
|
||||
not_null<QPixmap*> cache) const {
|
||||
ensureDataMediaCreated();
|
||||
@@ -989,8 +990,16 @@ void Gif::drawGrouped(
|
||||
p.drawPixmap(geometry, *cache);
|
||||
}
|
||||
|
||||
if (selected) {
|
||||
const auto overlayOpacity = selected
|
||||
? (1. - highlightOpacity)
|
||||
: highlightOpacity;
|
||||
if (overlayOpacity > 0.) {
|
||||
p.setOpacity(overlayOpacity);
|
||||
Ui::FillComplexOverlayRect(p, geometry, roundRadius, corners);
|
||||
if (!selected) {
|
||||
Ui::FillComplexOverlayRect(p, geometry, roundRadius, corners);
|
||||
}
|
||||
p.setOpacity(1.);
|
||||
}
|
||||
|
||||
if (radial
|
||||
|
||||
@@ -79,6 +79,7 @@ public:
|
||||
const QRect &geometry,
|
||||
RectParts sides,
|
||||
RectParts corners,
|
||||
float64 highlightOpacity,
|
||||
not_null<uint64*> cacheKey,
|
||||
not_null<QPixmap*> cache) const override;
|
||||
TextState getStateGrouped(
|
||||
|
||||
@@ -84,6 +84,8 @@ public:
|
||||
}
|
||||
virtual void refreshParentId(not_null<HistoryItem*> realParent) {
|
||||
}
|
||||
virtual void drawHighlight(Painter &p, int top) const {
|
||||
}
|
||||
virtual void draw(
|
||||
Painter &p,
|
||||
const QRect &r,
|
||||
@@ -177,6 +179,7 @@ public:
|
||||
const QRect &geometry,
|
||||
RectParts sides,
|
||||
RectParts corners,
|
||||
float64 highlightOpacity,
|
||||
not_null<uint64*> cacheKey,
|
||||
not_null<QPixmap*> cache) const {
|
||||
Unexpected("Grouping method call.");
|
||||
@@ -274,6 +277,9 @@ public:
|
||||
const QRect &bubble,
|
||||
crl::time ms) const {
|
||||
}
|
||||
[[nodiscard]] virtual bool customHighlight() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool hasHeavyPart() const {
|
||||
return false;
|
||||
|
||||
@@ -268,6 +268,18 @@ QMargins GroupedMedia::groupedPadding() const {
|
||||
(normal.bottom() - grouped.bottom()) + addToBottom);
|
||||
}
|
||||
|
||||
void GroupedMedia::drawHighlight(Painter &p, int top) const {
|
||||
if (_mode != Mode::Column) {
|
||||
return;
|
||||
}
|
||||
const auto skip = top + groupedPadding().top();
|
||||
for (auto i = 0, count = int(_parts.size()); i != count; ++i) {
|
||||
const auto &part = _parts[i];
|
||||
const auto rect = part.geometry.translated(0, skip);
|
||||
_parent->paintCustomHighlight(p, rect.y(), rect.height(), part.item);
|
||||
}
|
||||
}
|
||||
|
||||
void GroupedMedia::draw(
|
||||
Painter &p,
|
||||
const QRect &clip,
|
||||
@@ -290,6 +302,9 @@ void GroupedMedia::draw(
|
||||
if (textSelection) {
|
||||
selection = part.content->skipSelection(selection);
|
||||
}
|
||||
const auto highlightOpacity = (_mode == Mode::Grid)
|
||||
? _parent->highlightOpacity(part.item)
|
||||
: 0.;
|
||||
part.content->drawGrouped(
|
||||
p,
|
||||
clip,
|
||||
@@ -298,6 +313,7 @@ void GroupedMedia::draw(
|
||||
part.geometry.translated(0, groupPadding.top()),
|
||||
part.sides,
|
||||
cornersFromSides(part.sides),
|
||||
highlightOpacity,
|
||||
&part.cacheKey,
|
||||
&part.cache);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ public:
|
||||
|
||||
void refreshParentId(not_null<HistoryItem*> realParent) override;
|
||||
|
||||
void drawHighlight(Painter &p, int top) const override;
|
||||
void draw(
|
||||
Painter &p,
|
||||
const QRect &clip,
|
||||
@@ -87,6 +88,9 @@ public:
|
||||
bool allowsFastShare() const override {
|
||||
return true;
|
||||
}
|
||||
bool customHighlight() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
void stopAnimation() override;
|
||||
void checkAnimation() override;
|
||||
|
||||
@@ -485,6 +485,7 @@ void Photo::drawGrouped(
|
||||
const QRect &geometry,
|
||||
RectParts sides,
|
||||
RectParts corners,
|
||||
float64 highlightOpacity,
|
||||
not_null<uint64*> cacheKey,
|
||||
not_null<QPixmap*> cache) const {
|
||||
ensureDataMediaCreated();
|
||||
@@ -509,9 +510,18 @@ void Photo::drawGrouped(
|
||||
// App::roundShadow(p, 0, 0, paintw, painth, selected ? st::msgInShadowSelected : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners);
|
||||
}
|
||||
p.drawPixmap(geometry.topLeft(), *cache);
|
||||
if (selected) {
|
||||
|
||||
const auto overlayOpacity = selected
|
||||
? (1. - highlightOpacity)
|
||||
: highlightOpacity;
|
||||
if (overlayOpacity > 0.) {
|
||||
p.setOpacity(overlayOpacity);
|
||||
const auto roundRadius = ImageRoundRadius::Large;
|
||||
Ui::FillComplexOverlayRect(p, geometry, roundRadius, corners);
|
||||
if (!selected) {
|
||||
Ui::FillComplexOverlayRect(p, geometry, roundRadius, corners);
|
||||
}
|
||||
p.setOpacity(1.);
|
||||
}
|
||||
|
||||
const auto displayState = radial
|
||||
|
||||
@@ -68,6 +68,7 @@ public:
|
||||
const QRect &geometry,
|
||||
RectParts sides,
|
||||
RectParts corners,
|
||||
float64 highlightOpacity,
|
||||
not_null<uint64*> cacheKey,
|
||||
not_null<QPixmap*> cache) const override;
|
||||
TextState getStateGrouped(
|
||||
|
||||
@@ -765,7 +765,9 @@ void Poll::draw(Painter &p, const QRect &r, TextSelection selection, crl::time m
|
||||
: nullptr;
|
||||
if (animation) {
|
||||
animation->percent.update(progress, anim::linear);
|
||||
animation->filling.update(progress, anim::linear);
|
||||
animation->filling.update(
|
||||
progress,
|
||||
showVotes() ? anim::easeOutCirc : anim::linear);
|
||||
animation->opacity.update(progress, anim::linear);
|
||||
}
|
||||
const auto height = paintAnswer(
|
||||
|
||||
@@ -247,7 +247,7 @@ rpl::producer<int> AdminsCountValue(not_null<PeerData*> peer) {
|
||||
) | rpl::map([=] {
|
||||
return chat->participants.empty()
|
||||
? 0
|
||||
: int(chat->admins.size() + 1); // + creator
|
||||
: int(chat->admins.size() + (chat->creator ? 1 : 0));
|
||||
});
|
||||
} else if (const auto channel = peer->asChannel()) {
|
||||
return peer->session().changes().peerFlagsValue(
|
||||
|
||||
@@ -7,8 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "main/main_account.h"
|
||||
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "core/application.h"
|
||||
#include "core/launcher.h"
|
||||
#include "core/shortcuts.h"
|
||||
#include "storage/storage_account.h"
|
||||
#include "storage/storage_domain.h" // Storage::StartResult.
|
||||
@@ -386,8 +386,8 @@ void Account::startMtp(std::unique_ptr<MTP::Config> config) {
|
||||
|
||||
auto fields = base::take(_mtpFields);
|
||||
fields.config = std::move(config);
|
||||
fields.deviceModel = Core::App().launcher()->deviceModel();
|
||||
fields.systemVersion = Core::App().launcher()->systemVersion();
|
||||
fields.deviceModel = Platform::DeviceModelPretty();
|
||||
fields.systemVersion = Platform::SystemVersionPretty();
|
||||
_mtp = std::make_unique<MTP::Instance>(
|
||||
MTP::Instance::Mode::Normal,
|
||||
std::move(fields));
|
||||
@@ -534,8 +534,8 @@ void Account::destroyMtpKeys(MTP::AuthKeysList &&keys) {
|
||||
destroyFields.mainDcId = MTP::Instance::Fields::kNoneMainDc;
|
||||
destroyFields.config = std::make_unique<MTP::Config>(_mtp->config());
|
||||
destroyFields.keys = std::move(keys);
|
||||
destroyFields.deviceModel = Core::App().launcher()->deviceModel();
|
||||
destroyFields.systemVersion = Core::App().launcher()->systemVersion();
|
||||
destroyFields.deviceModel = Platform::DeviceModelPretty();
|
||||
destroyFields.systemVersion = Platform::SystemVersionPretty();
|
||||
_mtpForKeysDestroy = std::make_unique<MTP::Instance>(
|
||||
MTP::Instance::Mode::KeysDestroyer,
|
||||
std::move(destroyFields));
|
||||
|
||||
@@ -360,6 +360,7 @@ OverlayWidget::OverlayWidget()
|
||||
setWindowFlags(Qt::FramelessWindowHint);
|
||||
}
|
||||
updateGeometry();
|
||||
updateControlsGeometry();
|
||||
setAttribute(Qt::WA_NoSystemBackground, true);
|
||||
setAttribute(Qt::WA_TranslucentBackground, true);
|
||||
setMouseTracking(true);
|
||||
@@ -446,17 +447,16 @@ void OverlayWidget::moveToScreen() {
|
||||
: nullptr;
|
||||
const auto activeWindowScreen = widgetScreen(window);
|
||||
const auto myScreen = widgetScreen(this);
|
||||
// Wayland doesn't support positioning, but Qt emits screenChanged anyway
|
||||
// and geometry of the widget become broken
|
||||
if (activeWindowScreen
|
||||
&& myScreen != activeWindowScreen
|
||||
&& !Platform::IsWayland()) {
|
||||
if (activeWindowScreen && myScreen != activeWindowScreen) {
|
||||
windowHandle()->setScreen(activeWindowScreen);
|
||||
}
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void OverlayWidget::updateGeometry() {
|
||||
if (!Platform::IsMac()) {
|
||||
return;
|
||||
}
|
||||
const auto screen = windowHandle() && windowHandle()->screen()
|
||||
? windowHandle()->screen()
|
||||
: QApplication::primaryScreen();
|
||||
@@ -465,7 +465,13 @@ void OverlayWidget::updateGeometry() {
|
||||
return;
|
||||
}
|
||||
setGeometry(available);
|
||||
}
|
||||
|
||||
void OverlayWidget::resizeEvent(QResizeEvent *e) {
|
||||
updateControlsGeometry();
|
||||
}
|
||||
|
||||
void OverlayWidget::updateControlsGeometry() {
|
||||
auto navSkip = 2 * st::mediaviewControlMargin + st::mediaviewControlSize;
|
||||
_closeNav = myrtlrect(width() - st::mediaviewControlMargin - st::mediaviewControlSize, st::mediaviewControlMargin, st::mediaviewControlSize, st::mediaviewControlSize);
|
||||
_closeNavIcon = style::centerrect(_closeNav, st::mediaviewClose);
|
||||
@@ -478,6 +484,7 @@ void OverlayWidget::updateGeometry() {
|
||||
_photoRadialRect = QRect(QPoint((width() - st::radialSize.width()) / 2, (height() - st::radialSize.height()) / 2), st::radialSize);
|
||||
|
||||
resizeContentByScreenSize();
|
||||
updateControls();
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -2443,7 +2450,9 @@ bool OverlayWidget::initStreaming(bool continueStreaming) {
|
||||
void OverlayWidget::startStreamingPlayer() {
|
||||
Expects(_streamed != nullptr);
|
||||
|
||||
if (_streamed->instance.player().playing()) {
|
||||
if (!_streamed->instance.player().paused()
|
||||
&& !_streamed->instance.player().finished()
|
||||
&& !_streamed->instance.player().failed()) {
|
||||
if (!_streamed->withSound) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -55,10 +55,14 @@ class Pip;
|
||||
#define USE_OPENGL_OVERLAY_WIDGET
|
||||
#endif // Q_OS_MAC && !OS_MAC_OLD
|
||||
|
||||
struct OverlayParentTraits : Ui::RpWidgetDefaultTraits {
|
||||
static constexpr bool kSetZeroGeometry = false;
|
||||
};
|
||||
|
||||
#ifdef USE_OPENGL_OVERLAY_WIDGET
|
||||
using OverlayParent = Ui::RpWidgetWrap<QOpenGLWidget>;
|
||||
using OverlayParent = Ui::RpWidgetWrap<QOpenGLWidget, OverlayParentTraits>;
|
||||
#else // USE_OPENGL_OVERLAY_WIDGET
|
||||
using OverlayParent = Ui::RpWidget;
|
||||
using OverlayParent = Ui::RpWidgetWrap<QWidget, OverlayParentTraits>;
|
||||
#endif // USE_OPENGL_OVERLAY_WIDGET
|
||||
|
||||
class OverlayWidget final
|
||||
@@ -166,6 +170,7 @@ private:
|
||||
};
|
||||
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
void wheelEvent(QWheelEvent *e) override;
|
||||
@@ -270,6 +275,7 @@ private:
|
||||
void updateDocSize();
|
||||
void updateControls();
|
||||
void updateActions();
|
||||
void updateControlsGeometry();
|
||||
void resizeCenteredControls();
|
||||
void resizeContentByScreenSize();
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ QByteArray DnsUserAgent() {
|
||||
static const auto kResult = QByteArray(
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
||||
"Chrome/86.0.4240.198 Safari/537.36");
|
||||
"Chrome/87.0.4280.88 Safari/537.36");
|
||||
return kResult;
|
||||
}
|
||||
|
||||
|
||||
@@ -1479,9 +1479,8 @@ Link::Link(
|
||||
int32 tw = 0, th = 0;
|
||||
if (_page && _page->photo) {
|
||||
const auto photo = _page->photo;
|
||||
if (photo->inlineThumbnailBytes().isEmpty()
|
||||
&& (photo->hasExact(Data::PhotoSize::Small)
|
||||
|| photo->hasExact(Data::PhotoSize::Thumbnail))) {
|
||||
if (photo->hasExact(Data::PhotoSize::Small)
|
||||
|| photo->hasExact(Data::PhotoSize::Thumbnail)) {
|
||||
photo->load(Data::PhotoSize::Small, parent->fullId());
|
||||
}
|
||||
tw = style::ConvertScale(photo->width());
|
||||
@@ -1623,7 +1622,7 @@ void Link::paint(Painter &p, const QRect &clip, TextSelection selection, const P
|
||||
}
|
||||
|
||||
void Link::validateThumbnail() {
|
||||
if (!_thumbnail.isNull()) {
|
||||
if (!_thumbnail.isNull() && !_thumbnailBlurred) {
|
||||
return;
|
||||
}
|
||||
if (_page && _page->photo) {
|
||||
@@ -1631,12 +1630,16 @@ void Link::validateThumbnail() {
|
||||
ensurePhotoMediaCreated();
|
||||
if (const auto thumbnail = _photoMedia->image(PhotoSize::Thumbnail)) {
|
||||
_thumbnail = thumbnail->pixSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
|
||||
_thumbnailBlurred = false;
|
||||
} else if (const auto large = _photoMedia->image(PhotoSize::Large)) {
|
||||
_thumbnail = large->pixSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
|
||||
_thumbnailBlurred = false;
|
||||
} else if (const auto small = _photoMedia->image(PhotoSize::Small)) {
|
||||
_thumbnail = small->pixSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
|
||||
_thumbnailBlurred = false;
|
||||
} else if (const auto blurred = _photoMedia->thumbnailInline()) {
|
||||
_thumbnail = blurred->pixBlurredSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@@ -1644,14 +1647,20 @@ void Link::validateThumbnail() {
|
||||
delegate()->unregisterHeavyItem(this);
|
||||
} else if (_page && _page->document && _page->document->hasThumbnail()) {
|
||||
ensureDocumentMediaCreated();
|
||||
const auto roundRadius = _page->document->isVideoMessage()
|
||||
? ImageRoundRadius::Ellipse
|
||||
: ImageRoundRadius::Small;
|
||||
if (const auto thumbnail = _documentMedia->thumbnail()) {
|
||||
auto roundRadius = _page->document->isVideoMessage()
|
||||
? ImageRoundRadius::Ellipse
|
||||
: ImageRoundRadius::Small;
|
||||
_thumbnail = thumbnail->pixSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, roundRadius);
|
||||
_documentMedia = nullptr;
|
||||
delegate()->unregisterHeavyItem(this);
|
||||
_thumbnailBlurred = false;
|
||||
} else if (const auto blurred = _documentMedia->thumbnailInline()) {
|
||||
_thumbnail = blurred->pixBlurredSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, roundRadius);
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
_documentMedia = nullptr;
|
||||
delegate()->unregisterHeavyItem(this);
|
||||
} else {
|
||||
const auto size = QSize(st::linksPhotoSize, st::linksPhotoSize);
|
||||
_thumbnail = QPixmap(size * cIntRetinaFactor());
|
||||
@@ -1683,6 +1692,7 @@ void Link::validateThumbnail() {
|
||||
_letter,
|
||||
style::al_center);
|
||||
}
|
||||
_thumbnailBlurred = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -368,6 +368,7 @@ private:
|
||||
int _pixh = 0;
|
||||
Ui::Text::String _text = { st::msgMinWidth };
|
||||
QPixmap _thumbnail;
|
||||
bool _thumbnailBlurred = true;
|
||||
|
||||
struct LinkEntry {
|
||||
LinkEntry() : width(0) {
|
||||
|
||||
@@ -45,45 +45,95 @@ bool ShowOpenWithSupported() {
|
||||
&& (Libs::gtk_app_chooser_dialog_new != nullptr)
|
||||
&& (Libs::gtk_app_chooser_get_app_info != nullptr)
|
||||
&& (Libs::gtk_app_chooser_get_type != nullptr)
|
||||
&& (Libs::gtk_widget_get_type != nullptr)
|
||||
&& (Libs::gtk_widget_get_window != nullptr)
|
||||
&& (Libs::gtk_widget_realize != nullptr)
|
||||
&& (Libs::gtk_widget_show != nullptr)
|
||||
&& (Libs::gtk_widget_destroy != nullptr);
|
||||
}
|
||||
|
||||
void HandleAppChooserResponse(
|
||||
GtkDialog *dialog,
|
||||
int responseId,
|
||||
GFile *file) {
|
||||
class OpenWithDialog : public QWindow {
|
||||
public:
|
||||
OpenWithDialog(const QString &filepath);
|
||||
~OpenWithDialog();
|
||||
|
||||
bool exec();
|
||||
|
||||
private:
|
||||
static void handleResponse(OpenWithDialog *dialog, int responseId);
|
||||
|
||||
GFile *_gfileInstance = nullptr;
|
||||
GtkWidget *_gtkWidget = nullptr;
|
||||
QEventLoop _loop;
|
||||
std::optional<bool> _result = std::nullopt;
|
||||
};
|
||||
|
||||
OpenWithDialog::OpenWithDialog(const QString &filepath)
|
||||
: _gfileInstance(g_file_new_for_path(filepath.toUtf8()))
|
||||
, _gtkWidget(Libs::gtk_app_chooser_dialog_new(
|
||||
nullptr,
|
||||
GTK_DIALOG_MODAL,
|
||||
_gfileInstance)) {
|
||||
g_signal_connect_swapped(
|
||||
_gtkWidget,
|
||||
"response",
|
||||
G_CALLBACK(handleResponse),
|
||||
this);
|
||||
}
|
||||
|
||||
OpenWithDialog::~OpenWithDialog() {
|
||||
Libs::gtk_widget_destroy(_gtkWidget);
|
||||
g_object_unref(_gfileInstance);
|
||||
}
|
||||
|
||||
bool OpenWithDialog::exec() {
|
||||
Libs::gtk_widget_realize(_gtkWidget);
|
||||
|
||||
if (const auto activeWindow = Core::App().activeWindow()) {
|
||||
Platform::internal::XSetTransientForHint(
|
||||
Libs::gtk_widget_get_window(_gtkWidget),
|
||||
activeWindow->widget().get()->windowHandle()->winId());
|
||||
}
|
||||
|
||||
QGuiApplicationPrivate::showModalWindow(this);
|
||||
Libs::gtk_widget_show(_gtkWidget);
|
||||
|
||||
if (!_result.has_value()) {
|
||||
_loop.exec();
|
||||
}
|
||||
|
||||
QGuiApplicationPrivate::hideModalWindow(this);
|
||||
return *_result;
|
||||
}
|
||||
|
||||
void OpenWithDialog::handleResponse(OpenWithDialog *dialog, int responseId) {
|
||||
GAppInfo *chosenAppInfo = nullptr;
|
||||
dialog->_result = true;
|
||||
|
||||
switch (responseId) {
|
||||
case GTK_RESPONSE_OK:
|
||||
chosenAppInfo = Libs::gtk_app_chooser_get_app_info(
|
||||
Libs::gtk_app_chooser_cast(dialog));
|
||||
Libs::gtk_app_chooser_cast(dialog->_gtkWidget));
|
||||
|
||||
if (chosenAppInfo) {
|
||||
GList *uris = nullptr;
|
||||
uris = g_list_prepend(uris, g_file_get_uri(file));
|
||||
uris = g_list_prepend(uris, g_file_get_uri(dialog->_gfileInstance));
|
||||
g_app_info_launch_uris(chosenAppInfo, uris, nullptr, nullptr);
|
||||
g_list_free(uris);
|
||||
g_object_unref(chosenAppInfo);
|
||||
}
|
||||
|
||||
g_object_unref(file);
|
||||
Libs::gtk_widget_destroy(Libs::gtk_widget_cast(dialog));
|
||||
break;
|
||||
|
||||
case GTK_RESPONSE_CANCEL:
|
||||
case GTK_RESPONSE_DELETE_EVENT:
|
||||
g_object_unref(file);
|
||||
Libs::gtk_widget_destroy(Libs::gtk_widget_cast(dialog));
|
||||
break;
|
||||
|
||||
default:
|
||||
dialog->_result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
dialog->_loop.quit();
|
||||
}
|
||||
#endif // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
|
||||
@@ -141,30 +191,7 @@ bool UnsafeShowOpenWith(const QString &filepath) {
|
||||
}
|
||||
|
||||
const auto absolutePath = QFileInfo(filepath).absoluteFilePath();
|
||||
auto gfileInstance = g_file_new_for_path(absolutePath.toUtf8());
|
||||
|
||||
auto appChooserDialog = Libs::gtk_app_chooser_dialog_new(
|
||||
nullptr,
|
||||
GTK_DIALOG_MODAL,
|
||||
gfileInstance);
|
||||
|
||||
g_signal_connect(
|
||||
appChooserDialog,
|
||||
"response",
|
||||
G_CALLBACK(HandleAppChooserResponse),
|
||||
gfileInstance);
|
||||
|
||||
Libs::gtk_widget_realize(appChooserDialog);
|
||||
|
||||
if (const auto activeWindow = Core::App().activeWindow()) {
|
||||
Platform::internal::XSetTransientForHint(
|
||||
Libs::gtk_widget_get_window(appChooserDialog),
|
||||
activeWindow->widget().get()->windowHandle()->winId());
|
||||
}
|
||||
|
||||
Libs::gtk_widget_show(appChooserDialog);
|
||||
|
||||
return true;
|
||||
return OpenWithDialog(absolutePath).exec();
|
||||
#else // !TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
return false;
|
||||
#endif // TDESKTOP_DISABLE_GTK_INTEGRATION
|
||||
|
||||
@@ -7,7 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "platform/linux/launcher_linux.h"
|
||||
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "platform/linux/specific_linux.h"
|
||||
#include "core/crash_reports.h"
|
||||
#include "core/update_checker.h"
|
||||
@@ -46,7 +45,7 @@ private:
|
||||
} // namespace
|
||||
|
||||
Launcher::Launcher(int argc, char *argv[])
|
||||
: Core::Launcher(argc, argv, DeviceModelPretty(), SystemVersionPretty()) {
|
||||
: Core::Launcher(argc, argv) {
|
||||
}
|
||||
|
||||
void Launcher::initHook() {
|
||||
|
||||
@@ -9,8 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "platform/linux/linux_gdk_helper.h"
|
||||
|
||||
#include "platform/linux/linux_libs.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "base/platform/linux/base_xcb_utilities_linux.h"
|
||||
|
||||
extern "C" {
|
||||
#undef signals
|
||||
@@ -33,6 +31,9 @@ GtkLoaded gdk_helper_loaded = GtkLoaded::GtkNone;
|
||||
#define GdkDrawable GdkWindow
|
||||
|
||||
// Gtk 2
|
||||
using f_gdk_x11_drawable_get_xdisplay = Display*(*)(GdkDrawable*);
|
||||
f_gdk_x11_drawable_get_xdisplay gdk_x11_drawable_get_xdisplay = nullptr;
|
||||
|
||||
using f_gdk_x11_drawable_get_xid = XID(*)(GdkDrawable*);
|
||||
f_gdk_x11_drawable_get_xid gdk_x11_drawable_get_xid = nullptr;
|
||||
|
||||
@@ -46,6 +47,12 @@ inline bool gdk_is_x11_window_check(Object *obj) {
|
||||
return Libs::g_type_cit_helper(obj, gdk_x11_window_get_type());
|
||||
}
|
||||
|
||||
using f_gdk_window_get_display = GdkDisplay*(*)(GdkWindow *window);
|
||||
f_gdk_window_get_display gdk_window_get_display = nullptr;
|
||||
|
||||
using f_gdk_x11_display_get_xdisplay = Display*(*)(GdkDisplay *display);
|
||||
f_gdk_x11_display_get_xdisplay gdk_x11_display_get_xdisplay = nullptr;
|
||||
|
||||
using f_gdk_x11_window_get_xid = Window(*)(GdkWindow *window);
|
||||
f_gdk_x11_window_get_xid gdk_x11_window_get_xid = nullptr;
|
||||
|
||||
@@ -53,6 +60,7 @@ bool GdkHelperLoadGtk2(QLibrary &lib) {
|
||||
#if defined DESKTOP_APP_USE_PACKAGED && !defined DESKTOP_APP_USE_PACKAGED_LAZY
|
||||
return false;
|
||||
#else // DESKTOP_APP_USE_PACKAGED && !DESKTOP_APP_USE_PACKAGED_LAZY
|
||||
if (!LOAD_SYMBOL(lib, "gdk_x11_drawable_get_xdisplay", gdk_x11_drawable_get_xdisplay)) return false;
|
||||
if (!LOAD_SYMBOL(lib, "gdk_x11_drawable_get_xid", gdk_x11_drawable_get_xid)) return false;
|
||||
return true;
|
||||
#endif // !DESKTOP_APP_USE_PACKAGED || DESKTOP_APP_USE_PACKAGED_LAZY
|
||||
@@ -60,6 +68,8 @@ bool GdkHelperLoadGtk2(QLibrary &lib) {
|
||||
|
||||
bool GdkHelperLoadGtk3(QLibrary &lib) {
|
||||
if (!LOAD_SYMBOL(lib, "gdk_x11_window_get_type", gdk_x11_window_get_type)) return false;
|
||||
if (!LOAD_SYMBOL(lib, "gdk_window_get_display", gdk_window_get_display)) return false;
|
||||
if (!LOAD_SYMBOL(lib, "gdk_x11_display_get_xdisplay", gdk_x11_display_get_xdisplay)) return false;
|
||||
if (!LOAD_SYMBOL(lib, "gdk_x11_window_get_xid", gdk_x11_window_get_xid)) return false;
|
||||
return true;
|
||||
}
|
||||
@@ -79,28 +89,14 @@ bool GdkHelperLoaded() {
|
||||
|
||||
void XSetTransientForHint(GdkWindow *window, quintptr winId) {
|
||||
if (gdk_helper_loaded == GtkLoaded::Gtk2) {
|
||||
if (!IsWayland()) {
|
||||
xcb_change_property(
|
||||
base::Platform::XCB::GetConnectionFromQt(),
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
gdk_x11_drawable_get_xid(window),
|
||||
XCB_ATOM_WM_TRANSIENT_FOR,
|
||||
XCB_ATOM_WINDOW,
|
||||
32,
|
||||
1,
|
||||
&winId);
|
||||
}
|
||||
::XSetTransientForHint(gdk_x11_drawable_get_xdisplay(window),
|
||||
gdk_x11_drawable_get_xid(window),
|
||||
winId);
|
||||
} else if (gdk_helper_loaded == GtkLoaded::Gtk3) {
|
||||
if (!IsWayland() && gdk_is_x11_window_check(window)) {
|
||||
xcb_change_property(
|
||||
base::Platform::XCB::GetConnectionFromQt(),
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
gdk_x11_window_get_xid(window),
|
||||
XCB_ATOM_WM_TRANSIENT_FOR,
|
||||
XCB_ATOM_WINDOW,
|
||||
32,
|
||||
1,
|
||||
&winId);
|
||||
if (gdk_is_x11_window_check(window)) {
|
||||
::XSetTransientForHint(gdk_x11_display_get_xdisplay(gdk_window_get_display(window)),
|
||||
gdk_x11_window_get_xid(window),
|
||||
winId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
182
Telegram/SourceFiles/platform/linux/linux_gsd_media_keys.cpp
Normal file
182
Telegram/SourceFiles/platform/linux/linux_gsd_media_keys.cpp
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
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 "platform/linux/linux_gsd_media_keys.h"
|
||||
|
||||
#include "core/sandbox.h"
|
||||
#include "media/player/media_player_instance.h"
|
||||
|
||||
#include <QtDBus/QDBusConnection>
|
||||
#include <QtDBus/QDBusConnectionInterface>
|
||||
|
||||
extern "C" {
|
||||
#undef signals
|
||||
#include <gio/gio.h>
|
||||
#define signals public
|
||||
} // extern "C"
|
||||
|
||||
namespace Platform {
|
||||
namespace internal {
|
||||
namespace {
|
||||
|
||||
constexpr auto kDBusTimeout = 30000;
|
||||
constexpr auto kService = "org.gnome.SettingsDaemon.MediaKeys"_cs;
|
||||
constexpr auto kOldService = "org.gnome.SettingsDaemon"_cs;
|
||||
constexpr auto kMATEService = "org.mate.SettingsDaemon"_cs;
|
||||
constexpr auto kObjectPath = "/org/gnome/SettingsDaemon/MediaKeys"_cs;
|
||||
constexpr auto kMATEObjectPath = "/org/mate/SettingsDaemon/MediaKeys"_cs;
|
||||
constexpr auto kInterface = kService;
|
||||
constexpr auto kMATEInterface = "org.mate.SettingsDaemon.MediaKeys"_cs;
|
||||
|
||||
void KeyPressed(
|
||||
GDBusConnection *connection,
|
||||
const gchar *sender_name,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
gpointer user_data) {
|
||||
gchar *appUtf8;
|
||||
gchar *keyUtf8;
|
||||
g_variant_get(parameters, "(ss)", &appUtf8, &keyUtf8);
|
||||
const auto app = QString::fromUtf8(appUtf8);
|
||||
const auto key = QString::fromUtf8(keyUtf8);
|
||||
g_free(keyUtf8);
|
||||
g_free(appUtf8);
|
||||
|
||||
if (app != QCoreApplication::applicationName()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
|
||||
if (key == qstr("Play")) {
|
||||
Media::Player::instance()->playPause();
|
||||
} else if (key == qstr("Stop")) {
|
||||
Media::Player::instance()->stop();
|
||||
} else if (key == qstr("Next")) {
|
||||
Media::Player::instance()->next();
|
||||
} else if (key == qstr("Previous")) {
|
||||
Media::Player::instance()->previous();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
GSDMediaKeys::GSDMediaKeys() {
|
||||
GError *error = nullptr;
|
||||
const auto interface = QDBusConnection::sessionBus().interface();
|
||||
|
||||
if (!interface) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (interface->isServiceRegistered(kService.utf16())) {
|
||||
_service = kService.utf16();
|
||||
_objectPath = kObjectPath.utf16();
|
||||
_interface = kInterface.utf16();
|
||||
} else if (interface->isServiceRegistered(kOldService.utf16())) {
|
||||
_service = kOldService.utf16();
|
||||
_objectPath = kObjectPath.utf16();
|
||||
_interface = kInterface.utf16();
|
||||
} else if (interface->isServiceRegistered(kMATEService.utf16())) {
|
||||
_service = kMATEService.utf16();
|
||||
_objectPath = kMATEObjectPath.utf16();
|
||||
_interface = kMATEInterface.utf16();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
_dbusConnection = g_bus_get_sync(
|
||||
G_BUS_TYPE_SESSION,
|
||||
nullptr,
|
||||
&error);
|
||||
|
||||
if (error) {
|
||||
LOG(("GSD Media Keys Error: %1").arg(error->message));
|
||||
g_error_free(error);
|
||||
return;
|
||||
}
|
||||
|
||||
auto reply = g_dbus_connection_call_sync(
|
||||
_dbusConnection,
|
||||
_service.toUtf8(),
|
||||
_objectPath.toUtf8(),
|
||||
_interface.toUtf8(),
|
||||
"GrabMediaPlayerKeys",
|
||||
g_variant_new(
|
||||
"(su)",
|
||||
QCoreApplication::applicationName().toUtf8().constData(),
|
||||
0),
|
||||
nullptr,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
kDBusTimeout,
|
||||
nullptr,
|
||||
&error);
|
||||
|
||||
if (!error) {
|
||||
_grabbed = true;
|
||||
g_variant_unref(reply);
|
||||
} else {
|
||||
LOG(("GSD Media Keys Error: %1").arg(error->message));
|
||||
g_error_free(error);
|
||||
}
|
||||
|
||||
_signalId = g_dbus_connection_signal_subscribe(
|
||||
_dbusConnection,
|
||||
_service.toUtf8(),
|
||||
_interface.toUtf8(),
|
||||
"MediaPlayerKeyPressed",
|
||||
_objectPath.toUtf8(),
|
||||
nullptr,
|
||||
G_DBUS_SIGNAL_FLAGS_NONE,
|
||||
KeyPressed,
|
||||
nullptr,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
GSDMediaKeys::~GSDMediaKeys() {
|
||||
GError *error = nullptr;
|
||||
|
||||
if (_signalId != 0) {
|
||||
g_dbus_connection_signal_unsubscribe(
|
||||
_dbusConnection,
|
||||
_signalId);
|
||||
}
|
||||
|
||||
if (_grabbed) {
|
||||
auto reply = g_dbus_connection_call_sync(
|
||||
_dbusConnection,
|
||||
_service.toUtf8(),
|
||||
_objectPath.toUtf8(),
|
||||
_interface.toUtf8(),
|
||||
"ReleaseMediaPlayerKeys",
|
||||
g_variant_new(
|
||||
"(s)",
|
||||
QCoreApplication::applicationName().toUtf8().constData()),
|
||||
nullptr,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
kDBusTimeout,
|
||||
nullptr,
|
||||
&error);
|
||||
|
||||
if (!error) {
|
||||
_grabbed = false;
|
||||
g_variant_unref(reply);
|
||||
} else {
|
||||
LOG(("GSD Media Keys Error: %1").arg(error->message));
|
||||
g_error_free(error);
|
||||
}
|
||||
}
|
||||
|
||||
if (_dbusConnection) {
|
||||
g_object_unref(_dbusConnection);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Platform
|
||||
36
Telegram/SourceFiles/platform/linux/linux_gsd_media_keys.h
Normal file
36
Telegram/SourceFiles/platform/linux/linux_gsd_media_keys.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
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
|
||||
|
||||
typedef struct _GDBusConnection GDBusConnection;
|
||||
|
||||
namespace Platform {
|
||||
namespace internal {
|
||||
|
||||
class GSDMediaKeys {
|
||||
public:
|
||||
GSDMediaKeys();
|
||||
|
||||
GSDMediaKeys(const GSDMediaKeys &other) = delete;
|
||||
GSDMediaKeys &operator=(const GSDMediaKeys &other) = delete;
|
||||
GSDMediaKeys(GSDMediaKeys &&other) = delete;
|
||||
GSDMediaKeys &operator=(GSDMediaKeys &&other) = delete;
|
||||
|
||||
~GSDMediaKeys();
|
||||
|
||||
private:
|
||||
GDBusConnection *_dbusConnection = nullptr;
|
||||
QString _service;
|
||||
QString _objectPath;
|
||||
QString _interface;
|
||||
uint _signalId = 0;
|
||||
bool _grabbed = false;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Platform
|
||||
@@ -74,7 +74,6 @@ bool setupGtkBase(QLibrary &lib_gtk) {
|
||||
if (!LOAD_SYMBOL(lib_gtk, "gtk_widget_realize", gtk_widget_realize)) return false;
|
||||
if (!LOAD_SYMBOL(lib_gtk, "gtk_widget_hide_on_delete", gtk_widget_hide_on_delete)) return false;
|
||||
if (!LOAD_SYMBOL(lib_gtk, "gtk_widget_destroy", gtk_widget_destroy)) return false;
|
||||
if (!LOAD_SYMBOL(lib_gtk, "gtk_widget_get_type", gtk_widget_get_type)) return false;
|
||||
if (!LOAD_SYMBOL(lib_gtk, "gtk_clipboard_get", gtk_clipboard_get)) return false;
|
||||
if (!LOAD_SYMBOL(lib_gtk, "gtk_clipboard_store", gtk_clipboard_store)) return false;
|
||||
if (!LOAD_SYMBOL(lib_gtk, "gtk_clipboard_wait_for_contents", gtk_clipboard_wait_for_contents)) return false;
|
||||
@@ -236,7 +235,6 @@ f_gtk_widget_get_window gtk_widget_get_window = nullptr;
|
||||
f_gtk_widget_realize gtk_widget_realize = nullptr;
|
||||
f_gtk_widget_hide_on_delete gtk_widget_hide_on_delete = nullptr;
|
||||
f_gtk_widget_destroy gtk_widget_destroy = nullptr;
|
||||
f_gtk_widget_get_type gtk_widget_get_type = nullptr;
|
||||
f_gtk_clipboard_get gtk_clipboard_get = nullptr;
|
||||
f_gtk_clipboard_store gtk_clipboard_store = nullptr;
|
||||
f_gtk_clipboard_wait_for_contents gtk_clipboard_wait_for_contents = nullptr;
|
||||
|
||||
@@ -235,14 +235,6 @@ inline GtkWindow *gtk_window_cast(Object *obj) {
|
||||
return g_type_cic_helper<GtkWindow, Object>(obj, gtk_window_get_type());
|
||||
}
|
||||
|
||||
typedef GType (*f_gtk_widget_get_type)(void) G_GNUC_CONST;
|
||||
extern f_gtk_widget_get_type gtk_widget_get_type;
|
||||
|
||||
template <typename Object>
|
||||
inline GtkWidget *gtk_widget_cast(Object *obj) {
|
||||
return g_type_cic_helper<GtkWidget, Object>(obj, gtk_widget_get_type());
|
||||
}
|
||||
|
||||
typedef GType (*f_gtk_app_chooser_get_type)(void) G_GNUC_CONST;
|
||||
extern f_gtk_app_chooser_get_type gtk_app_chooser_get_type;
|
||||
|
||||
|
||||
@@ -15,11 +15,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <private/qwaylandwindow_p.h>
|
||||
#include <private/qwaylandshellsurface_p.h>
|
||||
|
||||
#include <connection_thread.h>
|
||||
#include <registry.h>
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) && !defined DESKTOP_APP_QT_PATCHED
|
||||
#include <wayland-client.h>
|
||||
#endif // Qt < 5.13 && !DESKTOP_APP_QT_PATCHED
|
||||
|
||||
using QtWaylandClient::QWaylandWindow;
|
||||
using namespace KWayland::Client;
|
||||
|
||||
namespace Platform {
|
||||
namespace internal {
|
||||
@@ -51,15 +55,75 @@ enum wl_shell_surface_resize WlResizeFromEdges(Qt::Edges edges) {
|
||||
|
||||
} // namespace
|
||||
|
||||
WaylandIntegration::WaylandIntegration() {
|
||||
class WaylandIntegration::Private : public QObject {
|
||||
public:
|
||||
Private();
|
||||
|
||||
[[nodiscard]] Registry ®istry() {
|
||||
return _registry;
|
||||
}
|
||||
|
||||
[[nodiscard]] QEventLoop &interfacesLoop() {
|
||||
return _interfacesLoop;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool interfacesAnnounced() const {
|
||||
return _interfacesAnnounced;
|
||||
}
|
||||
|
||||
private:
|
||||
ConnectionThread _connection;
|
||||
Registry _registry;
|
||||
QEventLoop _interfacesLoop;
|
||||
bool _interfacesAnnounced = false;
|
||||
};
|
||||
|
||||
WaylandIntegration::Private::Private() {
|
||||
connect(&_connection, &ConnectionThread::connected, [=] {
|
||||
LOG(("Successfully connected to Wayland server at socket: %1")
|
||||
.arg(_connection.socketName()));
|
||||
|
||||
_registry.create(&_connection);
|
||||
_registry.setup();
|
||||
});
|
||||
|
||||
connect(
|
||||
&_connection,
|
||||
&ConnectionThread::connectionDied,
|
||||
&_registry,
|
||||
&Registry::destroy);
|
||||
|
||||
connect(&_registry, &Registry::interfacesAnnounced, [=] {
|
||||
_interfacesAnnounced = true;
|
||||
_interfacesLoop.quit();
|
||||
});
|
||||
|
||||
_connection.initConnection();
|
||||
}
|
||||
|
||||
WaylandIntegration::WaylandIntegration()
|
||||
: _private(std::make_unique<Private>()) {
|
||||
}
|
||||
|
||||
WaylandIntegration::~WaylandIntegration() = default;
|
||||
|
||||
WaylandIntegration *WaylandIntegration::Instance() {
|
||||
if (!IsWayland()) return nullptr;
|
||||
static WaylandIntegration instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
void WaylandIntegration::waitForInterfaceAnnounce() {
|
||||
if (!_private->interfacesAnnounced()) {
|
||||
_private->interfacesLoop().exec();
|
||||
}
|
||||
}
|
||||
|
||||
bool WaylandIntegration::supportsXdgDecoration() {
|
||||
return _private->registry().hasInterface(
|
||||
Registry::Interface::XdgDecorationUnstableV1);
|
||||
}
|
||||
|
||||
bool WaylandIntegration::startMove(QWindow *window) {
|
||||
// There are startSystemMove on Qt 5.15
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) && !defined DESKTOP_APP_QT_PATCHED
|
||||
|
||||
@@ -15,12 +15,18 @@ namespace internal {
|
||||
class WaylandIntegration {
|
||||
public:
|
||||
static WaylandIntegration *Instance();
|
||||
void waitForInterfaceAnnounce();
|
||||
bool supportsXdgDecoration();
|
||||
bool startMove(QWindow *window);
|
||||
bool startResize(QWindow *window, Qt::Edges edges);
|
||||
bool showWindowMenu(QWindow *window);
|
||||
|
||||
private:
|
||||
WaylandIntegration();
|
||||
~WaylandIntegration();
|
||||
|
||||
class Private;
|
||||
const std::unique_ptr<Private> _private;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
@@ -12,15 +12,27 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Platform {
|
||||
namespace internal {
|
||||
|
||||
class WaylandIntegration::Private {
|
||||
};
|
||||
|
||||
WaylandIntegration::WaylandIntegration() {
|
||||
}
|
||||
|
||||
WaylandIntegration::~WaylandIntegration() = default;
|
||||
|
||||
WaylandIntegration *WaylandIntegration::Instance() {
|
||||
if (!IsWayland()) return nullptr;
|
||||
static WaylandIntegration instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
void WaylandIntegration::waitForInterfaceAnnounce() {
|
||||
}
|
||||
|
||||
bool WaylandIntegration::supportsXdgDecoration() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WaylandIntegration::startMove(QWindow *window) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "base/platform/linux/base_xcb_utilities_linux.h"
|
||||
#include "base/call_delayed.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "facades.h"
|
||||
#include "app.h"
|
||||
@@ -34,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <QtGui/QWindow>
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
#include <QtCore/QTemporaryFile>
|
||||
#include <QtDBus/QDBusInterface>
|
||||
#include <QtDBus/QDBusConnection>
|
||||
#include <QtDBus/QDBusConnectionInterface>
|
||||
@@ -41,9 +43,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <QtDBus/QDBusMessage>
|
||||
#include <QtDBus/QDBusReply>
|
||||
#include <QtDBus/QDBusError>
|
||||
#include <QtDBus/QDBusObjectPath>
|
||||
#include <QtDBus/QDBusMetaType>
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
#include <statusnotifieritem.h>
|
||||
#include <dbusmenuexporter.h>
|
||||
|
||||
extern "C" {
|
||||
#undef signals
|
||||
@@ -58,6 +62,7 @@ namespace {
|
||||
constexpr auto kPanelTrayIconName = "telegram-panel"_cs;
|
||||
constexpr auto kMutePanelTrayIconName = "telegram-mute-panel"_cs;
|
||||
constexpr auto kAttentionPanelTrayIconName = "telegram-attention-panel"_cs;
|
||||
|
||||
constexpr auto kPropertiesInterface = "org.freedesktop.DBus.Properties"_cs;
|
||||
constexpr auto kTrayIconFilename = "tdesktop-trayicon-XXXXXX.png"_cs;
|
||||
|
||||
@@ -69,6 +74,8 @@ constexpr auto kAppMenuService = "com.canonical.AppMenu.Registrar"_cs;
|
||||
constexpr auto kAppMenuObjectPath = "/com/canonical/AppMenu/Registrar"_cs;
|
||||
constexpr auto kAppMenuInterface = kAppMenuService;
|
||||
|
||||
constexpr auto kMainMenuObjectPath = "/MenuBar"_cs;
|
||||
|
||||
bool TrayIconMuted = true;
|
||||
int32 TrayIconCount = 0;
|
||||
base::flat_map<int, QImage> TrayIconImageBack;
|
||||
@@ -395,10 +402,8 @@ bool UseUnityCounter() {
|
||||
|
||||
return Result;
|
||||
}
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
bool IsSNIAvailable() {
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
auto message = QDBusMessage::createMethodCall(
|
||||
kSNIWatcherService.utf16(),
|
||||
kSNIWatcherObjectPath.utf16(),
|
||||
@@ -406,7 +411,7 @@ bool IsSNIAvailable() {
|
||||
qsl("Get"));
|
||||
|
||||
message.setArguments({
|
||||
kSNIWatcherService.utf16(),
|
||||
kSNIWatcherInterface.utf16(),
|
||||
qsl("IsStatusNotifierHostRegistered")
|
||||
});
|
||||
|
||||
@@ -418,7 +423,6 @@ bool IsSNIAvailable() {
|
||||
} else if (reply.error().type() != QDBusError::ServiceUnknown) {
|
||||
LOG(("SNI Error: %1").arg(reply.error().message()));
|
||||
}
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -432,7 +436,6 @@ quint32 djbStringHash(QString string) {
|
||||
return hash;
|
||||
}
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
bool IsAppMenuSupported() {
|
||||
const auto interface = QDBusConnection::sessionBus().interface();
|
||||
|
||||
@@ -443,7 +446,7 @@ bool IsAppMenuSupported() {
|
||||
return interface->isServiceRegistered(kAppMenuService.utf16());
|
||||
}
|
||||
|
||||
void RegisterAppMenu(uint winId, const QDBusObjectPath &menuPath) {
|
||||
void RegisterAppMenu(uint winId, const QString &menuPath) {
|
||||
auto message = QDBusMessage::createMethodCall(
|
||||
kAppMenuService.utf16(),
|
||||
kAppMenuObjectPath.utf16(),
|
||||
@@ -452,7 +455,7 @@ void RegisterAppMenu(uint winId, const QDBusObjectPath &menuPath) {
|
||||
|
||||
message.setArguments({
|
||||
winId,
|
||||
QVariant::fromValue(menuPath)
|
||||
QVariant::fromValue(QDBusObjectPath(menuPath))
|
||||
});
|
||||
|
||||
QDBusConnection::sessionBus().send(message);
|
||||
@@ -505,10 +508,9 @@ MainWindow::MainWindow(not_null<Window::Controller*> controller)
|
||||
}
|
||||
|
||||
void MainWindow::initHook() {
|
||||
_sniAvailable = IsSNIAvailable();
|
||||
LOG(("System tray available: %1").arg(Logs::b(trayAvailable())));
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
_sniAvailable = IsSNIAvailable();
|
||||
|
||||
_sniDBusProxy = g_dbus_proxy_new_for_bus_sync(
|
||||
G_BUS_TYPE_SESSION,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
@@ -574,8 +576,9 @@ void MainWindow::initHook() {
|
||||
}
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
updateWaylandDecorationColors();
|
||||
LOG(("System tray available: %1").arg(Logs::b(trayAvailable())));
|
||||
|
||||
updateWaylandDecorationColors();
|
||||
style::PaletteChanged(
|
||||
) | rpl::start_with_next([=] {
|
||||
updateWaylandDecorationColors();
|
||||
@@ -740,8 +743,8 @@ void MainWindow::handleAppMenuOwnerChanged(
|
||||
LOG(("Not using D-Bus global menu."));
|
||||
}
|
||||
|
||||
if (_appMenuSupported && !_mainMenuPath.path().isEmpty()) {
|
||||
RegisterAppMenu(winId(), _mainMenuPath);
|
||||
if (_appMenuSupported && _mainMenuExporter) {
|
||||
RegisterAppMenu(winId(), kMainMenuObjectPath.utf16());
|
||||
} else {
|
||||
UnregisterAppMenu(winId());
|
||||
}
|
||||
@@ -819,25 +822,28 @@ void MainWindow::updateIconCounters() {
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
if (UseUnityCounter()) {
|
||||
const auto launcherUrl = "application://" + GetLauncherFilename();
|
||||
// Gnome requires that count is a 64bit integer
|
||||
const qint64 counterSlice = std::min(counter, 9999);
|
||||
QVariantMap dbusUnityProperties;
|
||||
if (counter > 0) {
|
||||
// Gnome requires that count is a 64bit integer
|
||||
dbusUnityProperties.insert(
|
||||
"count",
|
||||
(qint64) ((counter > 9999)
|
||||
? 9999
|
||||
: counter));
|
||||
dbusUnityProperties.insert("count-visible", true);
|
||||
|
||||
if (counterSlice > 0) {
|
||||
dbusUnityProperties["count"] = counterSlice;
|
||||
dbusUnityProperties["count-visible"] = true;
|
||||
} else {
|
||||
dbusUnityProperties.insert("count-visible", false);
|
||||
dbusUnityProperties["count-visible"] = false;
|
||||
}
|
||||
QDBusMessage signal = QDBusMessage::createSignal(
|
||||
|
||||
auto signal = QDBusMessage::createSignal(
|
||||
"/com/canonical/unity/launcherentry/"
|
||||
+ QString::number(djbStringHash(launcherUrl)),
|
||||
"com.canonical.Unity.LauncherEntry",
|
||||
"Update");
|
||||
signal << launcherUrl;
|
||||
signal << dbusUnityProperties;
|
||||
|
||||
signal.setArguments({
|
||||
launcherUrl,
|
||||
dbusUnityProperties
|
||||
});
|
||||
|
||||
QDBusConnection::sessionBus().send(signal);
|
||||
}
|
||||
|
||||
@@ -1056,14 +1062,12 @@ void MainWindow::createGlobalMenu() {
|
||||
|
||||
about->setMenuRole(QAction::AboutQtRole);
|
||||
|
||||
_mainMenuPath.setPath(qsl("/MenuBar"));
|
||||
|
||||
_mainMenuExporter = new DBusMenuExporter(
|
||||
_mainMenuPath.path(),
|
||||
kMainMenuObjectPath.utf16(),
|
||||
psMainMenu);
|
||||
|
||||
if (_appMenuSupported) {
|
||||
RegisterAppMenu(winId(), _mainMenuPath);
|
||||
RegisterAppMenu(winId(), kMainMenuObjectPath.utf16());
|
||||
}
|
||||
|
||||
updateGlobalMenu();
|
||||
@@ -1195,9 +1199,9 @@ void MainWindow::handleVisibleChangedHook(bool visible) {
|
||||
}
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
if (_appMenuSupported && !_mainMenuPath.path().isEmpty()) {
|
||||
if (_appMenuSupported && _mainMenuExporter) {
|
||||
if (visible) {
|
||||
RegisterAppMenu(winId(), _mainMenuPath);
|
||||
RegisterAppMenu(winId(), kMainMenuObjectPath.utf16());
|
||||
} else {
|
||||
UnregisterAppMenu(winId());
|
||||
}
|
||||
|
||||
@@ -9,13 +9,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "platform/platform_main_window.h"
|
||||
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
namespace Ui {
|
||||
class PopupMenu;
|
||||
} // namespace Ui
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
#include "statusnotifieritem.h"
|
||||
#include <QtCore/QTemporaryFile>
|
||||
#include <QtDBus/QDBusObjectPath>
|
||||
#include <dbusmenuexporter.h>
|
||||
class QTemporaryFile;
|
||||
class DBusMenuExporter;
|
||||
class StatusNotifierItem;
|
||||
|
||||
typedef void* gpointer;
|
||||
typedef char gchar;
|
||||
@@ -82,11 +83,10 @@ private:
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
StatusNotifierItem *_sniTrayIcon = nullptr;
|
||||
GDBusProxy *_sniDBusProxy = nullptr;
|
||||
std::unique_ptr<QTemporaryFile> _trayIconFile = nullptr;
|
||||
std::unique_ptr<QTemporaryFile> _trayIconFile;
|
||||
|
||||
bool _appMenuSupported = false;
|
||||
DBusMenuExporter *_mainMenuExporter = nullptr;
|
||||
QDBusObjectPath _mainMenuPath;
|
||||
|
||||
QMenu *psMainMenu = nullptr;
|
||||
QAction *psLogout = nullptr;
|
||||
|
||||
@@ -17,7 +17,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "main/main_session.h"
|
||||
#include "lang/lang_keys.h"
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
#include <QtCore/QVersionNumber>
|
||||
#include <QtDBus/QDBusConnection>
|
||||
#include <QtDBus/QDBusMessage>
|
||||
@@ -29,12 +28,9 @@ extern "C" {
|
||||
#include <gio/gio.h>
|
||||
#define signals public
|
||||
} // extern "C"
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
namespace Platform {
|
||||
namespace Notifications {
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
namespace {
|
||||
|
||||
constexpr auto kDBusTimeout = 30000;
|
||||
@@ -615,16 +611,13 @@ void NotificationData::notificationReplied(uint id, const QString &text) {
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
bool SkipAudio() {
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
if (Supported()
|
||||
&& GetCapabilities().contains(qsl("inhibitions"))
|
||||
&& !InhibitedNotSupported) {
|
||||
return Inhibited();
|
||||
}
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -638,18 +631,12 @@ bool SkipFlashBounce() {
|
||||
}
|
||||
|
||||
bool Supported() {
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
return NotificationsSupported;
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<Window::Notifications::Manager> Create(
|
||||
Window::Notifications::System *system) {
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
GetSupported();
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
if ((Core::App().settings().nativeNotifications() && Supported())
|
||||
|| IsWayland()) {
|
||||
@@ -659,27 +646,6 @@ std::unique_ptr<Window::Notifications::Manager> Create(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
class Manager::Private {
|
||||
public:
|
||||
using Type = Window::Notifications::CachedUserpics::Type;
|
||||
explicit Private(not_null<Manager*> manager, Type type) {}
|
||||
|
||||
void showNotification(
|
||||
not_null<PeerData*> peer,
|
||||
std::shared_ptr<Data::CloudImageView> &userpicView,
|
||||
MsgId msgId,
|
||||
const QString &title,
|
||||
const QString &subtitle,
|
||||
const QString &msg,
|
||||
bool hideNameAndPhoto,
|
||||
bool hideReplyButton) {}
|
||||
void clearAll() {}
|
||||
void clearFromHistory(not_null<History*> history) {}
|
||||
void clearFromSession(not_null<Main::Session*> session) {}
|
||||
void clearNotification(NotificationId id) {}
|
||||
};
|
||||
#else // DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
class Manager::Private {
|
||||
public:
|
||||
using Type = Window::Notifications::CachedUserpics::Type;
|
||||
@@ -866,7 +832,6 @@ void Manager::Private::clearNotification(NotificationId id) {
|
||||
Manager::Private::~Private() {
|
||||
clearAll();
|
||||
}
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
Manager::Manager(not_null<Window::Notifications::System*> system)
|
||||
: NativeManager(system)
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
/*
|
||||
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 "platform/linux/notifications_manager_linux.h"
|
||||
|
||||
namespace Platform {
|
||||
namespace Notifications {
|
||||
|
||||
bool SkipAudio() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkipToast() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkipFlashBounce() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Supported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<Window::Notifications::Manager> Create(
|
||||
Window::Notifications::System *system) {
|
||||
if (IsWayland()) {
|
||||
return std::make_unique<Window::Notifications::DummyManager>(system);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace Notifications
|
||||
} // namespace Platform
|
||||
@@ -24,6 +24,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "window/window_controller.h"
|
||||
#include "core/application.h"
|
||||
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
#include "platform/linux/linux_gsd_media_keys.h"
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QDesktopWidget>
|
||||
#include <QtCore/QStandardPaths>
|
||||
@@ -451,25 +455,6 @@ bool ShowXCBWindowMenu(QWindow *window) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XCBFrameExtentsSupported() {
|
||||
const auto connection = base::Platform::XCB::GetConnectionFromQt();
|
||||
if (!connection) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto frameExtentsAtom = base::Platform::XCB::GetAtom(
|
||||
connection,
|
||||
kXCBFrameExtentsAtomName.utf16());
|
||||
|
||||
if (!frameExtentsAtom.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ranges::contains(
|
||||
base::Platform::XCB::GetWMSupported(connection),
|
||||
*frameExtentsAtom);
|
||||
}
|
||||
|
||||
bool SetXCBFrameExtents(QWindow *window, const QMargins &extents) {
|
||||
const auto connection = base::Platform::XCB::GetConnectionFromQt();
|
||||
if (!connection) {
|
||||
@@ -526,25 +511,6 @@ bool UnsetXCBFrameExtents(QWindow *window) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XCBSkipTaskbarSupported() {
|
||||
const auto connection = base::Platform::XCB::GetConnectionFromQt();
|
||||
if (!connection) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto skipTaskbarAtom = base::Platform::XCB::GetAtom(
|
||||
connection,
|
||||
"_NET_WM_STATE_SKIP_TASKBAR");
|
||||
|
||||
if (!skipTaskbarAtom.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ranges::contains(
|
||||
base::Platform::XCB::GetWMSupported(connection),
|
||||
*skipTaskbarAtom);
|
||||
}
|
||||
|
||||
Window::Control GtkKeywordToWindowControl(const QString &keyword) {
|
||||
if (keyword == qstr("minimize")) {
|
||||
return Window::Control::Minimize;
|
||||
@@ -559,6 +525,18 @@ Window::Control GtkKeywordToWindowControl(const QString &keyword) {
|
||||
|
||||
} // namespace
|
||||
|
||||
void SetWatchingMediaKeys(bool watching) {
|
||||
#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
static std::unique_ptr<internal::GSDMediaKeys> Instance;
|
||||
|
||||
if (watching && !Instance) {
|
||||
Instance = std::make_unique<internal::GSDMediaKeys>();
|
||||
} else if (!watching && Instance) {
|
||||
Instance = nullptr;
|
||||
}
|
||||
#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION
|
||||
}
|
||||
|
||||
void SetApplicationIcon(const QIcon &icon) {
|
||||
QApplication::setWindowIcon(icon);
|
||||
}
|
||||
@@ -804,7 +782,8 @@ bool TrayIconSupported() {
|
||||
}
|
||||
|
||||
bool SkipTaskbarSupported() {
|
||||
return !IsWayland() && XCBSkipTaskbarSupported();
|
||||
return !IsWayland()
|
||||
&& base::Platform::XCB::IsSupportedByWM("_NET_WM_STATE_SKIP_TASKBAR");
|
||||
}
|
||||
|
||||
bool StartSystemMove(QWindow *window) {
|
||||
@@ -848,11 +827,8 @@ bool UnsetWindowExtents(QWindow *window) {
|
||||
}
|
||||
|
||||
bool WindowsNeedShadow() {
|
||||
if (!IsWayland() && XCBFrameExtentsSupported()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return !IsWayland()
|
||||
&& base::Platform::XCB::IsSupportedByWM(kXCBFrameExtentsAtomName.utf16());
|
||||
}
|
||||
|
||||
Window::ControlsLayout WindowControlsLayout() {
|
||||
@@ -1250,6 +1226,11 @@ void start() {
|
||||
|
||||
Libs::start();
|
||||
MainWindow::LibsLoaded();
|
||||
|
||||
// wait for interface announce to know if native window frame is supported
|
||||
if (const auto waylandIntegration = WaylandIntegration::Instance()) {
|
||||
waylandIntegration->waitForInterfaceAnnounce();
|
||||
}
|
||||
}
|
||||
|
||||
void finish() {
|
||||
|
||||
@@ -17,9 +17,6 @@ class LocationPoint;
|
||||
|
||||
namespace Platform {
|
||||
|
||||
inline void SetWatchingMediaKeys(bool watching) {
|
||||
}
|
||||
|
||||
bool InFlatpak();
|
||||
bool InSnap();
|
||||
bool IsStaticBinary();
|
||||
|
||||
@@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "platform/linux/window_title_linux.h"
|
||||
|
||||
#include "platform/linux/linux_desktop_environment.h"
|
||||
#include "platform/linux/linux_wayland_integration.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
|
||||
namespace Platform {
|
||||
@@ -24,9 +24,10 @@ bool SystemMoveResizeSupported() {
|
||||
} // namespace
|
||||
|
||||
bool AllowNativeWindowFrameToggle() {
|
||||
const auto waylandIntegration = internal::WaylandIntegration::Instance();
|
||||
return SystemMoveResizeSupported()
|
||||
// https://gitlab.gnome.org/GNOME/mutter/-/issues/217
|
||||
&& !(DesktopEnvironment::IsGnome() && IsWayland());
|
||||
&& (!waylandIntegration
|
||||
|| waylandIntegration->supportsXdgDecoration());
|
||||
}
|
||||
|
||||
object_ptr<Window::TitleWidget> CreateTitleWidget(QWidget *parent) {
|
||||
|
||||
@@ -9,7 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "core/crash_reports.h"
|
||||
#include "core/update_checker.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "base/platform/base_platform_file_utilities.h"
|
||||
#include "base/platform/mac/base_utilities_mac.h"
|
||||
|
||||
@@ -20,7 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Platform {
|
||||
|
||||
Launcher::Launcher(int argc, char *argv[])
|
||||
: Core::Launcher(argc, argv, DeviceModelPretty(), SystemVersionPretty()) {
|
||||
: Core::Launcher(argc, argv) {
|
||||
}
|
||||
|
||||
void Launcher::initHook() {
|
||||
|
||||
@@ -9,7 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "core/crash_reports.h"
|
||||
#include "core/update_checker.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "base/platform/win/base_windows_h.h"
|
||||
|
||||
#include <shellapi.h>
|
||||
@@ -18,7 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Platform {
|
||||
|
||||
Launcher::Launcher(int argc, char *argv[])
|
||||
: Core::Launcher(argc, argv, DeviceModelPretty(), SystemVersionPretty()) {
|
||||
: Core::Launcher(argc, argv) {
|
||||
}
|
||||
|
||||
std::optional<QStringList> Launcher::readArgumentsHook(
|
||||
|
||||
@@ -217,7 +217,11 @@ void MainWindow::psSetupTrayIcon() {
|
||||
auto icon = QIcon(App::pixmapFromImageInPlace(Core::App().logoNoMargin()));
|
||||
|
||||
trayIcon->setIcon(icon);
|
||||
connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(showFromTray()));
|
||||
connect(
|
||||
trayIcon,
|
||||
&QSystemTrayIcon::messageClicked,
|
||||
this,
|
||||
[=] { App::wnd()->showFromTray(); });
|
||||
attachToTrayIcon(trayIcon);
|
||||
}
|
||||
updateIconCounters();
|
||||
|
||||
@@ -30,11 +30,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "webrtc/webrtc_media_devices.h"
|
||||
#include "webrtc/webrtc_video_track.h"
|
||||
#include "webrtc/webrtc_audio_input_tester.h"
|
||||
#include "webrtc/webrtc_create_adm.h" // Webrtc::Backend.
|
||||
#include "tgcalls/VideoCaptureInterface.h"
|
||||
#include "facades.h"
|
||||
#include "app.h" // App::restart().
|
||||
#include "styles/style_layers.h"
|
||||
|
||||
namespace Settings {
|
||||
namespace {
|
||||
|
||||
using namespace Webrtc;
|
||||
|
||||
} // namespace
|
||||
|
||||
Calls::Calls(
|
||||
QWidget *parent,
|
||||
@@ -58,7 +65,7 @@ void Calls::setupContent() {
|
||||
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
|
||||
|
||||
const auto &settings = Core::App().settings();
|
||||
const auto cameras = Webrtc::GetVideoInputList();
|
||||
const auto cameras = GetVideoInputList();
|
||||
if (!cameras.empty()) {
|
||||
const auto hasCall = (Core::App().calls().currentCall() != nullptr);
|
||||
|
||||
@@ -66,16 +73,16 @@ void Calls::setupContent() {
|
||||
const auto capturer = capturerOwner.get();
|
||||
content->lifetime().add([owner = std::move(capturerOwner)]{});
|
||||
|
||||
const auto track = content->lifetime().make_state<Webrtc::VideoTrack>(
|
||||
const auto track = content->lifetime().make_state<VideoTrack>(
|
||||
(hasCall
|
||||
? Webrtc::VideoState::Inactive
|
||||
: Webrtc::VideoState::Active));
|
||||
? VideoState::Inactive
|
||||
: VideoState::Active));
|
||||
|
||||
const auto currentCameraName = [&] {
|
||||
const auto i = ranges::find(
|
||||
cameras,
|
||||
settings.callVideoInputDeviceId(),
|
||||
&Webrtc::VideoInput::id);
|
||||
&VideoInput::id);
|
||||
return (i != end(cameras))
|
||||
? i->name
|
||||
: tr::lng_settings_call_device_default(tr::now);
|
||||
@@ -93,15 +100,15 @@ void Calls::setupContent() {
|
||||
),
|
||||
st::settingsButton
|
||||
)->addClickHandler([=] {
|
||||
const auto &devices = Webrtc::GetVideoInputList();
|
||||
const auto &devices = GetVideoInputList();
|
||||
const auto options = ranges::view::concat(
|
||||
ranges::view::single(tr::lng_settings_call_device_default(tr::now)),
|
||||
devices | ranges::view::transform(&Webrtc::VideoInput::name)
|
||||
devices | ranges::view::transform(&VideoInput::name)
|
||||
) | ranges::to_vector;
|
||||
const auto i = ranges::find(
|
||||
devices,
|
||||
Core::App().settings().callVideoInputDeviceId(),
|
||||
&Webrtc::VideoInput::id);
|
||||
&VideoInput::id);
|
||||
const auto currentOption = (i != end(devices))
|
||||
? int(i - begin(devices) + 1)
|
||||
: 0;
|
||||
@@ -159,11 +166,11 @@ void Calls::setupContent() {
|
||||
Core::App().calls().currentCallValue(
|
||||
) | rpl::start_with_next([=](::Calls::Call *value) {
|
||||
if (value) {
|
||||
track->setState(Webrtc::VideoState::Inactive);
|
||||
track->setState(VideoState::Inactive);
|
||||
bubbleWrap->resize(bubbleWrap->width(), 0);
|
||||
} else {
|
||||
capturer->setPreferredAspectRatio(0.);
|
||||
track->setState(Webrtc::VideoState::Active);
|
||||
track->setState(VideoState::Active);
|
||||
capturer->setOutput(track->sink());
|
||||
}
|
||||
}, content->lifetime());
|
||||
@@ -252,6 +259,22 @@ void Calls::setupContent() {
|
||||
// }, content->lifetime());
|
||||
//#endif // Q_OS_MAC && !OS_MAC_STORE
|
||||
|
||||
const auto backend = [&]() -> QString {
|
||||
using namespace Webrtc;
|
||||
switch (settings.callAudioBackend()) {
|
||||
case Backend::OpenAL: return "OpenAL";
|
||||
case Backend::ADM: return "WebRTC ADM";
|
||||
case Backend::ADM2: return "WebRTC ADM2";
|
||||
}
|
||||
Unexpected("Value in backend.");
|
||||
}();
|
||||
AddButton(
|
||||
content,
|
||||
rpl::single("Call audio backend: " + backend),
|
||||
st::settingsButton
|
||||
)->addClickHandler([] {
|
||||
Ui::show(ChooseAudioBackendBox());
|
||||
});
|
||||
AddButton(
|
||||
content,
|
||||
tr::lng_settings_call_open_system_prefs(),
|
||||
@@ -300,27 +323,30 @@ void Calls::requestPermissionAndStartTestingMicrophone() {
|
||||
|
||||
void Calls::startTestingMicrophone() {
|
||||
_levelUpdateTimer.callEach(kMicTestUpdateInterval);
|
||||
_micTester = std::make_unique<Webrtc::AudioInputTester>(
|
||||
_micTester = std::make_unique<AudioInputTester>(
|
||||
Core::App().settings().callAudioBackend(),
|
||||
Core::App().settings().callInputDeviceId());
|
||||
}
|
||||
|
||||
QString CurrentAudioOutputName() {
|
||||
const auto list = Webrtc::GetAudioOutputList();
|
||||
const auto &settings = Core::App().settings();
|
||||
const auto list = GetAudioOutputList(settings.callAudioBackend());
|
||||
const auto i = ranges::find(
|
||||
list,
|
||||
Core::App().settings().callOutputDeviceId(),
|
||||
&Webrtc::AudioOutput::id);
|
||||
settings.callOutputDeviceId(),
|
||||
&AudioOutput::id);
|
||||
return (i != end(list))
|
||||
? i->name
|
||||
: tr::lng_settings_call_device_default(tr::now);
|
||||
}
|
||||
|
||||
QString CurrentAudioInputName() {
|
||||
const auto list = Webrtc::GetAudioInputList();
|
||||
const auto &settings = Core::App().settings();
|
||||
const auto list = GetAudioInputList(settings.callAudioBackend());
|
||||
const auto i = ranges::find(
|
||||
list,
|
||||
Core::App().settings().callInputDeviceId(),
|
||||
&Webrtc::AudioInput::id);
|
||||
settings.callInputDeviceId(),
|
||||
&AudioInput::id);
|
||||
return (i != end(list))
|
||||
? i->name
|
||||
: tr::lng_settings_call_device_default(tr::now);
|
||||
@@ -330,21 +356,22 @@ object_ptr<SingleChoiceBox> ChooseAudioOutputBox(
|
||||
Fn<void(QString id, QString name)> chosen,
|
||||
const style::Checkbox *st,
|
||||
const style::Radio *radioSt) {
|
||||
const auto &devices = Webrtc::GetAudioOutputList();
|
||||
const auto &settings = Core::App().settings();
|
||||
const auto list = GetAudioOutputList(settings.callAudioBackend());
|
||||
const auto options = ranges::view::concat(
|
||||
ranges::view::single(tr::lng_settings_call_device_default(tr::now)),
|
||||
devices | ranges::view::transform(&Webrtc::AudioOutput::name)
|
||||
list | ranges::view::transform(&AudioOutput::name)
|
||||
) | ranges::to_vector;
|
||||
const auto i = ranges::find(
|
||||
devices,
|
||||
Core::App().settings().callOutputDeviceId(),
|
||||
&Webrtc::AudioOutput::id);
|
||||
const auto currentOption = (i != end(devices))
|
||||
? int(i - begin(devices) + 1)
|
||||
list,
|
||||
settings.callOutputDeviceId(),
|
||||
&AudioOutput::id);
|
||||
const auto currentOption = (i != end(list))
|
||||
? int(i - begin(list) + 1)
|
||||
: 0;
|
||||
const auto save = [=](int option) {
|
||||
const auto deviceId = option
|
||||
? devices[option - 1].id
|
||||
? list[option - 1].id
|
||||
: "default";
|
||||
Core::App().calls().setCurrentAudioDevice(false, deviceId);
|
||||
chosen(deviceId, options[option]);
|
||||
@@ -362,21 +389,22 @@ object_ptr<SingleChoiceBox> ChooseAudioInputBox(
|
||||
Fn<void(QString id, QString name)> chosen,
|
||||
const style::Checkbox *st,
|
||||
const style::Radio *radioSt) {
|
||||
const auto devices = Webrtc::GetAudioInputList();
|
||||
const auto &settings = Core::App().settings();
|
||||
const auto list = GetAudioInputList(settings.callAudioBackend());
|
||||
const auto options = ranges::view::concat(
|
||||
ranges::view::single(tr::lng_settings_call_device_default(tr::now)),
|
||||
devices | ranges::view::transform(&Webrtc::AudioInput::name)
|
||||
list | ranges::view::transform(&AudioInput::name)
|
||||
) | ranges::to_vector;
|
||||
const auto i = ranges::find(
|
||||
devices,
|
||||
list,
|
||||
Core::App().settings().callInputDeviceId(),
|
||||
&Webrtc::AudioInput::id);
|
||||
const auto currentOption = (i != end(devices))
|
||||
? int(i - begin(devices) + 1)
|
||||
&AudioInput::id);
|
||||
const auto currentOption = (i != end(list))
|
||||
? int(i - begin(list) + 1)
|
||||
: 0;
|
||||
const auto save = [=](int option) {
|
||||
const auto deviceId = option
|
||||
? devices[option - 1].id
|
||||
? list[option - 1].id
|
||||
: "default";
|
||||
Core::App().calls().setCurrentAudioDevice(true, deviceId);
|
||||
chosen(deviceId, options[option]);
|
||||
@@ -390,5 +418,33 @@ object_ptr<SingleChoiceBox> ChooseAudioInputBox(
|
||||
radioSt);
|
||||
}
|
||||
|
||||
object_ptr<SingleChoiceBox> ChooseAudioBackendBox(
|
||||
const style::Checkbox *st,
|
||||
const style::Radio *radioSt) {
|
||||
const auto &settings = Core::App().settings();
|
||||
const auto list = GetAudioInputList(settings.callAudioBackend());
|
||||
const auto options = std::vector<QString>{
|
||||
"OpenAL",
|
||||
"Webrtc ADM",
|
||||
#ifdef Q_OS_WIN
|
||||
"Webrtc ADM2",
|
||||
#endif // Q_OS_WIN
|
||||
};
|
||||
const auto currentOption = static_cast<int>(settings.callAudioBackend());
|
||||
const auto save = [=](int option) {
|
||||
Core::App().settings().setCallAudioBackend(
|
||||
static_cast<Webrtc::Backend>(option));
|
||||
Core::App().saveSettings();
|
||||
App::restart();
|
||||
};
|
||||
return Box<SingleChoiceBox>(
|
||||
rpl::single<QString>("Calls audio backend"),
|
||||
options,
|
||||
currentOption,
|
||||
save,
|
||||
st,
|
||||
radioSt);
|
||||
}
|
||||
|
||||
} // namespace Settings
|
||||
|
||||
|
||||
@@ -69,6 +69,9 @@ inline constexpr auto kMicTestAnimationDuration = crl::time(200);
|
||||
Fn<void(QString id, QString name)> chosen,
|
||||
const style::Checkbox *st = nullptr,
|
||||
const style::Radio *radioSt = nullptr);
|
||||
[[nodiscard]] object_ptr<SingleChoiceBox> ChooseAudioBackendBox(
|
||||
const style::Checkbox *st = nullptr,
|
||||
const style::Radio *radioSt = nullptr);
|
||||
|
||||
} // namespace Settings
|
||||
|
||||
|
||||
@@ -73,10 +73,18 @@ object_ptr<Ui::RpWidget> CreateIntroSettings(
|
||||
SetupUpdate(result);
|
||||
AddSkip(result);
|
||||
}
|
||||
AddDivider(result);
|
||||
AddSkip(result);
|
||||
SetupSystemIntegrationContent(result);
|
||||
AddSkip(result);
|
||||
{
|
||||
auto wrap = object_ptr<Ui::VerticalLayout>(result);
|
||||
SetupSystemIntegrationContent(wrap.data());
|
||||
if (wrap->count() > 0) {
|
||||
AddDivider(result);
|
||||
AddSkip(result);
|
||||
result->add(object_ptr<Ui::OverrideMargins>(
|
||||
result,
|
||||
std::move(wrap)));
|
||||
AddSkip(result);
|
||||
}
|
||||
}
|
||||
AddDivider(result);
|
||||
AddSkip(result);
|
||||
SetupInterfaceScale(result, false);
|
||||
|
||||
@@ -248,6 +248,30 @@ protected:
|
||||
|
||||
};
|
||||
|
||||
class DummyManager : public NativeManager {
|
||||
public:
|
||||
using NativeManager::NativeManager;
|
||||
|
||||
protected:
|
||||
void doShowNativeNotification(
|
||||
not_null<PeerData*> peer,
|
||||
std::shared_ptr<Data::CloudImageView> &userpicView,
|
||||
MsgId msgId,
|
||||
const QString &title,
|
||||
const QString &subtitle,
|
||||
const QString &msg,
|
||||
bool hideNameAndPhoto,
|
||||
bool hideReplyButton) override {
|
||||
}
|
||||
void doClearAllFast() override {
|
||||
}
|
||||
void doClearFromHistory(not_null<History*> history) override {
|
||||
}
|
||||
void doClearFromSession(not_null<Main::Session*> session) override {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
QString WrapFromScheduled(const QString &text);
|
||||
|
||||
} // namespace Notifications
|
||||
|
||||
2
Telegram/ThirdParty/libtgvoip
vendored
2
Telegram/ThirdParty/libtgvoip
vendored
Submodule Telegram/ThirdParty/libtgvoip updated: 37d98e984f...13a5fcb16b
2
Telegram/ThirdParty/tgcalls
vendored
2
Telegram/ThirdParty/tgcalls
vendored
Submodule Telegram/ThirdParty/tgcalls updated: cba2d0daa7...bc56b9108a
@@ -1,12 +1,14 @@
|
||||
FROM centos:7 AS builder
|
||||
|
||||
ENV GIT https://github.com
|
||||
ENV PKG_CONFIG_PATH /usr/local/lib/pkgconfig
|
||||
ENV PKG_CONFIG_PATH /usr/local/lib/pkgconfig:/usr/local/share/pkgconfig
|
||||
ENV QT 5_15_2
|
||||
ENV QT_TAG v5.15.2
|
||||
ENV QT_PREFIX /usr/local/desktop-app/Qt-5.15.2
|
||||
ENV OPENSSL_VER 1_1_1
|
||||
ENV OPENSSL_PREFIX /usr/local/desktop-app/openssl-1.1.1
|
||||
ENV PATH ${PATH}:${QT_PREFIX}/bin
|
||||
ENV Qt5_DIR ${QT_PREFIX}
|
||||
|
||||
RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
|
||||
RUN yum -y install https://packages.endpoint.com/rhel/7/os/x86_64/endpoint-repo-1.7-1.x86_64.rpm
|
||||
@@ -27,8 +29,20 @@ ENV LibrariesPath /usr/src/Libraries
|
||||
WORKDIR $LibrariesPath
|
||||
|
||||
FROM builder AS patches
|
||||
RUN git clone $GIT/desktop-app/patches.git
|
||||
RUN cd patches && git checkout 6afd91a
|
||||
ADD https://api.github.com/repos/desktop-app/patches/git/refs/heads/master patches-version.json
|
||||
RUN git clone --depth=1 $GIT/desktop-app/patches.git
|
||||
|
||||
FROM builder AS extra-cmake-modules
|
||||
|
||||
RUN git clone -b v5.77.0 --depth=1 $GIT/KDE/extra-cmake-modules.git
|
||||
|
||||
WORKDIR extra-cmake-modules
|
||||
RUN cmake3 -B build . -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF
|
||||
RUN cmake3 --build build -j$(nproc)
|
||||
RUN DESTDIR="$LibrariesPath/extra-cmake-modules-cache" cmake3 --install build
|
||||
|
||||
WORKDIR ..
|
||||
RUN rm -rf extra-cmake-modules
|
||||
|
||||
FROM builder AS libffi
|
||||
RUN git clone -b v3.3 --depth=1 $GIT/libffi/libffi.git
|
||||
@@ -107,20 +121,18 @@ RUN rm -rf libxcb
|
||||
|
||||
FROM builder AS xcb-wm
|
||||
|
||||
RUN git clone --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-wm.git
|
||||
RUN git clone -b 0.4.1 --depth=1 --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-wm.git
|
||||
|
||||
WORKDIR libxcb-wm
|
||||
RUN git checkout 0.4.1
|
||||
RUN ./autogen.sh --enable-static
|
||||
RUN make -j$(nproc)
|
||||
RUN make DESTDIR="$LibrariesPath/xcb-wm-cache" install
|
||||
|
||||
FROM builder AS xcb-util
|
||||
|
||||
RUN git clone --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-util.git
|
||||
RUN git clone -b 0.4.0 --depth=1 --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-util.git
|
||||
|
||||
WORKDIR libxcb-util
|
||||
RUN git checkout 0.4.0
|
||||
RUN ./autogen.sh --enable-static
|
||||
RUN make -j$(nproc)
|
||||
RUN make DESTDIR="$LibrariesPath/xcb-util-cache" install
|
||||
@@ -128,30 +140,27 @@ RUN make DESTDIR="$LibrariesPath/xcb-util-cache" install
|
||||
FROM builder AS xcb-image
|
||||
COPY --from=xcb-util ${LibrariesPath}/xcb-util-cache /
|
||||
|
||||
RUN git clone --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-image.git
|
||||
RUN git clone -b 0.4.0 --depth=1 --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-image.git
|
||||
|
||||
WORKDIR libxcb-image
|
||||
RUN git checkout 0.4.0
|
||||
RUN ./autogen.sh --enable-static
|
||||
RUN make -j$(nproc)
|
||||
RUN make DESTDIR="$LibrariesPath/xcb-image-cache" install
|
||||
|
||||
FROM builder AS xcb-keysyms
|
||||
|
||||
RUN git clone --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-keysyms.git
|
||||
RUN git clone -b 0.4.0 --depth=1 --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-keysyms.git
|
||||
|
||||
WORKDIR libxcb-keysyms
|
||||
RUN git checkout 0.4.0
|
||||
RUN ./autogen.sh --enable-static
|
||||
RUN make -j$(nproc)
|
||||
RUN make DESTDIR="$LibrariesPath/xcb-keysyms-cache" install
|
||||
|
||||
FROM builder AS xcb-render-util
|
||||
|
||||
RUN git clone --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-render-util.git
|
||||
RUN git clone -b 0.3.9 --depth=1 --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-render-util.git
|
||||
|
||||
WORKDIR libxcb-render-util
|
||||
RUN git checkout 0.3.9
|
||||
RUN ./autogen.sh --enable-static
|
||||
RUN make -j$(nproc)
|
||||
RUN make DESTDIR="$LibrariesPath/xcb-render-util-cache" install
|
||||
@@ -208,6 +217,32 @@ RUN make DESTDIR="$LibrariesPath/wayland-cache" install
|
||||
WORKDIR ..
|
||||
RUN rm -rf wayland
|
||||
|
||||
FROM builder AS wayland-protocols
|
||||
COPY --from=wayland ${LibrariesPath}/wayland-cache /
|
||||
|
||||
RUN git clone -b 1.18 --depth=1 https://gitlab.freedesktop.org/wayland/wayland-protocols.git
|
||||
|
||||
WORKDIR wayland-protocols
|
||||
RUN ./autogen.sh
|
||||
RUN make -j$(nproc)
|
||||
RUN make DESTDIR="$LibrariesPath/wayland-protocols-cache" install
|
||||
|
||||
WORKDIR ..
|
||||
RUN rm -rf wayland-protocols
|
||||
|
||||
FROM builder AS plasma-wayland-protocols
|
||||
COPY --from=extra-cmake-modules ${LibrariesPath}/extra-cmake-modules-cache /
|
||||
|
||||
RUN git clone -b v1.1.1 --depth=1 $GIT/KDE/plasma-wayland-protocols.git
|
||||
|
||||
WORKDIR plasma-wayland-protocols
|
||||
RUN cmake3 -B build . -DCMAKE_BUILD_TYPE=Release
|
||||
RUN cmake3 --build build -j$(nproc)
|
||||
RUN DESTDIR="$LibrariesPath/plasma-wayland-protocols-cache" cmake3 --install build
|
||||
|
||||
WORKDIR ..
|
||||
RUN rm -rf plasma-wayland-protocols
|
||||
|
||||
FROM builder AS libva
|
||||
|
||||
COPY --from=libffi ${LibrariesPath}/libffi-cache /
|
||||
@@ -457,6 +492,34 @@ RUN make INSTALL_ROOT="$LibrariesPath/qt-cache" install
|
||||
WORKDIR ..
|
||||
RUN rm -rf qt_${QT}
|
||||
|
||||
FROM builder AS kwayland
|
||||
|
||||
COPY --from=extra-cmake-modules ${LibrariesPath}/extra-cmake-modules-cache /
|
||||
COPY --from=libffi ${LibrariesPath}/libffi-cache /
|
||||
COPY --from=mozjpeg ${LibrariesPath}/mozjpeg-cache /
|
||||
COPY --from=xcb ${LibrariesPath}/xcb-cache /
|
||||
COPY --from=xcb-wm ${LibrariesPath}/xcb-wm-cache /
|
||||
COPY --from=xcb-util ${LibrariesPath}/xcb-util-cache /
|
||||
COPY --from=xcb-image ${LibrariesPath}/xcb-image-cache /
|
||||
COPY --from=xcb-keysyms ${LibrariesPath}/xcb-keysyms-cache /
|
||||
COPY --from=xcb-render-util ${LibrariesPath}/xcb-render-util-cache /
|
||||
COPY --from=wayland ${LibrariesPath}/wayland-cache /
|
||||
COPY --from=wayland-protocols ${LibrariesPath}/wayland-protocols-cache /
|
||||
COPY --from=plasma-wayland-protocols ${LibrariesPath}/plasma-wayland-protocols-cache /
|
||||
COPY --from=openssl ${LibrariesPath}/openssl-cache /
|
||||
COPY --from=xkbcommon ${LibrariesPath}/xkbcommon-cache /
|
||||
COPY --from=qt ${LibrariesPath}/qt-cache /
|
||||
|
||||
RUN git clone -b v5.77.0 --depth=1 $GIT/KDE/kwayland.git
|
||||
|
||||
WORKDIR kwayland
|
||||
RUN cmake3 -B build . -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTING=OFF
|
||||
RUN cmake3 --build build -j$(nproc)
|
||||
RUN DESTDIR="$LibrariesPath/kwayland-cache" cmake3 --install build
|
||||
|
||||
WORKDIR ..
|
||||
RUN rm -rf kwayland
|
||||
|
||||
FROM patches AS breakpad
|
||||
RUN git clone https://chromium.googlesource.com/breakpad/breakpad.git
|
||||
|
||||
@@ -482,7 +545,7 @@ RUN make DESTDIR="$BreakpadCache" install
|
||||
|
||||
WORKDIR src
|
||||
RUN rm -rf testing
|
||||
RUN git clone $GIT/google/googletest.git testing
|
||||
RUN git clone --depth=1 $GIT/google/googletest.git testing
|
||||
|
||||
WORKDIR tools
|
||||
RUN sed -i 's/minidump_upload.m/minidump_upload.cc/' linux/tools_linux.gypi
|
||||
@@ -503,10 +566,10 @@ COPY --from=opus ${LibrariesPath}/opus-cache /
|
||||
COPY --from=ffmpeg ${LibrariesPath}/ffmpeg-cache /
|
||||
COPY --from=openssl ${LibrariesPath}/openssl-cache /
|
||||
|
||||
RUN git clone --recursive $GIT/desktop-app/tg_owt.git
|
||||
ADD https://api.github.com/repos/desktop-app/tg_owt/git/refs/heads/master tg_owt-version.json
|
||||
RUN git clone --depth=1 --recursive $GIT/desktop-app/tg_owt.git
|
||||
|
||||
WORKDIR tg_owt
|
||||
RUN git checkout 75ac669
|
||||
|
||||
RUN cmake3 -B out/Release . \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
@@ -552,6 +615,7 @@ COPY --from=openal ${LibrariesPath}/openal-cache /
|
||||
COPY --from=openssl ${LibrariesPath}/openssl-cache /
|
||||
COPY --from=xkbcommon ${LibrariesPath}/xkbcommon-cache /
|
||||
COPY --from=qt ${LibrariesPath}/qt-cache /
|
||||
COPY --from=kwayland ${LibrariesPath}/kwayland-cache /
|
||||
COPY --from=breakpad ${LibrariesPath}/breakpad breakpad
|
||||
COPY --from=breakpad ${LibrariesPath}/breakpad-cache /
|
||||
COPY --from=webrtc ${LibrariesPath}/tg_owt tg_owt
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
AppVersion 2005002
|
||||
AppVersion 2005004
|
||||
AppVersionStrMajor 2.5
|
||||
AppVersionStrSmall 2.5.2
|
||||
AppVersionStr 2.5.2
|
||||
AppVersionStrSmall 2.5.4
|
||||
AppVersionStr 2.5.4
|
||||
BetaChannel 1
|
||||
AlphaVersion 0
|
||||
AppVersionOriginal 2.5.2.beta
|
||||
AppVersionOriginal 2.5.4.beta
|
||||
|
||||
@@ -28,6 +28,8 @@ PRIVATE
|
||||
if (NOT DESKTOP_APP_DISABLE_WEBRTC_INTEGRATION)
|
||||
nice_target_sources(lib_tgcalls ${tgcalls_loc}
|
||||
PRIVATE
|
||||
AudioDeviceHelper.cpp
|
||||
AudioDeviceHelper.h
|
||||
CodecSelectHelper.cpp
|
||||
CodecSelectHelper.h
|
||||
CryptoHelper.cpp
|
||||
|
||||
Submodule Telegram/lib_base updated: 81df0d0b78...dc89f34be5
Submodule Telegram/lib_ui updated: 17eb0f22b4...9ebd51c8f8
Submodule Telegram/lib_webrtc updated: 4bc51d6f6d...c41c510b29
@@ -1,3 +1,15 @@
|
||||
2.5.4 beta (07.01.21)
|
||||
|
||||
- Implement new audio module code for calls and voice chats.
|
||||
- Allow retracting votes from polls in comments to channel posts.
|
||||
- Show small voice chat button for empty voice chats.
|
||||
- Fix media viewer updating when screen resolution is changed.
|
||||
|
||||
2.5.3 beta (30.12.20)
|
||||
|
||||
- Allow using mouse buttons in Push-to-Talk shortcut.
|
||||
- Fix blurred thumbnails in Shared Links section.
|
||||
|
||||
2.5.2 beta (25.12.20)
|
||||
|
||||
- Fix possible crash in video calls.
|
||||
|
||||
2
cmake
2
cmake
Submodule cmake updated: 2208358765...561273a2f8
@@ -68,17 +68,8 @@ Go to ***BuildPath*** and run
|
||||
cd build
|
||||
CFLAGS="$UNGUARDED" CPPFLAGS="$UNGUARDED" cmake -D CMAKE_OSX_DEPLOYMENT_TARGET:STRING=10.12 -D CMAKE_INSTALL_PREFIX:STRING=/usr/local/macos ..
|
||||
make $MAKE_THREADS_CNT
|
||||
cd ../..
|
||||
|
||||
xz_ver=5.2.4
|
||||
wget https://tukaani.org/xz/xz-$xz_ver.tar.gz
|
||||
tar -xvzf xz-$xz_ver.tar.gz
|
||||
rm xz-$xz_ver.tar.gz
|
||||
cd xz-$xz_ver
|
||||
CFLAGS="$MIN_VER" LDFLAGS="$MIN_VER" ./configure --prefix=/usr/local/macos
|
||||
make $MAKE_THREADS_CNT
|
||||
sudo make install
|
||||
cd ..
|
||||
cd ../..
|
||||
|
||||
git clone https://github.com/desktop-app/zlib.git
|
||||
cd zlib
|
||||
|
||||
@@ -74,6 +74,7 @@ parts:
|
||||
- libasound2-dev
|
||||
- libglib2.0-dev
|
||||
- libgtk-3-dev
|
||||
- libkf5wayland-dev
|
||||
- liblzma-dev
|
||||
- libopus-dev
|
||||
- libpulse-dev
|
||||
@@ -90,6 +91,7 @@ parts:
|
||||
- libasound2
|
||||
- libglib2.0-0
|
||||
- libgtk-3-0
|
||||
- libkf5waylandclient5
|
||||
- liblzma5
|
||||
- libopus0
|
||||
- libpulse0
|
||||
@@ -251,7 +253,7 @@ parts:
|
||||
webrtc:
|
||||
source: https://github.com/desktop-app/tg_owt.git
|
||||
source-depth: 1
|
||||
source-commit: 75ac66937341d8a9207375aaee79b4bdc500146c
|
||||
source-commit: d91d618889cc743aafd809151449012de62e5327
|
||||
plugin: cmake
|
||||
build-packages:
|
||||
- yasm
|
||||
|
||||
Reference in New Issue
Block a user