diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index f484089579..4005911faf 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -1373,6 +1373,8 @@ PRIVATE media/system_media_controls_manager.cpp menu/menu_antispam_validator.cpp menu/menu_antispam_validator.h + menu/menu_dock.cpp + menu/menu_dock.h menu/menu_item_download_files.cpp menu/menu_item_download_files.h menu/menu_item_rate_transcribe_session.cpp diff --git a/Telegram/SourceFiles/menu/menu_dock.cpp b/Telegram/SourceFiles/menu/menu_dock.cpp new file mode 100644 index 0000000000..dc8704f365 --- /dev/null +++ b/Telegram/SourceFiles/menu/menu_dock.cpp @@ -0,0 +1,83 @@ +/* +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 "menu/menu_dock.h" + +#include "core/application.h" +#include "core/core_settings.h" +#include "data/data_user.h" +#include "lang/lang_keys.h" +#include "main/main_account.h" +#include "main/main_domain.h" +#include "main/main_session.h" +#include "media/audio/media_audio.h" +#include "media/player/media_player_instance.h" +#include "ui/text/text_utilities.h" + +#include + +namespace Menu { + +void RefreshDockMenu(QMenu *menu) { + menu->clear(); + if (!Core::IsAppLaunched()) { + return; + } + + const auto accounts = Core::App().domain().orderedAccounts(); + if (accounts.size() > 1) { + menu->addSeparator(); + const auto profilesHeader = menu->addAction( + tr::lng_mac_menu_profiles(tr::now)); + profilesHeader->setEnabled(false); + constexpr auto kMaxLength = 30; + for (const auto &account : accounts) { + if (account->sessionExists()) { + const auto name = account->session().user()->name(); + menu->addAction( + (name.size() > kMaxLength) + ? (name.mid(0, kMaxLength) + Ui::kQEllipsis) + : name, + [account] { + Core::App().ensureSeparateWindowFor(account); + }); + } + } + menu->addSeparator(); + } + + menu->addAction( + Core::App().settings().desktopNotify() + ? tr::lng_disable_notifications_from_tray(tr::now) + : tr::lng_enable_notifications_from_tray(tr::now), + [] { + auto &settings = Core::App().settings(); + settings.setDesktopNotify(!settings.desktopNotify()); + }); + + using namespace Media::Player; + const auto type = instance()->getActiveType(); + const auto state = instance()->getState(type); + if (!IsStoppedOrStopping(state.state)) { + menu->addSeparator(); + const auto previous = menu->addAction( + tr::lng_mac_menu_player_previous(tr::now), + [] { instance()->previous(); }); + previous->setEnabled(instance()->previousAvailable(type)); + menu->addAction( + IsPausedOrPausing(state.state) + ? tr::lng_mac_menu_player_resume(tr::now) + : tr::lng_mac_menu_player_pause(tr::now), + [] { instance()->playPause(); }); + const auto next = menu->addAction( + tr::lng_mac_menu_player_next(tr::now), + [] { instance()->next(); }); + next->setEnabled(instance()->nextAvailable(type)); + } +} + +} // namespace Menu diff --git a/Telegram/SourceFiles/menu/menu_dock.h b/Telegram/SourceFiles/menu/menu_dock.h new file mode 100644 index 0000000000..d7e2982a1f --- /dev/null +++ b/Telegram/SourceFiles/menu/menu_dock.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 + +class QMenu; + +namespace Menu { + +void RefreshDockMenu(QMenu *menu); + +} // namespace Menu diff --git a/Telegram/SourceFiles/platform/mac/specific_mac_p.mm b/Telegram/SourceFiles/platform/mac/specific_mac_p.mm index f02c356f84..d72da3a884 100644 --- a/Telegram/SourceFiles/platform/mac/specific_mac_p.mm +++ b/Telegram/SourceFiles/platform/mac/specific_mac_p.mm @@ -9,28 +9,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mainwindow.h" #include "mainwidget.h" -#include "main/main_account.h" -#include "main/main_domain.h" -#include "main/main_session.h" -#include "data/data_user.h" #include "calls/calls_instance.h" #include "core/sandbox.h" #include "core/application.h" #include "core/core_settings.h" #include "core/crash_reports.h" +#include "menu/menu_dock.h" #include "storage/localstorage.h" #include "media/audio/media_audio.h" -#include "media/player/media_player_instance.h" #include "window/window_controller.h" #include "base/platform/mac/base_utilities_mac.h" #include "base/platform/base_platform_info.h" -#include "lang/lang_keys.h" #include "base/timer.h" #include "styles/style_window.h" #include "platform/platform_specific.h" #include #include +#include #if __has_include() #include #endif // __has_include() @@ -49,47 +45,16 @@ namespace { constexpr auto kIgnoreActivationTimeoutMs = 500; -NSMenuItem *CreateMenuItem( - QString title, - rpl::lifetime &lifetime, - Fn callback, - bool enabled = true) { - id block = [^{ - Core::Sandbox::Instance().customEnterFromEventLoop(callback); - } copy]; - - NSMenuItem *item = [[NSMenuItem alloc] - initWithTitle:Q2NSString(title) - action:@selector(invoke) - keyEquivalent:@""]; - [item setTarget:block]; - [item setEnabled:enabled]; - - lifetime.add([=] { - [block release]; +void SetupDockMenu() { + static const auto DockMenu = std::make_unique(); + QObject::connect(DockMenu.get(), &QMenu::aboutToShow, [] { + Menu::RefreshDockMenu(DockMenu.get()); }); - return [item autorelease]; + DockMenu->setAsDockMenu(); } } // namespace -@interface RpMenu : NSMenu { -} - -- (rpl::lifetime &) lifetime; - -@end // @interface Menu - -@implementation RpMenu { - rpl::lifetime _lifetime; -} - -- (rpl::lifetime &) lifetime { - return _lifetime; -} - -@end // @implementation Menu - @interface qVisualize : NSObject { } @@ -144,8 +109,6 @@ NSMenuItem *CreateMenuItem( - (void) ignoreApplicationActivationRightNow; -- (NSMenu *) applicationDockMenu:(NSApplication *)sender; - @end // @interface ApplicationDelegate ApplicationDelegate *_sharedDelegate = nil; @@ -220,83 +183,6 @@ ApplicationDelegate *_sharedDelegate = nil; _ignoreActivationStop.callOnce(kIgnoreActivationTimeoutMs); } -- (NSMenu *) applicationDockMenu:(NSApplication *)sender { - if (!Core::IsAppLaunched()) { - return nil; - } - RpMenu* dockMenu = [[[RpMenu alloc] initWithTitle: @""] autorelease]; - [dockMenu setAutoenablesItems:false]; - - const auto accounts = Core::App().domain().orderedAccounts(); - if (accounts.size() > 1) { - [dockMenu addItem:[NSMenuItem separatorItem]]; - NSMenuItem *profilesHeader = [[NSMenuItem alloc] - initWithTitle:@"" action:nil keyEquivalent:@""]; - NSDictionary *attributes = @{ - NSFontAttributeName: [NSFont - menuFontOfSize:[NSFont smallSystemFontSize]], - NSForegroundColorAttributeName: [NSColor secondaryLabelColor] - }; - NSAttributedString *attrTitle = [[NSAttributedString alloc] - initWithString:Q2NSString(tr::lng_mac_menu_profiles(tr::now)) - attributes:attributes]; - [profilesHeader setAttributedTitle:attrTitle]; - [attrTitle release]; - [profilesHeader setEnabled:NO]; - [dockMenu addItem:[profilesHeader autorelease]]; - constexpr auto kMaxLength = 30; - for (const auto &account : accounts) { - if (account->sessionExists()) { - auto name = account->session().user()->name(); - [dockMenu addItem:CreateMenuItem( - (name.size() > kMaxLength) - ? (name.mid(0, kMaxLength) + Ui::kQEllipsis) - : name, - [dockMenu lifetime], - [account] { - Core::App().ensureSeparateWindowFor(account); - })]; - } - } - [dockMenu addItem:[NSMenuItem separatorItem]]; - } - - auto notifyCallback = [] { - auto &settings = Core::App().settings(); - settings.setDesktopNotify(!settings.desktopNotify()); - }; - [dockMenu addItem:CreateMenuItem( - Core::App().settings().desktopNotify() - ? tr::lng_disable_notifications_from_tray(tr::now) - : tr::lng_enable_notifications_from_tray(tr::now), - [dockMenu lifetime], - std::move(notifyCallback))]; - - using namespace Media::Player; - const auto state = instance()->getState(instance()->getActiveType()); - if (!IsStoppedOrStopping(state.state)) { - [dockMenu addItem:[NSMenuItem separatorItem]]; - [dockMenu addItem:CreateMenuItem( - tr::lng_mac_menu_player_previous(tr::now), - [dockMenu lifetime], - [] { instance()->previous(); }, - instance()->previousAvailable(instance()->getActiveType()))]; - [dockMenu addItem:CreateMenuItem( - IsPausedOrPausing(state.state) - ? tr::lng_mac_menu_player_resume(tr::now) - : tr::lng_mac_menu_player_pause(tr::now), - [dockMenu lifetime], - [] { instance()->playPause(); })]; - [dockMenu addItem:CreateMenuItem( - tr::lng_mac_menu_player_next(tr::now), - [dockMenu lifetime], - [] { instance()->next(); }, - instance()->nextAvailable(instance()->getActiveType()))]; - } - - return dockMenu; -} - @end // @implementation ApplicationDelegate namespace Platform { @@ -348,6 +234,8 @@ void objc_start() { addObserver: _sharedDelegate selector: @selector(receiveWakeNote:) name: NSWorkspaceDidWakeNotification object: NULL]; + + crl::on_main([=] { SetupDockMenu(); }); } void objc_ignoreApplicationActivationRightNow() {