diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 4081dc951d..f6a0b114b9 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -923,6 +923,8 @@ PRIVATE platform/win/windows_dlls.h platform/win/windows_event_filter.cpp platform/win/windows_event_filter.h + platform/win/windows_system_media_controls_manager.cpp + platform/win/windows_system_media_controls_manager.h platform/platform_audio.h platform/platform_file_utilities.h platform/platform_launcher.h diff --git a/Telegram/SourceFiles/platform/win/launcher_win.cpp b/Telegram/SourceFiles/platform/win/launcher_win.cpp index 199c06a42b..a53de34a86 100644 --- a/Telegram/SourceFiles/platform/win/launcher_win.cpp +++ b/Telegram/SourceFiles/platform/win/launcher_win.cpp @@ -139,4 +139,4 @@ bool Launcher::launch( return true; } -} // namespace +} // namespace Platform diff --git a/Telegram/SourceFiles/platform/win/main_window_win.cpp b/Telegram/SourceFiles/platform/win/main_window_win.cpp index 1c71d6bc2c..8692e610d8 100644 --- a/Telegram/SourceFiles/platform/win/main_window_win.cpp +++ b/Telegram/SourceFiles/platform/win/main_window_win.cpp @@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "platform/platform_notifications_manager.h" #include "platform/win/windows_dlls.h" #include "platform/win/windows_event_filter.h" +#include "platform/win/windows_system_media_controls_manager.h" #include "window/notifications_manager.h" #include "mainwindow.h" #include "base/crc32hash.h" @@ -429,6 +430,10 @@ void MainWindow::initHook() { } psInitSysMenu(); + + if (IsWindows10OrGreater()) { + _smtcManager = std::make_unique(psHwnd()); + } } void MainWindow::initShadows() { diff --git a/Telegram/SourceFiles/platform/win/main_window_win.h b/Telegram/SourceFiles/platform/win/main_window_win.h index 28bd7aa40e..246a10e4e6 100644 --- a/Telegram/SourceFiles/platform/win/main_window_win.h +++ b/Telegram/SourceFiles/platform/win/main_window_win.h @@ -20,6 +20,8 @@ class PopupMenu; namespace Platform { +class SystemMediaControlsManager; + class MainWindow : public Window::MainWindow { public: explicit MainWindow(not_null controller); @@ -123,6 +125,8 @@ private: HICON ps_iconSmall = nullptr; HICON ps_iconOverlay = nullptr; + std::unique_ptr _smtcManager; + int _deltaLeft = 0; int _deltaTop = 0; int _deltaRight = 0; diff --git a/Telegram/SourceFiles/platform/win/windows_system_media_controls_manager.cpp b/Telegram/SourceFiles/platform/win/windows_system_media_controls_manager.cpp new file mode 100644 index 0000000000..d783f28028 --- /dev/null +++ b/Telegram/SourceFiles/platform/win/windows_system_media_controls_manager.cpp @@ -0,0 +1,148 @@ +/* +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_system_media_controls_manager.h" + +#include "base/observer.h" +#include "base/platform/win/base_windows_system_media_controls.h" +#include "core/application.h" +#include "data/data_document.h" +#include "data/data_document_media.h" +#include "data/data_file_origin.h" +#include "main/main_session.h" +#include "media/audio/media_audio.h" +#include "media/player/media_player_instance.h" +#include "ui/text/format_song_document_name.h" + +namespace Platform { + +SystemMediaControlsManager::SystemMediaControlsManager(HWND hwnd) +: _controls(std::make_unique()) { + + using PlaybackStatus = + base::Platform::SystemMediaControlsWin::PlaybackStatus; + using Command = base::Platform::SystemMediaControlsWin::Command; + + _controls->init(hwnd); + const auto type = AudioMsgId::Type::Song; + + const auto mediaPlayer = Media::Player::instance(); + + mediaPlayer->updatedNotifier( + ) | rpl::filter([=](const Media::Player::TrackState &state) { + return state.id.type() == type; + }) | rpl::map([=](const Media::Player::TrackState &state) { + using namespace Media::Player; + if (IsStoppedOrStopping(state.state)) { + return PlaybackStatus::Stopped; + } else if (IsPausedOrPausing(state.state)) { + return PlaybackStatus::Paused; + } + return PlaybackStatus::Playing; + }) | rpl::distinct_until_changed( + ) | rpl::start_with_next([=](PlaybackStatus status) { + _controls->setPlaybackStatus(status); + }, _lifetime); + + rpl::merge( + mediaPlayer->stops(type) | rpl::map_to(false), + mediaPlayer->startsPlay(type) | rpl::map_to(true) + ) | rpl::start_with_next([=](bool audio) { + if (audio) { + _controls->setEnabled(audio); + _controls->setIsNextEnabled(mediaPlayer->nextAvailable(type)); + _controls->setIsPreviousEnabled( + mediaPlayer->previousAvailable(type)); + _controls->setIsPlayPauseEnabled(true); + _controls->setIsStopEnabled(true); + _controls->setPlaybackStatus(PlaybackStatus::Playing); + _controls->updateDisplay(); + } else { + _cachedMediaView.clear(); + _controls->clearMetadata(); + } + _lifetimeDownload.destroy(); + }, _lifetime); + + auto trackChanged = base::ObservableViewer( + mediaPlayer->trackChangedNotifier() + ) | rpl::filter([=](AudioMsgId::Type audioType) { + return audioType == type; + }); + + auto unlocked = Core::App().passcodeLockChanges( + ) | rpl::filter([](bool locked) { + return !locked; + }) | rpl::map([=] { + return type; + }) | rpl::before_next([=] { + _controls->setEnabled(true); + _controls->updateDisplay(); + }); + + rpl::merge( + std::move(trackChanged), + std::move(unlocked) + ) | rpl::start_with_next([=](AudioMsgId::Type audioType) { + _lifetimeDownload.destroy(); + + const auto current = mediaPlayer->current(audioType); + if (!current) { + return; + } + const auto document = current.audio(); + + const auto &[title, performer] = Ui::Text::FormatSongNameFor(document) + .composedName(); + + _controls->setArtist(performer); + _controls->setTitle(title); + + if (document && document->isSongWithCover()) { + const auto view = document->createMediaView(); + view->thumbnailWanted(current.contextId()); + _cachedMediaView.push_back(view); + if (const auto imagePtr = view->thumbnail()) { + _controls->setThumbnail(imagePtr->original()); + } else { + document->session().downloaderTaskFinished( + ) | rpl::start_with_next([=] { + if (const auto imagePtr = view->thumbnail()) { + _controls->setThumbnail(imagePtr->original()); + _lifetimeDownload.destroy(); + } + }, _lifetimeDownload); + _controls->clearThumbnail(); + } + } else { + _controls->clearThumbnail(); + } + }, _lifetime); + + _controls->commandRequests( + ) | rpl::start_with_next([=](Command command) { + switch (command) { + case Command::Play: mediaPlayer->play(type); break; + case Command::Pause: mediaPlayer->pause(type); break; + case Command::Next: mediaPlayer->next(type); break; + case Command::Previous: mediaPlayer->previous(type); break; + case Command::Stop: mediaPlayer->stop(type); break; + } + }, _lifetime); + + Core::App().passcodeLockValue( + ) | rpl::filter([=](bool locked) { + return locked && Core::App().maybeActiveSession(); + }) | rpl::start_with_next([=] { + _controls->setEnabled(false); + }, _lifetime); + +} + +SystemMediaControlsManager::~SystemMediaControlsManager() = default; + +} // namespace Platform diff --git a/Telegram/SourceFiles/platform/win/windows_system_media_controls_manager.h b/Telegram/SourceFiles/platform/win/windows_system_media_controls_manager.h new file mode 100644 index 0000000000..76222d9b04 --- /dev/null +++ b/Telegram/SourceFiles/platform/win/windows_system_media_controls_manager.h @@ -0,0 +1,34 @@ +/* +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 base::Platform { +class SystemMediaControlsWin; +} // namespace base::Platform + +namespace Data { +class DocumentMedia; +} // namespace Data + +namespace Platform { + +class SystemMediaControlsManager { +public: + SystemMediaControlsManager(HWND hwnd); + ~SystemMediaControlsManager(); + +private: + const std::unique_ptr _controls; + + std::vector> _cachedMediaView; + + rpl::lifetime _lifetimeDownload; + rpl::lifetime _lifetime; +}; + +} // namespace Platform diff --git a/Telegram/lib_base b/Telegram/lib_base index 95b23bd09b..54f214213c 160000 --- a/Telegram/lib_base +++ b/Telegram/lib_base @@ -1 +1 @@ -Subproject commit 95b23bd09b71c5599b6b89d6c708e7d35b8963aa +Subproject commit 54f214213cc67885a57cb246483893272c986c3a