From f10ed4b9bcaa94273ac6e4aaa79844aedf22230c Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 4 Nov 2021 12:35:34 +0400 Subject: [PATCH] Support autostart in Windows Store version. Fixes #3234. --- Telegram/CMakeLists.txt | 23 ++++ Telegram/Resources/langs/lang.strings | 2 + Telegram/Resources/uwp/AppX/AppxManifest.xml | 12 +- .../SourceFiles/_other/startup_task_win.cpp | 54 +++++++++ Telegram/SourceFiles/core/application.cpp | 4 +- Telegram/SourceFiles/logs.cpp | 4 - .../platform/linux/specific_linux.cpp | 60 ++++++---- .../platform/linux/specific_linux.h | 4 +- .../SourceFiles/platform/mac/specific_mac.h | 4 +- .../SourceFiles/platform/mac/specific_mac.mm | 13 +- .../SourceFiles/platform/platform_specific.h | 5 +- .../SourceFiles/platform/win/specific_win.cpp | 54 ++++++++- .../SourceFiles/platform/win/specific_win.h | 1 - .../platform/win/windows_autostart_task.cpp | 111 ++++++++++++++++++ .../platform/win/windows_autostart_task.h | 16 +++ .../settings/settings_advanced.cpp | 21 ++-- Telegram/build/build.bat | 8 ++ 17 files changed, 343 insertions(+), 53 deletions(-) create mode 100644 Telegram/SourceFiles/_other/startup_task_win.cpp create mode 100644 Telegram/SourceFiles/platform/win/windows_autostart_task.cpp create mode 100644 Telegram/SourceFiles/platform/win/windows_autostart_task.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 7979804c1..44e5d26d4 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -982,6 +982,8 @@ PRIVATE platform/win/windows_dlls.h platform/win/windows_event_filter.cpp platform/win/windows_event_filter.h + platform/win/windows_autostart_task.cpp + platform/win/windows_autostart_task.h platform/win/windows_toast_activator.cpp platform/win/windows_toast_activator.h platform/platform_audio.h @@ -1192,6 +1194,13 @@ PRIVATE stdafx.h ) +if (NOT build_winstore) + remove_target_sources(Telegram ${src_loc} + platform/win/windows_start_task.cpp + platform/win/windows_start_task.h + ) +endif() + if (DESKTOP_APP_DISABLE_DBUS_INTEGRATION) remove_target_sources(Telegram ${src_loc} platform/linux/linux_xdp_file_dialog.cpp @@ -1490,6 +1499,20 @@ if ((NOT DESKTOP_APP_DISABLE_AUTOUPDATE OR APPLE) AND NOT build_macstore AND NOT set_target_properties(Packer PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_folder}) endif() +elseif (build_winstore) + add_executable(StartupTask WIN32) + init_non_host_target(StartupTask) + + add_dependencies(Telegram StartupTask) + + nice_target_sources(StartupTask ${src_loc} + PRIVATE + _other/startup_task_win.cpp + ) + + set_target_properties(StartupTask PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${output_folder} + ) endif() if (LINUX AND DESKTOP_APP_USE_PACKAGED) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index e26c4316c..3e4be3074 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -361,6 +361,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_settings_native_frame" = "Use system window frame"; "lng_settings_auto_start" = "Launch Telegram when system starts"; "lng_settings_start_min" = "Launch minimized"; +"lng_settings_auto_start_disabled_uwp" = "Starting with the system was disabled in Windows Settings.\n\nPlease enable Telegram Desktop in the Startup Apps Settings."; +"lng_settings_open_system_settings" = "Open Settings"; "lng_settings_add_sendto" = "Place Telegram in \"Send to\" menu"; "lng_settings_section_scale" = "Interface Scale"; "lng_settings_scale_auto" = "Auto ({cur})"; diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml index 4df1b3c15..21838beb0 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -4,8 +4,9 @@ xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap2="http://schemas.microsoft.com/appx/manifest/uap/windows10/2" xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" + xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" - IgnorableNamespaces="uap uap2 uap3 rescap"> + IgnorableNamespaces="uap uap2 uap3 desktop rescap"> + + + diff --git a/Telegram/SourceFiles/_other/startup_task_win.cpp b/Telegram/SourceFiles/_other/startup_task_win.cpp new file mode 100644 index 000000000..8e780848d --- /dev/null +++ b/Telegram/SourceFiles/_other/startup_task_win.cpp @@ -0,0 +1,54 @@ +/* +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 + +#include +#include + +using namespace std; + +constexpr auto kMaxPathLong = 32767; + +[[nodiscard]] std::wstring ExecutableDirectory() { + auto exePath = std::array{ 0 }; + const auto exeLength = GetModuleFileName( + nullptr, + exePath.data(), + kMaxPathLong + 1); + if (!exeLength || exeLength >= kMaxPathLong + 1) { + return {}; + } + const auto exe = std::wstring(exePath.data()); + const auto last1 = exe.find_last_of('\\'); + const auto last2 = exe.find_last_of('/'); + const auto last = std::max( + (last1 == std::wstring::npos) ? -1 : int(last1), + (last2 == std::wstring::npos) ? -1 : int(last2)); + if (last < 0) { + return {}; + } + return exe.substr(0, last); +} + +int APIENTRY wWinMain( + HINSTANCE instance, + HINSTANCE prevInstance, + LPWSTR cmdParamarg, + int cmdShow) { + const auto directory = ExecutableDirectory(); + if (!directory.empty()) { + ShellExecute( + nullptr, + nullptr, + (directory + L"\\Telegram.exe").c_str(), + L"-autostart", + directory.data(), + SW_SHOWNORMAL); + } + return 0; +} diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp index f69accb57..b777cd25f 100644 --- a/Telegram/SourceFiles/core/application.cpp +++ b/Telegram/SourceFiles/core/application.cpp @@ -226,8 +226,8 @@ void Application::run() { cSetAutoStart(false); } - if (cLaunchMode() == LaunchModeAutoStart && !cAutoStart()) { - psAutoStart(false, true); + if (cLaunchMode() == LaunchModeAutoStart && Platform::AutostartSkip()) { + Platform::AutostartToggle(false); App::quit(); return; } diff --git a/Telegram/SourceFiles/logs.cpp b/Telegram/SourceFiles/logs.cpp index 6d9beeb6a..78544083a 100644 --- a/Telegram/SourceFiles/logs.cpp +++ b/Telegram/SourceFiles/logs.cpp @@ -383,11 +383,7 @@ void start(not_null launcher) { #elif defined OS_WIN_STORE // Q_OS_UNIX || Q_OS_WINRT -#ifdef _DEBUG - cForceWorkingDir(cExeDir()); -#else // _DEBUG cForceWorkingDir(psAppDataPath()); -#endif // !_DEBUG workingDirChosen = true; #elif defined Q_OS_WIN diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.cpp b/Telegram/SourceFiles/platform/linux/specific_linux.cpp index 66acd0b2f..dff7bc434 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/specific_linux.cpp @@ -560,6 +560,41 @@ bool AutostartSupported() { return !InSnap(); } +void AutostartToggle(bool enabled, Fn done) { + const auto guard = gsl::finally([&] { + done(enabled); + }); + +#ifdef __HAIKU__ + + HaikuAutostart(enabled); + +#else // __HAIKU__ + + const auto silent = !done; + if (InFlatpak()) { +#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION + PortalAutostart(enabled, silent); +#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION + } else { + const auto autostart = QStandardPaths::writableLocation( + QStandardPaths::GenericConfigLocation) + + qsl("/autostart/"); + + if (enabled) { + GenerateDesktopFile(autostart, qsl("-autostart"), silent); + } else { + QFile::remove(autostart + QGuiApplication::desktopFileName()); + } + } + +#endif // __HAIKU__ +} + +bool AutostartSkip() { + return !cAutoStart(); +} + bool TrayIconSupported() { return App::wnd() ? App::wnd()->trayAvailable() @@ -637,7 +672,7 @@ QString psAppDataPath() { void psDoCleanup() { try { - psAutoStart(false, true); + Platform::AutostartToggle(false); psSendToMenu(false, true); } catch (...) { } @@ -837,29 +872,6 @@ void psNewVersion() { #endif // __HAIKU__ } -void psAutoStart(bool start, bool silent) { -#ifdef __HAIKU__ - HaikuAutostart(start); - return; -#endif // __HAIKU__ - - if (InFlatpak()) { -#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION - PortalAutostart(start, silent); -#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION - } else { - const auto autostart = QStandardPaths::writableLocation( - QStandardPaths::GenericConfigLocation) - + qsl("/autostart/"); - - if (start) { - GenerateDesktopFile(autostart, qsl("-autostart"), silent); - } else { - QFile::remove(autostart + QGuiApplication::desktopFileName()); - } - } -} - void psSendToMenu(bool send, bool silent) { } diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.h b/Telegram/SourceFiles/platform/linux/specific_linux.h index 7edf24c5c..fa5639aed 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.h +++ b/Telegram/SourceFiles/platform/linux/specific_linux.h @@ -29,6 +29,9 @@ inline void IgnoreApplicationActivationRightNow() { inline void WriteCrashDumpDetails() { } +inline void AutostartRequestStateFromSystem(Fn callback) { +} + } // namespace Platform inline void psCheckLocalSocket(const QString &serverName) { @@ -40,7 +43,6 @@ inline void psCheckLocalSocket(const QString &serverName) { void psActivateProcess(uint64 pid = 0); QString psAppDataPath(); -void psAutoStart(bool start, bool silent = false); void psSendToMenu(bool send, bool silent = false); int psCleanup(); diff --git a/Telegram/SourceFiles/platform/mac/specific_mac.h b/Telegram/SourceFiles/platform/mac/specific_mac.h index 66c940fe9..82010d7c7 100644 --- a/Telegram/SourceFiles/platform/mac/specific_mac.h +++ b/Telegram/SourceFiles/platform/mac/specific_mac.h @@ -22,6 +22,9 @@ inline bool AutostartSupported() { return false; } +inline void AutostartRequestStateFromSystem(Fn callback) { +} + inline bool TrayIconSupported() { return true; } @@ -50,7 +53,6 @@ inline void psCheckLocalSocket(const QString &serverName) { void psActivateProcess(uint64 pid = 0); QString psAppDataPath(); -void psAutoStart(bool start, bool silent = false); void psSendToMenu(bool send, bool silent = false); int psCleanup(); diff --git a/Telegram/SourceFiles/platform/mac/specific_mac.mm b/Telegram/SourceFiles/platform/mac/specific_mac.mm index c6f212c6e..47bef98ba 100644 --- a/Telegram/SourceFiles/platform/mac/specific_mac.mm +++ b/Telegram/SourceFiles/platform/mac/specific_mac.mm @@ -48,7 +48,7 @@ QString psAppDataPath() { void psDoCleanup() { try { - psAutoStart(false, true); + Platform::AutostartToggle(false); psSendToMenu(false, true); } catch (...) { } @@ -181,14 +181,19 @@ void IgnoreApplicationActivationRightNow() { objc_ignoreApplicationActivationRightNow(); } +void AutostartToggle(bool enabled, Fn done) { + done(false); +} + +bool AutostartSkip() { + return !cAutoStart(); +} + } // namespace Platform void psNewVersion() { } -void psAutoStart(bool start, bool silent) { -} - void psSendToMenu(bool send, bool silent) { } diff --git a/Telegram/SourceFiles/platform/platform_specific.h b/Telegram/SourceFiles/platform/platform_specific.h index a220a6867..ba1d2100c 100644 --- a/Telegram/SourceFiles/platform/platform_specific.h +++ b/Telegram/SourceFiles/platform/platform_specific.h @@ -34,7 +34,10 @@ void RequestPermission(PermissionType type, Fn resultCal void OpenSystemSettingsForPermission(PermissionType type); bool OpenSystemSettings(SystemSettingsType type); void IgnoreApplicationActivationRightNow(); -bool AutostartSupported(); +[[nodiscard]] bool AutostartSupported(); +void AutostartRequestStateFromSystem(Fn callback); +void AutostartToggle(bool enabled, Fn done = nullptr); +[[nodiscard]] bool AutostartSkip(); bool TrayIconSupported(); bool SkipTaskbarSupported(); void WriteCrashDumpDetails(); diff --git a/Telegram/SourceFiles/platform/win/specific_win.cpp b/Telegram/SourceFiles/platform/win/specific_win.cpp index c6e752c49..806d3f542 100644 --- a/Telegram/SourceFiles/platform/win/specific_win.cpp +++ b/Telegram/SourceFiles/platform/win/specific_win.cpp @@ -11,10 +11,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "platform/win/notifications_manager_win.h" #include "platform/win/windows_app_user_model_id.h" #include "platform/win/windows_dlls.h" +#include "platform/win/windows_autostart_task.h" #include "base/platform/base_platform_info.h" #include "base/platform/win/base_windows_co_task_mem.h" #include "base/platform/win/base_windows_winrt.h" #include "base/call_delayed.h" +#include "ui/boxes/confirm_box.h" #include "lang/lang_keys.h" #include "mainwindow.h" #include "mainwidget.h" @@ -175,7 +177,7 @@ QString psAppDataPathOld() { void psDoCleanup() { try { - psAutoStart(false, true); + Platform::AutostartToggle(false); psSendToMenu(false, true); AppUserModelId::cleanupShortcut(); DeleteMyModules(); @@ -328,7 +330,51 @@ std::optional IsDarkMode() { } bool AutostartSupported() { - return !IsWindowsStoreBuild(); + return true; +} + +void AutostartRequestStateFromSystem(Fn callback) { +#ifdef OS_WIN_STORE + AutostartTask::RequestState([=](bool enabled) { + crl::on_main([=] { + callback(enabled); + }); + }); +#endif // OS_WIN_STORE +} + +void AutostartToggle(bool enabled, Fn done) { +#ifdef OS_WIN_STORE + const auto requested = enabled; + const auto callback = [=](bool enabled) { crl::on_main([=] { + if (!Core::IsAppLaunched()) { + return; + } + done(enabled); + if (!requested || enabled) { + return; + } else if (const auto window = Core::App().activeWindow()) { + window->show(Box( + tr::lng_settings_auto_start_disabled_uwp(tr::now), + tr::lng_settings_open_system_settings(tr::now), + [] { AutostartTask::OpenSettings(); Ui::hideLayer(); })); + } + }); }; + AutostartTask::Toggle( + enabled, + done ? Fn(callback) : nullptr); +#else // OS_WIN_STORE + _manageAppLnk(start, silent, CSIDL_STARTUP, L"-autostart", L"Telegram autorun link.\nYou can disable autorun in Telegram settings."); + done(enabled); +#endif // OS_WIN_STORE +} + +bool AutostartSkip() { +#ifdef OS_WIN_STORE + return false; +#else // OS_WIN_STORE + return !cAutoStart(); +#endif // OS_WIN_STORE } void WriteCrashDumpDetails() { @@ -534,10 +580,6 @@ void _manageAppLnk(bool create, bool silent, int path_csidl, const wchar_t *args } } -void psAutoStart(bool start, bool silent) { - _manageAppLnk(start, silent, CSIDL_STARTUP, L"-autostart", L"Telegram autorun link.\nYou can disable autorun in Telegram settings."); -} - void psSendToMenu(bool send, bool silent) { _manageAppLnk(send, silent, CSIDL_SENDTO, L"-sendpath", L"Telegram send to link.\nYou can disable send to menu item in Telegram settings."); } diff --git a/Telegram/SourceFiles/platform/win/specific_win.h b/Telegram/SourceFiles/platform/win/specific_win.h index a659e37b3..14700976b 100644 --- a/Telegram/SourceFiles/platform/win/specific_win.h +++ b/Telegram/SourceFiles/platform/win/specific_win.h @@ -43,7 +43,6 @@ inline void psCheckLocalSocket(const QString &) { void psActivateProcess(uint64 pid = 0); QString psAppDataPath(); QString psAppDataPathOld(); -void psAutoStart(bool start, bool silent = false); void psSendToMenu(bool send, bool silent = false); int psCleanup(); diff --git a/Telegram/SourceFiles/platform/win/windows_autostart_task.cpp b/Telegram/SourceFiles/platform/win/windows_autostart_task.cpp new file mode 100644 index 000000000..b6eba5a26 --- /dev/null +++ b/Telegram/SourceFiles/platform/win/windows_autostart_task.cpp @@ -0,0 +1,111 @@ +/* +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/win/windows_autostart_task.h" + +#include "base/platform/win/base_windows_winrt.h" + +#include +#include +#include + +namespace Platform::AutostartTask { +namespace { + +using namespace winrt::Windows::ApplicationModel; +using namespace winrt::Windows::System; +using namespace winrt::Windows::Foundation; + +[[nodiscard]] bool IsEnabled(StartupTaskState state) { + switch (state) { + case StartupTaskState::Enabled: + case StartupTaskState::EnabledByPolicy: + return true; + case StartupTaskState::Disabled: + case StartupTaskState::DisabledByPolicy: + case StartupTaskState::DisabledByUser: + default: + return false; + } +} + +} // namespace + +void Toggle(bool enabled, Fn done) { + if (!base::WinRT::Supported()) { + return; + } + const auto processEnableResult = [=](StartupTaskState state) { + LOG(("Startup Task: Enable finished, state: %1").arg(int(state))); + + done(IsEnabled(state)); + }; + const auto processTask = [=](StartupTask task) { + LOG(("Startup Task: Got it, state: %1, requested: %2" + ).arg(int(task.State()) + ).arg(Logs::b(enabled))); + + if (IsEnabled(task.State()) == enabled) { + return; + } + if (!enabled) { + LOG(("Startup Task: Disabling.")); + task.Disable(); + return; + } + LOG(("Startup Task: Requesting enable.")); + const auto asyncState = task.RequestEnableAsync(); + if (!done) { + return; + } + asyncState.Completed([=]( + IAsyncOperation operation, + AsyncStatus status) { + base::WinRT::Try([&] { + processEnableResult(operation.GetResults()); + }); + }); + }; + base::WinRT::Try([&] { + StartupTask::GetAsync(L"TelegramStartupTask").Completed([=]( + IAsyncOperation operation, + AsyncStatus status) { + base::WinRT::Try([&] { + processTask(operation.GetResults()); + }); + }); + }); +} + +void RequestState(Fn callback) { + Expects(callback != nullptr); + + if (!base::WinRT::Supported()) { + return; + } + const auto processTask = [=](StartupTask task) { + DEBUG_LOG(("Startup Task: Got value, state: %1" + ).arg(int(task.State()))); + + callback(IsEnabled(task.State())); + }; + base::WinRT::Try([&] { + StartupTask::GetAsync(L"TelegramStartupTask").Completed([=]( + IAsyncOperation operation, + AsyncStatus status) { + base::WinRT::Try([&] { + processTask(operation.GetResults()); + }); + }); + }); +} + +void OpenSettings() { + Launcher::LaunchUriAsync(Uri(L"ms-settings:startupapps")); +} + +} // namespace Platform::AutostartTask diff --git a/Telegram/SourceFiles/platform/win/windows_autostart_task.h b/Telegram/SourceFiles/platform/win/windows_autostart_task.h new file mode 100644 index 000000000..6f8fe00f1 --- /dev/null +++ b/Telegram/SourceFiles/platform/win/windows_autostart_task.h @@ -0,0 +1,16 @@ +/* +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 + +namespace Platform::AutostartTask { + +void Toggle(bool enabled, Fn done); +void RequestState(Fn callback); +void OpenSettings(); + +} // namespace Platform::AutostartTask diff --git a/Telegram/SourceFiles/settings/settings_advanced.cpp b/Telegram/SourceFiles/settings/settings_advanced.cpp index 879380bc1..b0b89c2d8 100644 --- a/Telegram/SourceFiles/settings/settings_advanced.cpp +++ b/Telegram/SourceFiles/settings/settings_advanced.cpp @@ -462,16 +462,21 @@ void SetupSystemIntegrationContent( return (checked != cAutoStart()); }) | rpl::start_with_next([=](bool checked) { cSetAutoStart(checked); - psAutoStart(checked); - if (checked) { - Local::writeSettings(); - } else if (minimized->entity()->checked()) { - minimized->entity()->setChecked(false); - } else { - Local::writeSettings(); - } + Platform::AutostartToggle(checked, crl::guard(autostart, [=]( + bool enabled) { + autostart->setChecked(enabled); + if (enabled || !minimized->entity()->checked()) { + Local::writeSettings(); + } else { + minimized->entity()->setChecked(false); + } + })); }, autostart->lifetime()); + Platform::AutostartRequestStateFromSystem(crl::guard( + controller, + [=](bool enabled) { autostart->setChecked(enabled); })); + minimized->toggleOn(autostart->checkedValue()); minimized->entity()->checkedChanges( ) | rpl::filter([=](bool checked) { diff --git a/Telegram/build/build.bat b/Telegram/build/build.bat index 7396e6dfd..7266be18d 100644 --- a/Telegram/build/build.bat +++ b/Telegram/build/build.bat @@ -223,6 +223,13 @@ if %BuildUWP% equ 0 ( set "UpdateFile=!UpdateFile!_!AlphaSignature!" set "PortableFile=talpha!AlphaVersion!_!AlphaSignature!.zip" ) +) else ( +:sign2 + call "%SignPath%" "StartupTask.exe" + if %errorlevel% neq 0 ( + timeout /t 3 + goto sign2 + ) ) for /f ^"usebackq^ eol^=^ @@ -251,6 +258,7 @@ if %BuildUWP% neq 0 ( if %errorlevel% neq 0 goto error xcopy "%ReleasePath%\%BinaryName%.exe" "%ReleasePath%\AppX\" + xcopy "%ReleasePath%\StartupTask.exe" "%ReleasePath%\AppX\" xcopy "%ReleasePath%\modules\%Platform%\d3d\d3dcompiler_47.dll" "%ReleasePath%\AppX\modules\%Platform%\d3d\" MakeAppx.exe pack /d "%ReleasePath%\AppX" /l /p ..\out\Release\%BinaryName%.%Platform%.appx