/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "mtproto/mtproto_auth_key.h" #include "mtproto/mtproto_proxy_data.h" #include "base/timer.h" class History; namespace base { class BatterySaving; } // namespace base namespace Platform { class Integration; } // namespace Platform namespace Storage { class Databases; } // namespace Storage namespace Window { class Controller; } // namespace Window namespace Window { namespace Notifications { class System; } // namespace Notifications } // namespace Window namespace ChatHelpers { class EmojiKeywords; } // namespace ChatHelpers namespace Main { class Domain; class Account; class Session; } // namespace Main namespace Ui { namespace Animations { class Manager; } // namespace Animations namespace Emoji { class UniversalImages; } // namespace Emoji class BoxContent; } // namespace Ui namespace MTP { class Config; class Instance; class AuthKey; using AuthKeyPtr = std::shared_ptr; using AuthKeysList = std::vector; } // namespace MTP namespace Media { namespace Audio { class Instance; } // namespace Audio namespace View { class OverlayWidget; struct OpenRequest; } // namespace View namespace Player { class FloatController; class FloatDelegate; } // namespace Player class SystemMediaControlsManager; } // namespace Media namespace Lang { class Instance; class Translator; class CloudManager; } // namespace Lang namespace Data { struct CloudTheme; class DownloadManager; } // namespace Data namespace Stickers { class EmojiImageLoader; } // namespace Stickers namespace Export { class Manager; } // namespace Export namespace Calls { class Instance; } // namespace Calls namespace Core { class Launcher; struct LocalUrlHandler; class Settings; class Tray; enum class LaunchState { Running, QuitRequested, QuitProcessed, }; enum class QuitReason { Default, QtQuitEvent, }; class Application final : public QObject { public: struct ProxyChange { MTP::ProxyData was; MTP::ProxyData now; }; Application(not_null launcher); Application(const Application &other) = delete; Application &operator=(const Application &other) = delete; ~Application(); void run(); [[nodiscard]] Launcher &launcher() const { return *_launcher; } [[nodiscard]] Platform::Integration &platformIntegration() const { return *_platformIntegration; } [[nodiscard]] Ui::Animations::Manager &animationManager() const { return *_animationsManager; } [[nodiscard]] Window::Notifications::System ¬ifications() const { Expects(_notifications != nullptr); return *_notifications; } [[nodiscard]] Data::DownloadManager &downloadManager() const { return *_downloadManager; } [[nodiscard]] Tray &tray() const { return *_tray; } [[nodiscard]] base::BatterySaving &batterySaving() const { return *_batterySaving; } // Windows interface. bool hasActiveWindow(not_null session) const; [[nodiscard]] bool savingPositionFor( not_null window) const; [[nodiscard]] Window::Controller *activeWindow() const; [[nodiscard]] Window::Controller *activePrimaryWindow() const; [[nodiscard]] Window::Controller *separateWindowForAccount( not_null account) const; [[nodiscard]] Window::Controller *separateWindowForPeer( not_null peer) const; Window::Controller *ensureSeparateWindowForPeer( not_null peer, MsgId showAtMsgId); Window::Controller *ensureSeparateWindowForAccount( not_null account); [[nodiscard]] Window::Controller *windowFor( // Doesn't auto-switch. not_null peer) const; [[nodiscard]] Window::Controller *windowFor( // Doesn't auto-switch. not_null account) const; [[nodiscard]] bool closeNonLastAsync( not_null window); void closeWindow(not_null window); void windowActivated(not_null window); bool closeActiveWindow(); bool minimizeActiveWindow(); bool toggleActiveWindowFullScreen(); [[nodiscard]] QWidget *getFileDialogParent(); void notifyFileDialogShown(bool shown); void checkSystemDarkMode(); [[nodiscard]] bool isActiveForTrayMenu() const; void closeChatFromWindows(not_null peer); void checkWindowAccount(not_null window); void activate(); // Media view interface. bool hideMediaView(); [[nodiscard]] QPoint getPointForCallPanelCenter() const; void startSettingsAndBackground(); [[nodiscard]] Settings &settings(); [[nodiscard]] const Settings &settings() const; void saveSettingsDelayed(crl::time delay = kDefaultSaveDelay); void saveSettings(); [[nodiscard]] bool canReadDefaultDownloadPath(bool always = false) const; [[nodiscard]] bool canSaveFileWithoutAskingForPath() const; // Fallback config and proxy. [[nodiscard]] MTP::Config &fallbackProductionConfig() const; void refreshFallbackProductionConfig(const MTP::Config &config); void constructFallbackProductionConfig(const QByteArray &serialized); void setCurrentProxy( const MTP::ProxyData &proxy, MTP::ProxyData::Settings settings); [[nodiscard]] rpl::producer proxyChanges() const; void badMtprotoConfigurationError(); // Databases. [[nodiscard]] Storage::Databases &databases() { return *_databases; } // Domain component. [[nodiscard]] Main::Domain &domain() const { return *_domain; } [[nodiscard]] Main::Account &activeAccount() const; [[nodiscard]] bool someSessionExists() const; [[nodiscard]] Export::Manager &exportManager() const { return *_exportManager; } [[nodiscard]] bool exportPreventsQuit(); // Main::Session component. Main::Session *maybePrimarySession() const; [[nodiscard]] int unreadBadge() const; [[nodiscard]] bool unreadBadgeMuted() const; [[nodiscard]] rpl::producer<> unreadBadgeChanges() const; // Media component. [[nodiscard]] Media::Audio::Instance &audio() { return *_audio; } // Langpack and emoji keywords. [[nodiscard]] Lang::Instance &langpack() { return *_langpack; } [[nodiscard]] Lang::CloudManager *langCloudManager() { return _langCloudManager.get(); } [[nodiscard]] bool offerLegacyLangPackSwitch() const; [[nodiscard]] bool canApplyLangPackWithoutRestart() const; [[nodiscard]] ChatHelpers::EmojiKeywords &emojiKeywords() { return *_emojiKeywords; } [[nodiscard]] auto emojiImageLoader() const -> const crl::object_on_queue & { return _emojiImageLoader; } // Internal links. void checkStartUrl(); void checkSendPaths(); bool openLocalUrl(const QString &url, QVariant context); bool openInternalUrl(const QString &url, QVariant context); [[nodiscard]] QString changelogLink() const; // Float player. void floatPlayerToggleGifsPaused(bool paused); [[nodiscard]] rpl::producer floatPlayerClosed() const; // Calls. Calls::Instance &calls() const { return *_calls; } void logout(Main::Account *account = nullptr); void logoutWithChecks(Main::Account *account); void forceLogOut( not_null account, const TextWithEntities &explanation); [[nodiscard]] bool uploadPreventsQuit(); [[nodiscard]] bool downloadPreventsQuit(); void checkLocalTime(); void lockByPasscode(); void maybeLockByPasscode(); void unlockPasscode(); [[nodiscard]] bool passcodeLocked() const; rpl::producer passcodeLockChanges() const; rpl::producer passcodeLockValue() const; void checkAutoLock(crl::time lastNonIdleTime = 0); void checkAutoLockIn(crl::time time); void localPasscodeChanged(); [[nodiscard]] bool preventsQuit(QuitReason reason); [[nodiscard]] crl::time lastNonIdleTime() const; void updateNonIdle(); void registerLeaveSubscription(not_null widget); void unregisterLeaveSubscription(not_null widget); // Sandbox interface. void postponeCall(FnMut &&callable); void refreshGlobalProxy(); void refreshApplicationIcon(); void quitPreventFinished(); void handleAppActivated(); void handleAppDeactivated(); [[nodiscard]] rpl::producer appDeactivatedValue() const; void switchDebugMode(); void writeInstallBetaVersionsSetting(); void preventOrInvoke(Fn &&callback); // Global runtime variables. void setScreenIsLocked(bool locked); bool screenIsLocked() const; static void RegisterUrlScheme(); protected: bool eventFilter(QObject *object, QEvent *event) override; private: static constexpr auto kDefaultSaveDelay = crl::time(1000); friend bool IsAppLaunched(); friend Application &App(); void clearEmojiSourceImages(); [[nodiscard]] auto prepareEmojiSourceImages() -> std::shared_ptr; void startLocalStorage(); void startShortcuts(); void startDomain(); void startEmojiImageLoader(); void startSystemDarkModeViewer(); void startMediaView(); void startTray(); void createTray(); void updateWindowTitles(); void setLastActiveWindow(Window::Controller *window); void showAccount(not_null account); void enumerateWindows( Fn)> callback) const; void processCreatedWindow(not_null window); void refreshApplicationIcon(Main::Session *session); friend void QuitAttempt(); void quitDelayed(); [[nodiscard]] bool readyToQuit(); void showOpenGLCrashNotification(); void clearPasscodeLock(); bool openCustomUrl( const QString &protocol, const std::vector &handlers, const QString &url, const QVariant &context); static Application *Instance; struct InstanceSetter { InstanceSetter(not_null instance) { Expects(Instance == nullptr); Instance = instance; } }; InstanceSetter _setter = { this }; const not_null _launcher; rpl::event_stream _proxyChanges; // Some fields are just moved from the declaration. struct Private; const std::unique_ptr _private; const std::unique_ptr _platformIntegration; const std::unique_ptr _batterySaving; const std::unique_ptr _databases; const std::unique_ptr _animationsManager; crl::object_on_queue _emojiImageLoader; base::Timer _clearEmojiImageLoaderTimer; const std::unique_ptr _audio; mutable std::unique_ptr _fallbackProductionConfig; // Notifications should be destroyed before _audio, after _domain. // Mutable because is created in run() after OpenSSL is inited. std::unique_ptr _notifications; using MediaControlsManager = Media::SystemMediaControlsManager; std::unique_ptr _mediaControlsManager; const std::unique_ptr _downloadManager; const std::unique_ptr _domain; const std::unique_ptr _exportManager; const std::unique_ptr _calls; base::flat_map< Main::Account*, std::unique_ptr> _primaryWindows; base::flat_set> _closingAsyncWindows; base::flat_map< not_null, std::unique_ptr> _secondaryWindows; std::vector> _windowStack; Window::Controller *_lastActiveWindow = nullptr; Window::Controller *_lastActivePrimaryWindow = nullptr; Window::Controller *_windowInSettings = nullptr; std::unique_ptr _mediaView; const std::unique_ptr _langpack; const std::unique_ptr _langCloudManager; const std::unique_ptr _emojiKeywords; std::unique_ptr _translator; QPointer _badProxyDisableBox; const std::unique_ptr _tray; std::unique_ptr _floatPlayers; rpl::lifetime _floatPlayerDelegateLifetime; bool _floatPlayerGifsPaused = false; rpl::variable _passcodeLock; bool _screenIsLocked = false; crl::time _shouldLockAt = 0; base::Timer _autoLockTimer; std::optional _saveSettingsTimer; struct LeaveFilter { std::vector> registered; QPointer filter; }; base::flat_map, LeaveFilter> _leaveFilters; rpl::event_stream _openInMediaViewRequests; rpl::lifetime _lifetime; crl::time _lastNonIdleTime = 0; }; [[nodiscard]] bool IsAppLaunched(); [[nodiscard]] Application &App(); [[nodiscard]] LaunchState CurrentLaunchState(); void SetLaunchState(LaunchState state); void Quit(QuitReason reason = QuitReason::Default); [[nodiscard]] bool Quitting(); void Restart(); } // namespace Core