Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c9fc9e881 | ||
|
|
1d089366ff | ||
|
|
fe40464e33 | ||
|
|
728b1efb9a | ||
|
|
175f3d7a38 | ||
|
|
ae1fb8841a | ||
|
|
16ba20f898 | ||
|
|
d8ffc114d3 | ||
|
|
23bd76a8dd | ||
|
|
d85981cca0 | ||
|
|
7b466e0643 | ||
|
|
d984c5924d | ||
|
|
cfa3352caf | ||
|
|
05d2fc819c | ||
|
|
cb930a89ce | ||
|
|
3808874da0 | ||
|
|
3be8521b9a | ||
|
|
9fb72e1c3e | ||
|
|
e26e666135 | ||
|
|
e9196bbbb5 | ||
|
|
819ce06dfb | ||
|
|
da1168fb00 |
9
.github/workflows/win.yml
vendored
9
.github/workflows/win.yml
vendored
@@ -114,6 +114,11 @@ jobs:
|
||||
- name: Choco installs.
|
||||
run: choco install --no-progress -y nasm yasm jom ninja
|
||||
|
||||
- name: NuGet sources.
|
||||
run: |
|
||||
nuget sources Disable -Name "Microsoft Visual Studio Offline Packages"
|
||||
nuget sources Add -Source https://api.nuget.org/v3/index.json & exit 0
|
||||
|
||||
- name: Patches.
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -279,6 +284,10 @@ jobs:
|
||||
msbuild -m opus.sln /property:Configuration=Debug /property:Platform="Win32"
|
||||
msbuild -m opus.sln /property:Configuration=Release /property:Platform="Win32"
|
||||
|
||||
echo "Workaround for FFmpeg."
|
||||
copy Win32\Release\m.lib Win32\Release\ssp.lib
|
||||
copy Win32\Release\m.lib Win32\Debug\ssp.lib
|
||||
|
||||
- name: FFmpeg cache.
|
||||
id: cache-ffmpeg
|
||||
uses: actions/cache@v2
|
||||
|
||||
@@ -15,7 +15,8 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
|
||||
|
||||
The latest version is available for
|
||||
|
||||
* [Windows 7 and above](https://telegram.org/dl/desktop/win) ([portable](https://telegram.org/dl/desktop/win_portable))
|
||||
* [Windows 7 and above (64 bit)](https://telegram.org/dl/desktop/win64) ([portable](https://telegram.org/dl/desktop/win64_portable))
|
||||
* [Windows 7 and above (32 bit)](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)
|
||||
* [Linux static build for 64 bit](https://telegram.org/dl/desktop/linux)
|
||||
* [Snap](https://snapcraft.io/telegram-desktop)
|
||||
|
||||
@@ -1908,6 +1908,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_payments_shipping_address_title" = "Shipping Information";
|
||||
"lng_payments_card_title" = "New Card";
|
||||
"lng_payments_card_number" = "Card Number";
|
||||
"lng_payments_card_cvc" = "CVC";
|
||||
"lng_payments_card_expire_date" = "MM / YY";
|
||||
"lng_payments_card_holder" = "Cardholder name";
|
||||
"lng_payments_billing_address" = "Billing Information";
|
||||
"lng_payments_billing_country" = "Country";
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="2.7.2.0" />
|
||||
Version="2.7.4.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||
|
||||
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,7,2,0
|
||||
PRODUCTVERSION 2,7,2,0
|
||||
FILEVERSION 2,7,4,0
|
||||
PRODUCTVERSION 2,7,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.7.2.0"
|
||||
VALUE "FileVersion", "2.7.4.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2021"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "2.7.2.0"
|
||||
VALUE "ProductVersion", "2.7.4.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,7,2,0
|
||||
PRODUCTVERSION 2,7,2,0
|
||||
FILEVERSION 2,7,4,0
|
||||
PRODUCTVERSION 2,7,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.7.2.0"
|
||||
VALUE "FileVersion", "2.7.4.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2021"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "2.7.2.0"
|
||||
VALUE "ProductVersion", "2.7.4.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -208,6 +208,55 @@ callRemoteAudioMute: FlatLabel(callStatus) {
|
||||
}
|
||||
callRemoteAudioMuteSkip: 12px;
|
||||
|
||||
callMuteMainBlobMinRadius: 57px;
|
||||
callMuteMainBlobMaxRadius: 63px;
|
||||
callMuteMinorBlobMinRadius: 64px;
|
||||
callMuteMinorBlobMaxRadius: 74px;
|
||||
callMuteMajorBlobMinRadius: 67px;
|
||||
callMuteMajorBlobMaxRadius: 77px;
|
||||
|
||||
callMuteButtonActiveInner: IconButton {
|
||||
width: 136px;
|
||||
height: 165px;
|
||||
}
|
||||
callMuteButtonLabel: FlatLabel(defaultFlatLabel) {
|
||||
textFg: groupCallMembersFg;
|
||||
style: TextStyle(defaultTextStyle) {
|
||||
font: font(14px);
|
||||
linkFont: font(14px);
|
||||
linkFontOver: font(14px underline);
|
||||
}
|
||||
}
|
||||
callMuteButtonSublabel: FlatLabel(defaultFlatLabel) {
|
||||
textFg: groupCallMemberNotJoinedStatus;
|
||||
}
|
||||
callMuteButtonLabelsSkip: 5px;
|
||||
callMuteButtonSublabelSkip: 19px;
|
||||
callMuteButtonActive: CallButton {
|
||||
button: callMuteButtonActiveInner;
|
||||
bg: groupCallLive1;
|
||||
bgSize: 100px;
|
||||
bgPosition: point(18px, 18px);
|
||||
outerRadius: 18px;
|
||||
outerBg: callAnswerBgOuter;
|
||||
label: callMuteButtonLabel;
|
||||
}
|
||||
callMuteButtonMuted: CallButton(callMuteButtonActive) {
|
||||
bg: groupCallMuted1;
|
||||
label: callMuteButtonLabel;
|
||||
}
|
||||
callMuteButtonConnecting: CallButton(callMuteButtonMuted) {
|
||||
bg: callIconBg;
|
||||
label: callMuteButtonLabel;
|
||||
}
|
||||
callMuteButtonLabelAdditional: 5px;
|
||||
|
||||
callConnectingRadial: InfiniteRadialAnimation(defaultInfiniteRadialAnimation) {
|
||||
color: lightButtonFg;
|
||||
thickness: 4px;
|
||||
size: size(100px, 100px);
|
||||
}
|
||||
|
||||
callBarHeight: 38px;
|
||||
callBarMuteToggle: IconButton {
|
||||
width: 41px;
|
||||
|
||||
@@ -269,14 +269,18 @@ GroupCall::~GroupCall() {
|
||||
destroyController();
|
||||
}
|
||||
|
||||
void GroupCall::setScheduledDate(TimeId date) {
|
||||
const auto was = _scheduleDate;
|
||||
_scheduleDate = date;
|
||||
if (was && !date) {
|
||||
join(inputCall());
|
||||
}
|
||||
}
|
||||
|
||||
void GroupCall::subscribeToReal(not_null<Data::GroupCall*> real) {
|
||||
real->scheduleDateValue(
|
||||
) | rpl::start_with_next([=](TimeId date) {
|
||||
const auto was = _scheduleDate;
|
||||
_scheduleDate = date;
|
||||
if (was && !date) {
|
||||
join(inputCall());
|
||||
}
|
||||
setScheduledDate(date);
|
||||
}, _lifetime);
|
||||
}
|
||||
|
||||
@@ -821,11 +825,7 @@ void GroupCall::handlePossibleCreateOrJoinResponse(
|
||||
|
||||
void GroupCall::handlePossibleCreateOrJoinResponse(
|
||||
const MTPDgroupCall &data) {
|
||||
if (const auto date = data.vschedule_date()) {
|
||||
_scheduleDate = date->v;
|
||||
} else {
|
||||
_scheduleDate = 0;
|
||||
}
|
||||
setScheduledDate(data.vschedule_date().value_or_empty());
|
||||
if (_acceptFields) {
|
||||
if (!_instance && !_id) {
|
||||
const auto input = MTP_inputGroupCall(
|
||||
|
||||
@@ -259,6 +259,7 @@ private:
|
||||
void setJoinAs(not_null<PeerData*> as);
|
||||
void saveDefaultJoinAs(not_null<PeerData*> as);
|
||||
void subscribeToReal(not_null<Data::GroupCall*> real);
|
||||
void setScheduledDate(TimeId date);
|
||||
|
||||
void audioLevelsUpdated(const tgcalls::GroupLevelsUpdate &data);
|
||||
void setInstanceConnected(tgcalls::GroupNetworkState networkState);
|
||||
|
||||
@@ -163,14 +163,20 @@ bool BotKeyboard::moderateKeyActivate(int key) {
|
||||
}
|
||||
} else if (const auto user = item->history()->peer->asUser()) {
|
||||
if (user->isBot() && item->from() == user) {
|
||||
if (key == Qt::Key_Q) {
|
||||
if (key == Qt::Key_Q || key == Qt::Key_6) {
|
||||
App::sendBotCommand(user, user, qsl("/translate"));
|
||||
} else if (key == Qt::Key_W) {
|
||||
} else if (key == Qt::Key_W || key == Qt::Key_5) {
|
||||
App::sendBotCommand(user, user, qsl("/eng"));
|
||||
} else if (key == Qt::Key_3) {
|
||||
App::sendBotCommand(user, user, qsl("/pattern"));
|
||||
} else if (key == Qt::Key_4) {
|
||||
App::sendBotCommand(user, user, qsl("/abuse"));
|
||||
} else if (key == Qt::Key_0 || key == Qt::Key_E) {
|
||||
App::sendBotCommand(user, user, qsl("/undo"));
|
||||
} else if (key == Qt::Key_Plus || key == Qt::Key_QuoteLeft) {
|
||||
App::sendBotCommand(user, user, qsl("/next"));
|
||||
} else if (key == Qt::Key_Period || key == Qt::Key_S) {
|
||||
App::sendBotCommand(user, user, qsl("/stats"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_app_config.h"
|
||||
#include "mainwindow.h"
|
||||
#include "facades.h" // Global::ScreenIsLocked.
|
||||
|
||||
namespace Core {
|
||||
namespace {
|
||||
@@ -112,6 +113,10 @@ void UiIntegration::activationFromTopPanel() {
|
||||
Platform::IgnoreApplicationActivationRightNow();
|
||||
}
|
||||
|
||||
bool UiIntegration::screenIsLocked() {
|
||||
return Global::ScreenIsLocked();
|
||||
}
|
||||
|
||||
QString UiIntegration::timeFormat() {
|
||||
return cTimeFormat();
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ public:
|
||||
void textActionsUpdated() override;
|
||||
void activationFromTopPanel() override;
|
||||
|
||||
bool screenIsLocked() override;
|
||||
QString timeFormat() override;
|
||||
|
||||
std::shared_ptr<ClickHandler> createLinkHandler(
|
||||
|
||||
@@ -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 = 2007002;
|
||||
constexpr auto AppVersionStr = "2.7.2";
|
||||
constexpr auto AppVersion = 2007004;
|
||||
constexpr auto AppVersionStr = "2.7.4";
|
||||
constexpr auto AppBetaVersion = false;
|
||||
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
|
||||
|
||||
@@ -557,13 +557,8 @@ bool MainWindow::doWeMarkAsRead() {
|
||||
if (!_main || Ui::isLayerShown()) {
|
||||
return false;
|
||||
}
|
||||
// for tile grid in case other windows have shadows
|
||||
// i've seen some windows with >70px shadow margins
|
||||
const auto margin = style::ConvertScale(100);
|
||||
return Ui::IsContentVisible(
|
||||
this,
|
||||
inner().marginsRemoved(QMargins(margin, margin, margin, margin)))
|
||||
&& _main->doWeMarkAsRead();
|
||||
updateIsActive();
|
||||
return isActive() && _main->doWeMarkAsRead();
|
||||
}
|
||||
|
||||
void MainWindow::checkHistoryActivation() {
|
||||
|
||||
@@ -2999,9 +2999,14 @@ void OverlayWidget::switchToPip() {
|
||||
_streamed->instance.shared(),
|
||||
closeAndContinue,
|
||||
[=] { _pip = nullptr; });
|
||||
close();
|
||||
if (const auto window = Core::App().activeWindow()) {
|
||||
window->activate();
|
||||
if (isHidden()) {
|
||||
clearBeforeHide();
|
||||
clearAfterHide();
|
||||
} else {
|
||||
close();
|
||||
if (const auto window = Core::App().activeWindow()) {
|
||||
window->activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4365,42 +4370,50 @@ void OverlayWidget::applyHideWindowWorkaround() {
|
||||
#endif // USE_OPENGL_OVERLAY_WIDGET
|
||||
}
|
||||
|
||||
// #TODO unite and check
|
||||
void OverlayWidget::clearBeforeHide() {
|
||||
_sharedMedia = nullptr;
|
||||
_sharedMediaData = std::nullopt;
|
||||
_sharedMediaDataKey = std::nullopt;
|
||||
_userPhotos = nullptr;
|
||||
_userPhotosData = std::nullopt;
|
||||
_collage = nullptr;
|
||||
_collageData = std::nullopt;
|
||||
assignMediaPointer(nullptr);
|
||||
_preloadPhotos.clear();
|
||||
_preloadDocuments.clear();
|
||||
if (_menu) {
|
||||
_menu->hideMenu(true);
|
||||
}
|
||||
_controlsHideTimer.cancel();
|
||||
_controlsState = ControlsShown;
|
||||
_controlsOpacity = anim::value(1, 1);
|
||||
_groupThumbs = nullptr;
|
||||
_groupThumbsRect = QRect();
|
||||
}
|
||||
|
||||
void OverlayWidget::clearAfterHide() {
|
||||
clearStreaming();
|
||||
destroyThemePreview();
|
||||
_radial.stop();
|
||||
_staticContent = QPixmap();
|
||||
_themePreview = nullptr;
|
||||
_themeApply.destroyDelayed();
|
||||
_themeCancel.destroyDelayed();
|
||||
_themeShare.destroyDelayed();
|
||||
}
|
||||
|
||||
void OverlayWidget::setVisibleHook(bool visible) {
|
||||
if (!visible) {
|
||||
applyHideWindowWorkaround();
|
||||
_sharedMedia = nullptr;
|
||||
_sharedMediaData = std::nullopt;
|
||||
_sharedMediaDataKey = std::nullopt;
|
||||
_userPhotos = nullptr;
|
||||
_userPhotosData = std::nullopt;
|
||||
_collage = nullptr;
|
||||
_collageData = std::nullopt;
|
||||
assignMediaPointer(nullptr);
|
||||
_preloadPhotos.clear();
|
||||
_preloadDocuments.clear();
|
||||
if (_menu) {
|
||||
_menu->hideMenu(true);
|
||||
}
|
||||
_controlsHideTimer.cancel();
|
||||
_controlsState = ControlsShown;
|
||||
_controlsOpacity = anim::value(1, 1);
|
||||
_groupThumbs = nullptr;
|
||||
_groupThumbsRect = QRect();
|
||||
clearBeforeHide();
|
||||
}
|
||||
OverlayParent::setVisibleHook(visible);
|
||||
if (visible) {
|
||||
QCoreApplication::instance()->installEventFilter(this);
|
||||
} else {
|
||||
QCoreApplication::instance()->removeEventFilter(this);
|
||||
|
||||
clearStreaming();
|
||||
destroyThemePreview();
|
||||
_radial.stop();
|
||||
_staticContent = QPixmap();
|
||||
_themePreview = nullptr;
|
||||
_themeApply.destroyDelayed();
|
||||
_themeCancel.destroyDelayed();
|
||||
_themeShare.destroyDelayed();
|
||||
clearAfterHide();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -210,6 +210,9 @@ private:
|
||||
void playbackPauseMusic();
|
||||
void switchToPip();
|
||||
|
||||
void clearBeforeHide();
|
||||
void clearAfterHide();
|
||||
|
||||
void assignMediaPointer(DocumentData *document);
|
||||
void assignMediaPointer(not_null<PhotoData*> photo);
|
||||
|
||||
|
||||
@@ -303,12 +303,12 @@ not_null<RpWidget*> EditCard::setupContent() {
|
||||
st::paymentsFieldPadding);
|
||||
_expire = make(container, {
|
||||
.type = FieldType::CardExpireDate,
|
||||
.placeholder = rpl::single(u"MM / YY"_q),
|
||||
.placeholder = tr::lng_payments_card_expire_date(),
|
||||
.validator = ExpireDateValidator(),
|
||||
});
|
||||
_cvc = make(container, {
|
||||
.type = FieldType::CardCVC,
|
||||
.placeholder = rpl::single(u"CVC"_q),
|
||||
.placeholder = tr::lng_payments_card_cvc(),
|
||||
.validator = CvcValidator([=] { return _number->value(); }),
|
||||
});
|
||||
container->widthValue(
|
||||
|
||||
@@ -196,7 +196,7 @@ void FormSummary::setupControls() {
|
||||
_1 + _2 < _3));
|
||||
|
||||
rpl::merge(
|
||||
_submit->widthValue(),
|
||||
(_submit ? _submit->widthValue() : rpl::single(0)),
|
||||
_cancel->widthValue()
|
||||
) | rpl::skip(2) | rpl::start_with_next([=] {
|
||||
updateControlsGeometry();
|
||||
|
||||
@@ -8,8 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "platform/linux/linux_xdp_file_dialog.h"
|
||||
|
||||
#include "platform/platform_file_utilities.h"
|
||||
#include "platform/linux/linux_desktop_environment.h"
|
||||
#include "platform/linux/specific_linux.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "base/platform/linux/base_linux_glibmm_helper.h"
|
||||
#include "storage/localstorage.h"
|
||||
@@ -642,18 +640,8 @@ rpl::producer<> XDPFileDialog::rejected() {
|
||||
} // namespace
|
||||
|
||||
bool Use(Type type) {
|
||||
static const auto ShouldUse = [&] {
|
||||
const auto envVar = qEnvironmentVariableIsSet("TDESKTOP_USE_PORTAL");
|
||||
const auto confined = InFlatpak() || InSnap();
|
||||
const auto notGtkBased = !DesktopEnvironment::IsGtkBased();
|
||||
|
||||
return confined || notGtkBased || envVar;
|
||||
}();
|
||||
|
||||
static const auto Version = FileChooserPortalVersion();
|
||||
|
||||
return ShouldUse
|
||||
&& Version.has_value()
|
||||
return Version.has_value()
|
||||
&& (type != Type::ReadFolder || *Version >= 3);
|
||||
}
|
||||
|
||||
|
||||
@@ -60,8 +60,17 @@ void StartServiceAsync(
|
||||
try {
|
||||
result(); // get the error if any
|
||||
} catch (const Glib::Error &e) {
|
||||
LOG(("Native Notification Error: %1").arg(
|
||||
QString::fromStdString(e.what())));
|
||||
static const auto NotSupportedErrors = {
|
||||
"org.freedesktop.DBus.Error.ServiceUnknown",
|
||||
};
|
||||
|
||||
const auto errorName =
|
||||
Gio::DBus::ErrorUtils::get_remote_error(e);
|
||||
|
||||
if (!ranges::contains(NotSupportedErrors, errorName)) {
|
||||
LOG(("Native Notification Error: %1").arg(
|
||||
QString::fromStdString(e.what())));
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
LOG(("Native Notification Error: %1").arg(
|
||||
QString::fromStdString(e.what())));
|
||||
@@ -72,9 +81,7 @@ void StartServiceAsync(
|
||||
cancellable);
|
||||
|
||||
return;
|
||||
} catch (const Glib::Error &e) {
|
||||
LOG(("Native Notification Error: %1").arg(
|
||||
QString::fromStdString(e.what())));
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
crl::on_main([=] { callback(); });
|
||||
@@ -708,23 +715,16 @@ void NotificationData::notificationReplied(
|
||||
|
||||
} // namespace
|
||||
|
||||
bool SkipAudio() {
|
||||
return Inhibited();
|
||||
bool SkipAudioForCustom() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkipToast() {
|
||||
// Do not skip native notifications because of Do not disturb.
|
||||
// They respect this setting anyway.
|
||||
if ((Core::App().settings().nativeNotifications() && Supported())
|
||||
|| Enforced()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Inhibited();
|
||||
bool SkipToastForCustom() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkipFlashBounce() {
|
||||
return Inhibited();
|
||||
bool SkipFlashBounceForCustom() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Supported() {
|
||||
@@ -1023,5 +1023,17 @@ void Manager::doClearFromSession(not_null<Main::Session*> session) {
|
||||
_private->clearFromSession(session);
|
||||
}
|
||||
|
||||
bool Manager::doSkipAudio() const {
|
||||
return Inhibited();
|
||||
}
|
||||
|
||||
bool Manager::doSkipToast() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Manager::doSkipFlashBounce() const {
|
||||
return Inhibited();
|
||||
}
|
||||
|
||||
} // namespace Notifications
|
||||
} // namespace Platform
|
||||
|
||||
@@ -34,6 +34,9 @@ protected:
|
||||
void doClearAllFast() override;
|
||||
void doClearFromHistory(not_null<History*> history) override;
|
||||
void doClearFromSession(not_null<Main::Session*> session) override;
|
||||
bool doSkipAudio() const override;
|
||||
bool doSkipToast() const override;
|
||||
bool doSkipFlashBounce() const override;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
|
||||
@@ -32,6 +32,9 @@ protected:
|
||||
void doClearFromHistory(not_null<History*> history) override;
|
||||
void doClearFromSession(not_null<Main::Session*> session) override;
|
||||
QString accountNameSeparator() override;
|
||||
bool doSkipAudio() const override;
|
||||
bool doSkipToast() const override;
|
||||
bool doSkipFlashBounce() const override;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
|
||||
@@ -140,23 +140,16 @@ using Manager = Platform::Notifications::Manager;
|
||||
namespace Platform {
|
||||
namespace Notifications {
|
||||
|
||||
bool SkipAudio() {
|
||||
queryDoNotDisturbState();
|
||||
return DoNotDisturbEnabled;
|
||||
bool SkipAudioForCustom() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkipToast() {
|
||||
if (Supported()) {
|
||||
// Do not skip native notifications because of Do not disturb.
|
||||
// They respect this setting anyway.
|
||||
return false;
|
||||
}
|
||||
queryDoNotDisturbState();
|
||||
return DoNotDisturbEnabled;
|
||||
bool SkipToastForCustom() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkipFlashBounce() {
|
||||
return SkipAudio();
|
||||
bool SkipFlashBounceForCustom() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Supported() {
|
||||
@@ -438,5 +431,18 @@ QString Manager::accountNameSeparator() {
|
||||
return QString::fromUtf8(" \xE2\x86\x92 ");
|
||||
}
|
||||
|
||||
bool Manager::doSkipAudio() const {
|
||||
queryDoNotDisturbState();
|
||||
return DoNotDisturbEnabled;
|
||||
}
|
||||
|
||||
bool Manager::doSkipToast() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Manager::doSkipFlashBounce() const {
|
||||
return doSkipAudio();
|
||||
}
|
||||
|
||||
} // namespace Notifications
|
||||
} // namespace Platform
|
||||
|
||||
@@ -12,9 +12,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Platform {
|
||||
namespace Notifications {
|
||||
|
||||
[[nodiscard]] bool SkipAudio();
|
||||
[[nodiscard]] bool SkipToast();
|
||||
[[nodiscard]] bool SkipFlashBounce();
|
||||
[[nodiscard]] bool SkipAudioForCustom();
|
||||
[[nodiscard]] bool SkipToastForCustom();
|
||||
[[nodiscard]] bool SkipFlashBounceForCustom();
|
||||
|
||||
[[nodiscard]] bool Supported();
|
||||
[[nodiscard]] bool Enforced();
|
||||
|
||||
@@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "core/core_settings.h"
|
||||
#include "main/main_session.h"
|
||||
#include "mainwindow.h"
|
||||
#include "facades.h" // Global::ScreenIsLocked.
|
||||
#include "windows_quiethours_h.h"
|
||||
|
||||
#include <Shobjidl.h>
|
||||
@@ -256,9 +257,188 @@ void Check() {
|
||||
InitSucceeded = init();
|
||||
}
|
||||
|
||||
bool QuietHoursEnabled = false;
|
||||
DWORD QuietHoursValue = 0;
|
||||
|
||||
[[nodiscard]] bool UseQuietHoursRegistryEntry() {
|
||||
static const bool result = [] {
|
||||
// Taken from QSysInfo.
|
||||
OSVERSIONINFO result = { sizeof(OSVERSIONINFO), 0, 0, 0, 0,{ '\0' } };
|
||||
if (const auto library = GetModuleHandle(L"ntdll.dll")) {
|
||||
using RtlGetVersionFunction = NTSTATUS(NTAPI*)(LPOSVERSIONINFO);
|
||||
const auto RtlGetVersion = reinterpret_cast<RtlGetVersionFunction>(
|
||||
GetProcAddress(library, "RtlGetVersion"));
|
||||
if (RtlGetVersion) {
|
||||
RtlGetVersion(&result);
|
||||
}
|
||||
}
|
||||
// At build 17134 (Redstone 4) the "Quiet hours" was replaced
|
||||
// by "Focus assist" and it looks like it doesn't use registry.
|
||||
return (result.dwMajorVersion == 10
|
||||
&& result.dwMinorVersion == 0
|
||||
&& result.dwBuildNumber < 17134);
|
||||
}();
|
||||
return result;
|
||||
}
|
||||
|
||||
// Thanks https://stackoverflow.com/questions/35600128/get-windows-quiet-hours-from-win32-or-c-sharp-api
|
||||
void QueryQuietHours() {
|
||||
if (!UseQuietHoursRegistryEntry()) {
|
||||
// There are quiet hours in Windows starting from Windows 8.1
|
||||
// But there were several reports about the notifications being shut
|
||||
// down according to the registry while no quiet hours were enabled.
|
||||
// So we try this method only starting with Windows 10.
|
||||
return;
|
||||
}
|
||||
|
||||
LPCWSTR lpKeyName = L"Software\\Microsoft\\Windows\\CurrentVersion\\Notifications\\Settings";
|
||||
LPCWSTR lpValueName = L"NOC_GLOBAL_SETTING_TOASTS_ENABLED";
|
||||
HKEY key;
|
||||
auto result = RegOpenKeyEx(HKEY_CURRENT_USER, lpKeyName, 0, KEY_READ, &key);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
DWORD value = 0, type = 0, size = sizeof(value);
|
||||
result = RegQueryValueEx(key, lpValueName, 0, &type, (LPBYTE)&value, &size);
|
||||
RegCloseKey(key);
|
||||
|
||||
auto quietHoursEnabled = (result == ERROR_SUCCESS) && (value == 0);
|
||||
if (QuietHoursEnabled != quietHoursEnabled) {
|
||||
QuietHoursEnabled = quietHoursEnabled;
|
||||
QuietHoursValue = value;
|
||||
LOG(("Quiet hours changed, entry value: %1").arg(value));
|
||||
} else if (QuietHoursValue != value) {
|
||||
QuietHoursValue = value;
|
||||
LOG(("Quiet hours value changed, was value: %1, entry value: %2").arg(QuietHoursValue).arg(value));
|
||||
}
|
||||
}
|
||||
|
||||
bool FocusAssistBlocks = false;
|
||||
|
||||
// Thanks https://www.withinrafael.com/2019/09/19/determine-if-your-app-is-in-a-focus-assist-profiles-priority-list/
|
||||
void QueryFocusAssist() {
|
||||
ComPtr<IQuietHoursSettings> quietHoursSettings;
|
||||
auto hr = CoCreateInstance(
|
||||
CLSID_QuietHoursSettings,
|
||||
nullptr,
|
||||
CLSCTX_LOCAL_SERVER,
|
||||
IID_PPV_ARGS(&quietHoursSettings));
|
||||
if (!SUCCEEDED(hr) || !quietHoursSettings) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto profileId = LPWSTR{};
|
||||
const auto guardProfileId = gsl::finally([&] {
|
||||
if (profileId) CoTaskMemFree(profileId);
|
||||
});
|
||||
hr = quietHoursSettings->get_UserSelectedProfile(&profileId);
|
||||
if (!SUCCEEDED(hr) || !profileId) {
|
||||
return;
|
||||
}
|
||||
const auto profileName = QString::fromWCharArray(profileId);
|
||||
if (profileName.endsWith(".alarmsonly", Qt::CaseInsensitive)) {
|
||||
if (!FocusAssistBlocks) {
|
||||
LOG(("Focus Assist: Alarms Only."));
|
||||
FocusAssistBlocks = true;
|
||||
}
|
||||
return;
|
||||
} else if (!profileName.endsWith(".priorityonly", Qt::CaseInsensitive)) {
|
||||
if (!profileName.endsWith(".unrestricted", Qt::CaseInsensitive)) {
|
||||
LOG(("Focus Assist Warning: Unknown profile '%1'"
|
||||
).arg(profileName));
|
||||
}
|
||||
if (FocusAssistBlocks) {
|
||||
LOG(("Focus Assist: Unrestricted."));
|
||||
FocusAssistBlocks = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
const auto appUserModelId = std::wstring(AppUserModelId::getId());
|
||||
auto blocked = true;
|
||||
const auto guard = gsl::finally([&] {
|
||||
if (FocusAssistBlocks != blocked) {
|
||||
LOG(("Focus Assist: %1, AppUserModelId: %2, Blocks: %3"
|
||||
).arg(profileName
|
||||
).arg(QString::fromStdWString(appUserModelId)
|
||||
).arg(Logs::b(blocked)));
|
||||
FocusAssistBlocks = blocked;
|
||||
}
|
||||
});
|
||||
|
||||
ComPtr<IQuietHoursProfile> profile;
|
||||
hr = quietHoursSettings->GetProfile(profileId, &profile);
|
||||
if (!SUCCEEDED(hr) || !profile) {
|
||||
return;
|
||||
}
|
||||
|
||||
UINT32 count = 0;
|
||||
auto apps = (LPWSTR*)nullptr;
|
||||
const auto guardApps = gsl::finally([&] {
|
||||
if (apps) CoTaskMemFree(apps);
|
||||
});
|
||||
hr = profile->GetAllowedApps(&count, &apps);
|
||||
if (!SUCCEEDED(hr) || !apps) {
|
||||
return;
|
||||
}
|
||||
for (UINT32 i = 0; i < count; i++) {
|
||||
auto app = apps[i];
|
||||
const auto guardApp = gsl::finally([&] {
|
||||
if (app) CoTaskMemFree(app);
|
||||
});
|
||||
if (app == appUserModelId) {
|
||||
blocked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QUERY_USER_NOTIFICATION_STATE UserNotificationState = QUNS_ACCEPTS_NOTIFICATIONS;
|
||||
|
||||
void QueryUserNotificationState() {
|
||||
if (Dlls::SHQueryUserNotificationState != nullptr) {
|
||||
QUERY_USER_NOTIFICATION_STATE state;
|
||||
if (SUCCEEDED(Dlls::SHQueryUserNotificationState(&state))) {
|
||||
UserNotificationState = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr auto kQuerySettingsEachMs = 1000;
|
||||
crl::time LastSettingsQueryMs = 0;
|
||||
|
||||
void QuerySystemNotificationSettings() {
|
||||
auto ms = crl::now();
|
||||
if (LastSettingsQueryMs > 0 && ms <= LastSettingsQueryMs + kQuerySettingsEachMs) {
|
||||
return;
|
||||
}
|
||||
LastSettingsQueryMs = ms;
|
||||
QueryQuietHours();
|
||||
QueryFocusAssist();
|
||||
QueryUserNotificationState();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif // !__MINGW32__
|
||||
|
||||
bool SkipAudioForCustom() {
|
||||
QuerySystemNotificationSettings();
|
||||
|
||||
return (UserNotificationState == QUNS_NOT_PRESENT)
|
||||
|| (UserNotificationState == QUNS_PRESENTATION_MODE)
|
||||
|| Global::ScreenIsLocked();
|
||||
}
|
||||
|
||||
bool SkipToastForCustom() {
|
||||
QuerySystemNotificationSettings();
|
||||
|
||||
return (UserNotificationState == QUNS_PRESENTATION_MODE)
|
||||
|| (UserNotificationState == QUNS_RUNNING_D3D_FULL_SCREEN);
|
||||
}
|
||||
|
||||
bool SkipFlashBounceForCustom() {
|
||||
return SkipToastForCustom();
|
||||
}
|
||||
|
||||
bool Supported() {
|
||||
#ifndef __MINGW32__
|
||||
if (!Checked) {
|
||||
@@ -626,205 +806,23 @@ void Manager::onAfterNotificationActivated(
|
||||
not_null<Window::SessionController*> window) {
|
||||
_private->afterNotificationActivated(id, window);
|
||||
}
|
||||
|
||||
bool Manager::doSkipAudio() const {
|
||||
return SkipAudioForCustom()
|
||||
|| QuietHoursEnabled
|
||||
|| FocusAssistBlocks;
|
||||
}
|
||||
|
||||
bool Manager::doSkipToast() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Manager::doSkipFlashBounce() const {
|
||||
return SkipFlashBounceForCustom()
|
||||
|| QuietHoursEnabled
|
||||
|| FocusAssistBlocks;
|
||||
}
|
||||
#endif // !__MINGW32__
|
||||
|
||||
namespace {
|
||||
|
||||
bool QuietHoursEnabled = false;
|
||||
DWORD QuietHoursValue = 0;
|
||||
|
||||
[[nodiscard]] bool UseQuietHoursRegistryEntry() {
|
||||
static const bool result = [] {
|
||||
// Taken from QSysInfo.
|
||||
OSVERSIONINFO result = { sizeof(OSVERSIONINFO), 0, 0, 0, 0,{ '\0' } };
|
||||
if (const auto library = GetModuleHandle(L"ntdll.dll")) {
|
||||
using RtlGetVersionFunction = NTSTATUS(NTAPI*)(LPOSVERSIONINFO);
|
||||
const auto RtlGetVersion = reinterpret_cast<RtlGetVersionFunction>(
|
||||
GetProcAddress(library, "RtlGetVersion"));
|
||||
if (RtlGetVersion) {
|
||||
RtlGetVersion(&result);
|
||||
}
|
||||
}
|
||||
// At build 17134 (Redstone 4) the "Quiet hours" was replaced
|
||||
// by "Focus assist" and it looks like it doesn't use registry.
|
||||
return (result.dwMajorVersion == 10
|
||||
&& result.dwMinorVersion == 0
|
||||
&& result.dwBuildNumber < 17134);
|
||||
}();
|
||||
return result;
|
||||
}
|
||||
|
||||
// Thanks https://stackoverflow.com/questions/35600128/get-windows-quiet-hours-from-win32-or-c-sharp-api
|
||||
void QueryQuietHours() {
|
||||
if (!UseQuietHoursRegistryEntry()) {
|
||||
// There are quiet hours in Windows starting from Windows 8.1
|
||||
// But there were several reports about the notifications being shut
|
||||
// down according to the registry while no quiet hours were enabled.
|
||||
// So we try this method only starting with Windows 10.
|
||||
return;
|
||||
}
|
||||
|
||||
LPCWSTR lpKeyName = L"Software\\Microsoft\\Windows\\CurrentVersion\\Notifications\\Settings";
|
||||
LPCWSTR lpValueName = L"NOC_GLOBAL_SETTING_TOASTS_ENABLED";
|
||||
HKEY key;
|
||||
auto result = RegOpenKeyEx(HKEY_CURRENT_USER, lpKeyName, 0, KEY_READ, &key);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
DWORD value = 0, type = 0, size = sizeof(value);
|
||||
result = RegQueryValueEx(key, lpValueName, 0, &type, (LPBYTE)&value, &size);
|
||||
RegCloseKey(key);
|
||||
|
||||
auto quietHoursEnabled = (result == ERROR_SUCCESS) && (value == 0);
|
||||
if (QuietHoursEnabled != quietHoursEnabled) {
|
||||
QuietHoursEnabled = quietHoursEnabled;
|
||||
QuietHoursValue = value;
|
||||
LOG(("Quiet hours changed, entry value: %1").arg(value));
|
||||
} else if (QuietHoursValue != value) {
|
||||
QuietHoursValue = value;
|
||||
LOG(("Quiet hours value changed, was value: %1, entry value: %2").arg(QuietHoursValue).arg(value));
|
||||
}
|
||||
}
|
||||
|
||||
bool FocusAssistBlocks = false;
|
||||
|
||||
// Thanks https://www.withinrafael.com/2019/09/19/determine-if-your-app-is-in-a-focus-assist-profiles-priority-list/
|
||||
void QueryFocusAssist() {
|
||||
ComPtr<IQuietHoursSettings> quietHoursSettings;
|
||||
auto hr = CoCreateInstance(
|
||||
CLSID_QuietHoursSettings,
|
||||
nullptr,
|
||||
CLSCTX_LOCAL_SERVER,
|
||||
IID_PPV_ARGS(&quietHoursSettings));
|
||||
if (!SUCCEEDED(hr) || !quietHoursSettings) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto profileId = LPWSTR{};
|
||||
const auto guardProfileId = gsl::finally([&] {
|
||||
if (profileId) CoTaskMemFree(profileId);
|
||||
});
|
||||
hr = quietHoursSettings->get_UserSelectedProfile(&profileId);
|
||||
if (!SUCCEEDED(hr) || !profileId) {
|
||||
return;
|
||||
}
|
||||
const auto profileName = QString::fromWCharArray(profileId);
|
||||
if (profileName.endsWith(".alarmsonly", Qt::CaseInsensitive)) {
|
||||
if (!FocusAssistBlocks) {
|
||||
LOG(("Focus Assist: Alarms Only."));
|
||||
FocusAssistBlocks = true;
|
||||
}
|
||||
return;
|
||||
} else if (!profileName.endsWith(".priorityonly", Qt::CaseInsensitive)) {
|
||||
if (!profileName.endsWith(".unrestricted", Qt::CaseInsensitive)) {
|
||||
LOG(("Focus Assist Warning: Unknown profile '%1'"
|
||||
).arg(profileName));
|
||||
}
|
||||
if (FocusAssistBlocks) {
|
||||
LOG(("Focus Assist: Unrestricted."));
|
||||
FocusAssistBlocks = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
const auto appUserModelId = std::wstring(AppUserModelId::getId());
|
||||
auto blocked = true;
|
||||
const auto guard = gsl::finally([&] {
|
||||
if (FocusAssistBlocks != blocked) {
|
||||
LOG(("Focus Assist: %1, AppUserModelId: %2, Blocks: %3"
|
||||
).arg(profileName
|
||||
).arg(QString::fromStdWString(appUserModelId)
|
||||
).arg(Logs::b(blocked)));
|
||||
FocusAssistBlocks = blocked;
|
||||
}
|
||||
});
|
||||
|
||||
ComPtr<IQuietHoursProfile> profile;
|
||||
hr = quietHoursSettings->GetProfile(profileId, &profile);
|
||||
if (!SUCCEEDED(hr) || !profile) {
|
||||
return;
|
||||
}
|
||||
|
||||
UINT32 count = 0;
|
||||
auto apps = (LPWSTR*)nullptr;
|
||||
const auto guardApps = gsl::finally([&] {
|
||||
if (apps) CoTaskMemFree(apps);
|
||||
});
|
||||
hr = profile->GetAllowedApps(&count, &apps);
|
||||
if (!SUCCEEDED(hr) || !apps) {
|
||||
return;
|
||||
}
|
||||
for (UINT32 i = 0; i < count; i++) {
|
||||
auto app = apps[i];
|
||||
const auto guardApp = gsl::finally([&] {
|
||||
if (app) CoTaskMemFree(app);
|
||||
});
|
||||
if (app == appUserModelId) {
|
||||
blocked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QUERY_USER_NOTIFICATION_STATE UserNotificationState = QUNS_ACCEPTS_NOTIFICATIONS;
|
||||
|
||||
void QueryUserNotificationState() {
|
||||
if (Dlls::SHQueryUserNotificationState != nullptr) {
|
||||
QUERY_USER_NOTIFICATION_STATE state;
|
||||
if (SUCCEEDED(Dlls::SHQueryUserNotificationState(&state))) {
|
||||
UserNotificationState = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr auto kQuerySettingsEachMs = 1000;
|
||||
crl::time LastSettingsQueryMs = 0;
|
||||
|
||||
void QuerySystemNotificationSettings() {
|
||||
auto ms = crl::now();
|
||||
if (LastSettingsQueryMs > 0 && ms <= LastSettingsQueryMs + kQuerySettingsEachMs) {
|
||||
return;
|
||||
}
|
||||
LastSettingsQueryMs = ms;
|
||||
QueryQuietHours();
|
||||
QueryFocusAssist();
|
||||
QueryUserNotificationState();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool SkipAudio() {
|
||||
QuerySystemNotificationSettings();
|
||||
|
||||
if (UserNotificationState == QUNS_NOT_PRESENT
|
||||
|| UserNotificationState == QUNS_PRESENTATION_MODE
|
||||
|| QuietHoursEnabled
|
||||
|| FocusAssistBlocks) {
|
||||
return true;
|
||||
}
|
||||
if (const auto filter = EventFilter::GetInstance()) {
|
||||
if (filter->sessionLoggedOff()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkipToast() {
|
||||
QuerySystemNotificationSettings();
|
||||
|
||||
if (UserNotificationState == QUNS_PRESENTATION_MODE
|
||||
|| UserNotificationState == QUNS_RUNNING_D3D_FULL_SCREEN
|
||||
//|| UserNotificationState == QUNS_BUSY
|
||||
|| QuietHoursEnabled
|
||||
|| FocusAssistBlocks) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkipFlashBounce() {
|
||||
return SkipToast();
|
||||
}
|
||||
|
||||
} // namespace Notifications
|
||||
} // namespace Platform
|
||||
|
||||
@@ -39,6 +39,9 @@ protected:
|
||||
void onAfterNotificationActivated(
|
||||
NotificationId id,
|
||||
not_null<Window::SessionController*> window) override;
|
||||
bool doSkipAudio() const override;
|
||||
bool doSkipToast() const override;
|
||||
bool doSkipFlashBounce() const override;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
|
||||
@@ -93,10 +93,6 @@ EventFilter *EventFilter::CreateInstance(not_null<MainWindow*> window) {
|
||||
return (instance = new EventFilter(window));
|
||||
}
|
||||
|
||||
EventFilter *EventFilter::GetInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
void EventFilter::Destroy() {
|
||||
Expects(instance != nullptr);
|
||||
|
||||
@@ -240,9 +236,9 @@ bool EventFilter::mainWindowEvent(
|
||||
|
||||
case WM_WTSSESSION_CHANGE: {
|
||||
if (wParam == WTS_SESSION_LOGOFF || wParam == WTS_SESSION_LOCK) {
|
||||
setSessionLoggedOff(true);
|
||||
Global::SetScreenIsLocked(true);
|
||||
} else if (wParam == WTS_SESSION_LOGON || wParam == WTS_SESSION_UNLOCK) {
|
||||
setSessionLoggedOff(false);
|
||||
Global::SetScreenIsLocked(false);
|
||||
}
|
||||
} return false;
|
||||
|
||||
|
||||
@@ -20,15 +20,7 @@ public:
|
||||
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result);
|
||||
bool mainWindowEvent(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *result);
|
||||
|
||||
bool sessionLoggedOff() const {
|
||||
return _sessionLoggedOff;
|
||||
}
|
||||
void setSessionLoggedOff(bool loggedOff) {
|
||||
_sessionLoggedOff = loggedOff;
|
||||
}
|
||||
|
||||
static EventFilter *CreateInstance(not_null<MainWindow*> window);
|
||||
static EventFilter *GetInstance();
|
||||
static void Destroy();
|
||||
|
||||
private:
|
||||
@@ -42,7 +34,6 @@ private:
|
||||
LRESULT *result);
|
||||
|
||||
not_null<MainWindow*> _window;
|
||||
bool _sessionLoggedOff = false;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
#include "ui/effects/radial_animation.h"
|
||||
#include "lottie/lottie_icon.h"
|
||||
|
||||
namespace st {
|
||||
extern const style::InfiniteRadialAnimation &callConnectingRadial;
|
||||
} // namespace st
|
||||
|
||||
namespace Ui {
|
||||
|
||||
class BlobsWidget;
|
||||
|
||||
@@ -356,11 +356,35 @@ QRect SeparatePanel::innerGeometry() const {
|
||||
|
||||
void SeparatePanel::initGeometry(QSize size) {
|
||||
const auto active = QApplication::activeWindow();
|
||||
const auto center = !active
|
||||
? QGuiApplication::primaryScreen()->geometry().center()
|
||||
: (active->isVisible() && active->isActiveWindow())
|
||||
? active->geometry().center()
|
||||
: active->windowHandle()->screen()->geometry().center();
|
||||
const auto available = !active
|
||||
? QGuiApplication::primaryScreen()->availableGeometry()
|
||||
: active->windowHandle()->screen()->availableGeometry();
|
||||
const auto parentGeometry = (active
|
||||
&& active->isVisible()
|
||||
&& active->isActiveWindow())
|
||||
? active->geometry()
|
||||
: available;
|
||||
|
||||
auto center = parentGeometry.center();
|
||||
if (size.height() > available.height()) {
|
||||
size = QSize(size.width(), available.height());
|
||||
}
|
||||
if (center.x() + size.width() / 2
|
||||
> available.x() + available.width()) {
|
||||
center.setX(
|
||||
available.x() + available.width() - size.width() / 2);
|
||||
}
|
||||
if (center.x() - size.width() / 2 < available.x()) {
|
||||
center.setX(available.x() + size.width() / 2);
|
||||
}
|
||||
if (center.y() + size.height() / 2
|
||||
> available.y() + available.height()) {
|
||||
center.setY(
|
||||
available.y() + available.height() - size.height() / 2);
|
||||
}
|
||||
if (center.y() - size.height() / 2 < available.y()) {
|
||||
center.setY(available.y() + size.height() / 2);
|
||||
}
|
||||
_useTransparency = Ui::Platform::TranslucentWindowsSupported(center);
|
||||
_padding = _useTransparency
|
||||
? st::callShadow.extend
|
||||
|
||||
@@ -461,6 +461,7 @@ void MainWindow::recountGeometryConstraints() {
|
||||
}
|
||||
|
||||
void MainWindow::initSize() {
|
||||
updateShadowSize();
|
||||
updateMinimumSize();
|
||||
|
||||
if (initSizeFromSystem()) {
|
||||
@@ -562,6 +563,7 @@ void MainWindow::initSize() {
|
||||
}
|
||||
maximized = position.maximized;
|
||||
}
|
||||
geometry += _padding;
|
||||
DEBUG_LOG(("Window Pos: Setting first %1, %2, %3, %4").arg(geometry.x()).arg(geometry.y()).arg(geometry.width()).arg(geometry.height()));
|
||||
setGeometry(geometry);
|
||||
}
|
||||
@@ -679,7 +681,7 @@ void MainWindow::savePosition(Qt::WindowState state) {
|
||||
realPosition.maximized = 1;
|
||||
DEBUG_LOG(("Window Pos: Saving maximized position."));
|
||||
} else {
|
||||
auto r = geometry();
|
||||
auto r = geometry().marginsRemoved(_padding);
|
||||
realPosition.x = r.x();
|
||||
realPosition.y = r.y();
|
||||
realPosition.w = r.width() - (_rightColumn ? _rightColumn->width() : 0);
|
||||
|
||||
@@ -138,6 +138,8 @@ System::SkipState System::skipNotification(
|
||||
}
|
||||
|
||||
void System::schedule(not_null<HistoryItem*> item) {
|
||||
Expects(_manager != nullptr);
|
||||
|
||||
const auto history = item->history();
|
||||
const auto skip = skipNotification(item);
|
||||
if (skip.value == SkipState::Skip) {
|
||||
@@ -167,7 +169,7 @@ void System::schedule(not_null<HistoryItem*> item) {
|
||||
_whenAlerts[history].emplace(when, notifyBy);
|
||||
}
|
||||
if (Core::App().settings().desktopNotify()
|
||||
&& !Platform::Notifications::SkipToast()) {
|
||||
&& !_manager->skipToast()) {
|
||||
auto &whenMap = _whenMaps[history];
|
||||
if (whenMap.find(item->id) == whenMap.end()) {
|
||||
whenMap.emplace(item->id, when);
|
||||
@@ -391,7 +393,7 @@ void System::showNext() {
|
||||
}
|
||||
const auto &settings = Core::App().settings();
|
||||
if (alert) {
|
||||
if (settings.flashBounceNotify() && !Platform::Notifications::SkipFlashBounce()) {
|
||||
if (settings.flashBounceNotify() && !_manager->skipFlashBounce()) {
|
||||
if (const auto window = Core::App().activeWindow()) {
|
||||
if (const auto handle = window->widget()->windowHandle()) {
|
||||
handle->alert(kSystemAlertDuration);
|
||||
@@ -399,7 +401,7 @@ void System::showNext() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (settings.soundNotify() && !Platform::Notifications::SkipAudio()) {
|
||||
if (settings.soundNotify() && !_manager->skipAudio()) {
|
||||
ensureSoundCreated();
|
||||
_soundTrack->playOnce();
|
||||
Media::Player::mixer()->suppressAll(_soundTrack->getLengthMs());
|
||||
@@ -407,7 +409,7 @@ void System::showNext() {
|
||||
}
|
||||
}
|
||||
|
||||
if (_waiters.empty() || !settings.desktopNotify() || Platform::Notifications::SkipToast()) {
|
||||
if (_waiters.empty() || !settings.desktopNotify() || _manager->skipToast()) {
|
||||
if (nextAlert) {
|
||||
_waitTimer.callOnce(nextAlert - ms);
|
||||
}
|
||||
@@ -576,9 +578,10 @@ void System::updateAll() {
|
||||
}
|
||||
}
|
||||
|
||||
Manager::DisplayOptions Manager::GetNotificationOptions(HistoryItem *item) {
|
||||
Manager::DisplayOptions Manager::getNotificationOptions(
|
||||
HistoryItem *item) const {
|
||||
const auto hideEverything = Core::App().passcodeLocked()
|
||||
|| Global::ScreenIsLocked();
|
||||
|| forceHideDetails();
|
||||
|
||||
const auto view = Core::App().settings().notifyView();
|
||||
DisplayOptions result;
|
||||
@@ -696,7 +699,7 @@ void Manager::notificationReplied(
|
||||
void NativeManager::doShowNotification(
|
||||
not_null<HistoryItem*> item,
|
||||
int forwardedCount) {
|
||||
const auto options = GetNotificationOptions(item);
|
||||
const auto options = getNotificationOptions(item);
|
||||
|
||||
const auto peer = item->history()->peer;
|
||||
const auto scheduled = !options.hideNameAndPhoto
|
||||
@@ -732,6 +735,10 @@ void NativeManager::doShowNotification(
|
||||
options.hideReplyButton);
|
||||
}
|
||||
|
||||
bool NativeManager::forceHideDetails() const {
|
||||
return Global::ScreenIsLocked();
|
||||
}
|
||||
|
||||
System::~System() = default;
|
||||
|
||||
QString WrapFromScheduled(const QString &text) {
|
||||
|
||||
@@ -193,8 +193,8 @@ public:
|
||||
bool hideMessageText = false;
|
||||
bool hideReplyButton = false;
|
||||
};
|
||||
[[nodiscard]] static DisplayOptions GetNotificationOptions(
|
||||
HistoryItem *item);
|
||||
[[nodiscard]] DisplayOptions getNotificationOptions(
|
||||
HistoryItem *item) const;
|
||||
|
||||
[[nodiscard]] QString addTargetAccountName(
|
||||
const QString &title,
|
||||
@@ -202,6 +202,16 @@ public:
|
||||
|
||||
[[nodiscard]] virtual ManagerType type() const = 0;
|
||||
|
||||
[[nodiscard]] bool skipAudio() const {
|
||||
return doSkipAudio();
|
||||
}
|
||||
[[nodiscard]] bool skipToast() const {
|
||||
return doSkipToast();
|
||||
}
|
||||
[[nodiscard]] bool skipFlashBounce() const {
|
||||
return doSkipFlashBounce();
|
||||
}
|
||||
|
||||
virtual ~Manager() = default;
|
||||
|
||||
protected:
|
||||
@@ -218,6 +228,12 @@ protected:
|
||||
virtual void doClearFromItem(not_null<HistoryItem*> item) = 0;
|
||||
virtual void doClearFromHistory(not_null<History*> history) = 0;
|
||||
virtual void doClearFromSession(not_null<Main::Session*> session) = 0;
|
||||
virtual bool doSkipAudio() const = 0;
|
||||
virtual bool doSkipToast() const = 0;
|
||||
virtual bool doSkipFlashBounce() const = 0;
|
||||
[[nodiscard]] virtual bool forceHideDetails() const {
|
||||
return false;
|
||||
}
|
||||
virtual void onBeforeNotificationActivated(NotificationId id) {
|
||||
}
|
||||
virtual void onAfterNotificationActivated(
|
||||
@@ -256,6 +272,8 @@ protected:
|
||||
not_null<HistoryItem*> item,
|
||||
int forwardedCount) override;
|
||||
|
||||
bool forceHideDetails() const override;
|
||||
|
||||
virtual void doShowNativeNotification(
|
||||
not_null<PeerData*> peer,
|
||||
std::shared_ptr<Data::CloudImageView> &userpicView,
|
||||
@@ -293,6 +311,15 @@ protected:
|
||||
}
|
||||
void doClearFromSession(not_null<Main::Session*> session) override {
|
||||
}
|
||||
bool doSkipAudio() const override {
|
||||
return false;
|
||||
}
|
||||
bool doSkipToast() const override {
|
||||
return false;
|
||||
}
|
||||
bool doSkipFlashBounce() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -404,6 +404,18 @@ void Manager::doClearFromItem(not_null<HistoryItem*> item) {
|
||||
}
|
||||
}
|
||||
|
||||
bool Manager::doSkipAudio() const {
|
||||
return Platform::Notifications::SkipAudioForCustom();
|
||||
}
|
||||
|
||||
bool Manager::doSkipToast() const {
|
||||
return Platform::Notifications::SkipToastForCustom();
|
||||
}
|
||||
|
||||
bool Manager::doSkipFlashBounce() const {
|
||||
return Platform::Notifications::SkipFlashBounceForCustom();
|
||||
}
|
||||
|
||||
void Manager::doUpdateAll() {
|
||||
for_const (auto ¬ification, _notifications) {
|
||||
notification->updateNotifyDisplay();
|
||||
@@ -725,7 +737,7 @@ void Notification::actionsOpacityCallback() {
|
||||
void Notification::updateNotifyDisplay() {
|
||||
if (!_history || (!_item && _forwardedCount < 2)) return;
|
||||
|
||||
const auto options = Manager::GetNotificationOptions(_item);
|
||||
const auto options = manager()->getNotificationOptions(_item);
|
||||
_hideReplyButton = options.hideReplyButton;
|
||||
|
||||
int32 w = width(), h = height();
|
||||
|
||||
@@ -76,6 +76,9 @@ private:
|
||||
void doClearFromHistory(not_null<History*> history) override;
|
||||
void doClearFromSession(not_null<Main::Session*> session) override;
|
||||
void doClearFromItem(not_null<HistoryItem*> item) override;
|
||||
bool doSkipAudio() const override;
|
||||
bool doSkipToast() const override;
|
||||
bool doSkipFlashBounce() const override;
|
||||
|
||||
void showNextFromQueue();
|
||||
void unlinkFromShown(Notification *remove);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
AppVersion 2007002
|
||||
AppVersion 2007004
|
||||
AppVersionStrMajor 2.7
|
||||
AppVersionStrSmall 2.7.2
|
||||
AppVersionStr 2.7.2
|
||||
AppVersionStrSmall 2.7.4
|
||||
AppVersionStr 2.7.4
|
||||
BetaChannel 0
|
||||
AlphaVersion 0
|
||||
AppVersionOriginal 2.7.2
|
||||
AppVersionOriginal 2.7.4
|
||||
|
||||
Submodule Telegram/lib_base updated: 3d256df61e...356daf59b3
Submodule Telegram/lib_ui updated: eb768c8c4b...14c67cf724
@@ -1,3 +1,15 @@
|
||||
2.7.4 (28.04.21)
|
||||
|
||||
- Fix crash in viewing an invoice after a payment is made.
|
||||
- Respect Focus Assist only for native notifications.
|
||||
- Mark messages as read only in active window.
|
||||
|
||||
2.7.3 (27.04.21)
|
||||
|
||||
- Fix crash on some versions of Linux.
|
||||
- Fix video not stopping when PiP window is closed.
|
||||
- Fix messages marking as read if the Windows session is locked.
|
||||
|
||||
2.7.2 (26.04.21)
|
||||
|
||||
- Offer real goods and services for sale in any group, channel or bot – Telegram doesn't charge a commission.
|
||||
|
||||
@@ -69,6 +69,8 @@ layout:
|
||||
bind: $SNAP/usr/share/alsa
|
||||
/usr/share/X11:
|
||||
bind: $SNAP/usr/share/X11
|
||||
/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/webkit2gtk-4.0:
|
||||
bind: $SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/webkit2gtk-4.0
|
||||
|
||||
parts:
|
||||
telegram:
|
||||
@@ -155,7 +157,7 @@ parts:
|
||||
prime: [-./*]
|
||||
|
||||
desktop-qt5:
|
||||
source: https://github.com/ubuntu/snapcraft-desktop-helpers.git
|
||||
source: https://github.com/desktop-app/snapcraft-desktop-helpers.git
|
||||
source-subdir: qt
|
||||
plugin: make
|
||||
make-parameters: ["FLAVOR=qt5"]
|
||||
|
||||
Reference in New Issue
Block a user