diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index fa0ba3c726..c2868db11b 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -37,6 +37,11 @@ include(cmake/td_scheme.cmake) include(cmake/td_ui.cmake) include(cmake/generate_appdata_changelog.cmake) +if (WIN32) + include(cmake/generate_midl.cmake) + generate_midl(Telegram ${src_loc}/platform/win/windows_quiethours.idl) +endif() + set_target_properties(Telegram PROPERTIES AUTOMOC ON AUTORCC ON) target_link_libraries(Telegram diff --git a/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp b/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp index 9ea6c222bc..65a001655a 100644 --- a/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp +++ b/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp @@ -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 "windows_quiethours_h.h" #include #include @@ -632,27 +633,30 @@ namespace { bool QuietHoursEnabled = false; DWORD QuietHoursValue = 0; -bool useQuietHoursRegistryEntry() { - // 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( - GetProcAddress(library, "RtlGetVersion")); - if (RtlGetVersion) { - RtlGetVersion(&result); +[[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( + 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); + // 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()) { +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. @@ -683,9 +687,82 @@ void queryQuietHours() { } } +bool FocusAssistBlocks = false; + +void QueryFocusAssist() { + ComPtr 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(".unrestricted", Qt::CaseInsensitive)) { + if (FocusAssistBlocks) { + LOG(("Focus Assist: Unrestricted.")); + FocusAssistBlocks = false; + } + return; + } else if (profileName.endsWith(".alarmsonly", Qt::CaseInsensitive)) { + if (!FocusAssistBlocks) { + LOG(("Focus Assist: Alarms Only.")); + FocusAssistBlocks = true; + } + 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 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() { +void QueryUserNotificationState() { if (Dlls::SHQueryUserNotificationState != nullptr) { QUERY_USER_NOTIFICATION_STATE state; if (SUCCEEDED(Dlls::SHQueryUserNotificationState(&state))) { @@ -697,24 +774,26 @@ void queryUserNotificationState() { static constexpr auto kQuerySettingsEachMs = 1000; crl::time LastSettingsQueryMs = 0; -void querySystemNotificationSettings() { +void QuerySystemNotificationSettings() { auto ms = crl::now(); if (LastSettingsQueryMs > 0 && ms <= LastSettingsQueryMs + kQuerySettingsEachMs) { return; } LastSettingsQueryMs = ms; - queryQuietHours(); - queryUserNotificationState(); + QueryQuietHours(); + QueryFocusAssist(); + QueryUserNotificationState(); } } // namespace bool SkipAudio() { - querySystemNotificationSettings(); + QuerySystemNotificationSettings(); if (UserNotificationState == QUNS_NOT_PRESENT || UserNotificationState == QUNS_PRESENTATION_MODE - || QuietHoursEnabled) { + || QuietHoursEnabled + || FocusAssistBlocks) { return true; } if (const auto filter = EventFilter::GetInstance()) { @@ -726,12 +805,13 @@ bool SkipAudio() { } bool SkipToast() { - querySystemNotificationSettings(); + QuerySystemNotificationSettings(); if (UserNotificationState == QUNS_PRESENTATION_MODE || UserNotificationState == QUNS_RUNNING_D3D_FULL_SCREEN //|| UserNotificationState == QUNS_BUSY - || QuietHoursEnabled) { + || QuietHoursEnabled + || FocusAssistBlocks) { return true; } return false; diff --git a/Telegram/SourceFiles/platform/win/windows_quiethours.idl b/Telegram/SourceFiles/platform/win/windows_quiethours.idl new file mode 100644 index 0000000000..15e6e85bb4 --- /dev/null +++ b/Telegram/SourceFiles/platform/win/windows_quiethours.idl @@ -0,0 +1,79 @@ +// © Rafael Rivera +// License: MIT + +import "oaidl.idl"; + +[uuid(e0b5ef8b-a9b4-497a-8f71-08dd5c8ab2bf)] +library QuietHours +{ + [uuid(f53321fa-34f8-4b7f-b9a3-361877cb94cf)] + coclass QuietHoursSettings + { + [default] interface IQuietHoursSettings; + } + + [uuid(af86e2e0-b12d-4c6a-9c5a-d7aa65101e90)] + interface IQuietMoment : IUnknown + { + // Incomplete + } + + [uuid(e813fe81-62b6-417d-b951-9d2e08486ac1)] + interface IQuietHoursProfile : IUnknown + { + [propget] HRESULT DisplayName([out, string, retval] LPWSTR* displayName); + [propget] HRESULT ProfileId([out, string, retval] LPWSTR* profileId); + HRESULT GetSetting(int setting, [out, retval] int* value); + HRESULT PutSetting(int setting, int value); + [propget] HRESULT IsCustomizable([out, retval] BOOL* result); + HRESULT GetAllowedContacts([out] UINT32* count, [out, retval] LPWSTR* allowedContacts); + HRESULT AddAllowedContact([in, string] LPWSTR allowedContact); + HRESULT RemoveAllowedContact([in, string] LPWSTR allowedContact); + HRESULT GetAllowedApps([out] UINT32* count, [out, retval] LPWSTR** allowedApps); + HRESULT AddAllowedApp([in, string] LPWSTR allowedApp); + HRESULT RemoveAllowedApp([in, string] LPWSTR allowedApp); + [propget] HRESULT Description([out, string, retval] LPWSTR* description); + [propget] HRESULT CustomizeLinkText([out, string, retval] LPWSTR* linkText); + [propget] HRESULT RestrictiveLevel([out, string, retval] LPWSTR* restrictiveLevel); + } + + [uuid(cd86a976-8ea9-404b-a197-42e73dbaa901)] + interface IQuietHoursPinnedContactManager : IUnknown + { + HRESULT GetPinnedContactList([out] UINT32* count, [out, string, retval] LPWSTR* pinnedContacts); + } + + [uuid(b0217783-87b7-422c-b902-5c148c14f150)] + interface IQuietMomentsManager : IUnknown + { + HRESULT GetAllQuietMomentModes([out] UINT32* count, [out, retval] UINT32** quietMomentModes); + HRESULT GetQuietMoment([in] UINT32 quietMomentId, [out, retval] IQuietMoment** quietMoment); + HRESULT TurnOffCurrentlyActiveQuietMoment(); + HRESULT GetActiveQuietMoment([out, retval] UINT32* quietMomentId); + } + + typedef struct _QH_PROFILE_DATA + { + char do_not_use__incomplete; // Incomplete + } QH_PROFILE_DATA; + + [uuid(6bff4732-81ec-4ffb-ae67-b6c1bc29631f)] + interface IQuietHoursSettings : IUnknown + { + [propget] HRESULT UserSelectedProfile([out, string, retval] LPWSTR* profileId); + [propput] HRESULT UserSelectedProfile([in] LPWSTR profileId); + HRESULT GetProfile([in, string] LPWSTR profileId, [out, retval] IQuietHoursProfile**); + HRESULT GetAllProfileData(UINT32* count, QH_PROFILE_DATA*); + HRESULT GetDisplayNameForProfile([in, string] LPWSTR profileId, [out, string, retval] LPWSTR* displayName); + [propget] HRESULT QuietMomentsManager([out, retval] IQuietMomentsManager**); + [propget] HRESULT OffProfileId([out, string, retval] LPWSTR* profileId); + [propget] HRESULT ActiveQuietMomentProfile([out, string, retval] LPWSTR* profileId); + [propput] HRESULT ActiveQuietMomentProfile([in] LPWSTR profileId); + [propget] HRESULT ActiveProfile([out, string, retval] LPWSTR* profileId); + [propget] HRESULT QuietHoursPinnedContactManager([out, retval] IQuietHoursPinnedContactManager**); + [propput] HRESULT QuietMomentsShowSummaryEnabled([out, retval] BOOL* isEnabled); + HRESULT GetAlwaysAllowedApps([out] UINT32* count, [out, string, retval] LPWSTR** allowedApps); + HRESULT StartProcessing(); + HRESULT StopProcessing(); + } +} diff --git a/Telegram/cmake/generate_midl.cmake b/Telegram/cmake/generate_midl.cmake new file mode 100644 index 0000000000..d40477f753 --- /dev/null +++ b/Telegram/cmake/generate_midl.cmake @@ -0,0 +1,43 @@ +# 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 + +function(generate_midl target_name idl_file) + set(gen_dst ${CMAKE_CURRENT_BINARY_DIR}/gen) + file(MAKE_DIRECTORY ${gen_dst}) + + get_filename_component(idl_file_name ${idl_file} NAME_WLE) + + set(gen_timestamp ${gen_dst}/midl_${idl_file_name}.timestamp) + set(gen_files + ${gen_dst}/${idl_file_name}_i.c + ${gen_dst}/${idl_file_name}_h.h + ) + + if (build_win64) + set(env x64) + else() + set(env win32) + endif() + add_custom_command( + OUTPUT + ${gen_timestamp} + BYPRODUCTS + ${gen_files} + COMMAND + midl + /out ${gen_dst} + /h ${idl_file_name}_h.h + /env ${env} + /notlb + ${idl_file} + COMMAND + echo 1> ${gen_timestamp} + COMMENT "Generating header from IDL (${target_name})" + DEPENDS + ${idl_file} + ) + generate_target(${target_name} midl ${gen_timestamp} "${gen_files}" ${gen_dst}) +endfunction() diff --git a/Telegram/lib_base b/Telegram/lib_base index 053ab218df..3d256df61e 160000 --- a/Telegram/lib_base +++ b/Telegram/lib_base @@ -1 +1 @@ -Subproject commit 053ab218dfb65e9cbd7c7a1d9594fa886ba27f0b +Subproject commit 3d256df61ebf4b92b79bf9eba39a33f7a885b1d3