tray.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "tray.h"
  8. #include "core/application.h"
  9. #include "core/core_settings.h"
  10. #include "platform/platform_notifications_manager.h"
  11. #include "platform/platform_specific.h"
  12. #include "lang/lang_keys.h"
  13. #include <QtWidgets/QApplication>
  14. namespace Core {
  15. Tray::Tray() {
  16. }
  17. void Tray::create() {
  18. rebuildMenu();
  19. using WorkMode = Settings::WorkMode;
  20. if (Core::App().settings().workMode() != WorkMode::WindowOnly) {
  21. _tray.createIcon();
  22. }
  23. Core::App().settings().workModeValue(
  24. ) | rpl::combine_previous(
  25. ) | rpl::start_with_next([=](WorkMode previous, WorkMode state) {
  26. const auto wasHasIcon = (previous != WorkMode::WindowOnly);
  27. const auto nowHasIcon = (state != WorkMode::WindowOnly);
  28. if (wasHasIcon != nowHasIcon) {
  29. if (nowHasIcon) {
  30. _tray.createIcon();
  31. } else {
  32. _tray.destroyIcon();
  33. }
  34. }
  35. }, _tray.lifetime());
  36. Core::App().settings().trayIconMonochromeChanges(
  37. ) | rpl::start_with_next([=] {
  38. updateIconCounters();
  39. }, _tray.lifetime());
  40. Core::App().passcodeLockChanges(
  41. ) | rpl::start_with_next([=] {
  42. rebuildMenu();
  43. }, _tray.lifetime());
  44. _tray.iconClicks(
  45. ) | rpl::start_with_next([=] {
  46. const auto skipTrayClick = (_lastTrayClickTime > 0)
  47. && (crl::now() - _lastTrayClickTime
  48. < QApplication::doubleClickInterval());
  49. if (!skipTrayClick) {
  50. _activeForTrayIconAction = Core::App().isActiveForTrayMenu();
  51. _minimizeMenuItemClicks.fire({});
  52. _lastTrayClickTime = crl::now();
  53. }
  54. }, _tray.lifetime());
  55. }
  56. void Tray::rebuildMenu() {
  57. _tray.destroyMenu();
  58. _tray.createMenu();
  59. {
  60. auto minimizeText = _textUpdates.events(
  61. ) | rpl::map([=] {
  62. _activeForTrayIconAction = Core::App().isActiveForTrayMenu();
  63. return _activeForTrayIconAction
  64. ? tr::lng_minimize_to_tray(tr::now)
  65. : tr::lng_open_from_tray(tr::now);
  66. });
  67. _tray.addAction(
  68. std::move(minimizeText),
  69. [=] { _minimizeMenuItemClicks.fire({}); });
  70. }
  71. if (!Core::App().passcodeLocked()) {
  72. auto notificationsText = _textUpdates.events(
  73. ) | rpl::map([=] {
  74. return Core::App().settings().desktopNotify()
  75. ? tr::lng_disable_notifications_from_tray(tr::now)
  76. : tr::lng_enable_notifications_from_tray(tr::now);
  77. });
  78. _tray.addAction(
  79. std::move(notificationsText),
  80. [=] { toggleSoundNotifications(); });
  81. }
  82. _tray.addAction(tr::lng_quit_from_tray(), [] { Core::Quit(); });
  83. updateMenuText();
  84. }
  85. void Tray::updateMenuText() {
  86. _textUpdates.fire({});
  87. }
  88. void Tray::updateIconCounters() {
  89. _tray.updateIcon();
  90. }
  91. rpl::producer<> Tray::aboutToShowRequests() const {
  92. return _tray.aboutToShowRequests();
  93. }
  94. rpl::producer<> Tray::showFromTrayRequests() const {
  95. return rpl::merge(
  96. _tray.showFromTrayRequests(),
  97. _minimizeMenuItemClicks.events() | rpl::filter([=] {
  98. return !_activeForTrayIconAction;
  99. })
  100. );
  101. }
  102. rpl::producer<> Tray::hideToTrayRequests() const {
  103. auto triggers = rpl::merge(
  104. _tray.hideToTrayRequests(),
  105. _minimizeMenuItemClicks.events() | rpl::filter([=] {
  106. return _activeForTrayIconAction;
  107. })
  108. );
  109. if (_tray.hasTrayMessageSupport()) {
  110. return std::move(triggers) | rpl::map([=]() -> rpl::empty_value {
  111. _tray.showTrayMessage();
  112. return {};
  113. });
  114. } else {
  115. return triggers;
  116. }
  117. }
  118. void Tray::toggleSoundNotifications() {
  119. auto soundNotifyChanged = false;
  120. auto flashBounceNotifyChanged = false;
  121. auto &settings = Core::App().settings();
  122. settings.setDesktopNotify(!settings.desktopNotify());
  123. if (settings.desktopNotify()) {
  124. if (settings.rememberedSoundNotifyFromTray()
  125. && !settings.soundNotify()) {
  126. settings.setSoundNotify(true);
  127. settings.setRememberedSoundNotifyFromTray(false);
  128. soundNotifyChanged = true;
  129. }
  130. if (settings.rememberedFlashBounceNotifyFromTray()
  131. && !settings.flashBounceNotify()) {
  132. settings.setFlashBounceNotify(true);
  133. settings.setRememberedFlashBounceNotifyFromTray(false);
  134. flashBounceNotifyChanged = true;
  135. }
  136. } else {
  137. if (settings.soundNotify()) {
  138. settings.setSoundNotify(false);
  139. settings.setRememberedSoundNotifyFromTray(true);
  140. soundNotifyChanged = true;
  141. } else {
  142. settings.setRememberedSoundNotifyFromTray(false);
  143. }
  144. if (settings.flashBounceNotify()) {
  145. settings.setFlashBounceNotify(false);
  146. settings.setRememberedFlashBounceNotifyFromTray(true);
  147. flashBounceNotifyChanged = true;
  148. } else {
  149. settings.setRememberedFlashBounceNotifyFromTray(false);
  150. }
  151. }
  152. Core::App().saveSettingsDelayed();
  153. using Change = Window::Notifications::ChangeType;
  154. auto &notifications = Core::App().notifications();
  155. notifications.notifySettingsChanged(Change::DesktopEnabled);
  156. if (soundNotifyChanged) {
  157. notifications.notifySettingsChanged(Change::SoundEnabled);
  158. }
  159. if (flashBounceNotifyChanged) {
  160. notifications.notifySettingsChanged(Change::FlashBounceEnabled);
  161. }
  162. }
  163. bool Tray::has() const {
  164. return _tray.hasIcon() && Platform::TrayIconSupported();
  165. }
  166. } // namespace Core