integration_win.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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 "platform/win/integration_win.h"
  8. #include "base/platform/win/base_windows_winrt.h"
  9. #include "core/application.h"
  10. #include "core/core_settings.h"
  11. #include "core/sandbox.h"
  12. #include "lang/lang_keys.h"
  13. #include "platform/win/windows_app_user_model_id.h"
  14. #include "platform/win/tray_win.h"
  15. #include "platform/platform_integration.h"
  16. #include "platform/platform_specific.h"
  17. #include "tray.h"
  18. #include "styles/style_window.h"
  19. #include <QtCore/QAbstractNativeEventFilter>
  20. #include <private/qguiapplication_p.h>
  21. #include <propvarutil.h>
  22. #include <propkey.h>
  23. namespace Platform {
  24. void WindowsIntegration::init() {
  25. #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
  26. using namespace QNativeInterface::Private;
  27. const auto native = qApp->nativeInterface<QWindowsApplication>();
  28. if (native) {
  29. native->setHasBorderInFullScreenDefault(true);
  30. }
  31. #endif // Qt >= 6.5.0
  32. QCoreApplication::instance()->installNativeEventFilter(this);
  33. _taskbarCreatedMsgId = RegisterWindowMessage(L"TaskbarButtonCreated");
  34. }
  35. ITaskbarList3 *WindowsIntegration::taskbarList() const {
  36. return _taskbarList.get();
  37. }
  38. WindowsIntegration &WindowsIntegration::Instance() {
  39. return static_cast<WindowsIntegration&>(Integration::Instance());
  40. }
  41. bool WindowsIntegration::nativeEventFilter(
  42. const QByteArray &eventType,
  43. void *message,
  44. native_event_filter_result *result) {
  45. return Core::Sandbox::Instance().customEnterFromEventLoop([&] {
  46. const auto msg = static_cast<MSG*>(message);
  47. return processEvent(
  48. msg->hwnd,
  49. msg->message,
  50. msg->wParam,
  51. msg->lParam,
  52. (LRESULT*)result);
  53. });
  54. }
  55. void WindowsIntegration::createCustomJumpList() {
  56. _jumpList = base::WinRT::TryCreateInstance<ICustomDestinationList>(
  57. CLSID_DestinationList);
  58. if (_jumpList) {
  59. refreshCustomJumpList();
  60. }
  61. }
  62. void WindowsIntegration::refreshCustomJumpList() {
  63. auto added = false;
  64. auto maxSlots = UINT();
  65. auto removed = (IObjectArray*)nullptr;
  66. auto hr = _jumpList->BeginList(&maxSlots, IID_PPV_ARGS(&removed));
  67. if (!SUCCEEDED(hr)) {
  68. return;
  69. }
  70. const auto guard = gsl::finally([&] {
  71. if (added) {
  72. _jumpList->CommitList();
  73. } else {
  74. _jumpList->AbortList();
  75. }
  76. });
  77. auto shellLink = base::WinRT::TryCreateInstance<IShellLink>(
  78. CLSID_ShellLink);
  79. if (!shellLink) {
  80. return;
  81. }
  82. // Set the path to your application and the command-line argument for quitting
  83. const auto exe = QDir::toNativeSeparators(cExeDir() + cExeName());
  84. const auto dir = QDir::toNativeSeparators(QDir(cWorkingDir()).absolutePath());
  85. const auto icon = Tray::QuitJumpListIconPath();
  86. shellLink->SetArguments(L"-quit");
  87. shellLink->SetPath(exe.toStdWString().c_str());
  88. shellLink->SetWorkingDirectory(dir.toStdWString().c_str());
  89. shellLink->SetIconLocation(icon.toStdWString().c_str(), 0);
  90. if (const auto propertyStore = shellLink.try_as<IPropertyStore>()) {
  91. auto appIdPropVar = PROPVARIANT();
  92. hr = InitPropVariantFromString(
  93. AppUserModelId::Id().c_str(),
  94. &appIdPropVar);
  95. if (SUCCEEDED(hr)) {
  96. hr = propertyStore->SetValue(
  97. AppUserModelId::Key(),
  98. appIdPropVar);
  99. PropVariantClear(&appIdPropVar);
  100. }
  101. auto titlePropVar = PROPVARIANT();
  102. hr = InitPropVariantFromString(
  103. tr::lng_quit_from_tray(tr::now).toStdWString().c_str(),
  104. &titlePropVar);
  105. if (SUCCEEDED(hr)) {
  106. hr = propertyStore->SetValue(PKEY_Title, titlePropVar);
  107. PropVariantClear(&titlePropVar);
  108. }
  109. propertyStore->Commit();
  110. }
  111. auto collection = base::WinRT::TryCreateInstance<IObjectCollection>(
  112. CLSID_EnumerableObjectCollection);
  113. if (!collection) {
  114. return;
  115. }
  116. collection->AddObject(shellLink.get());
  117. _jumpList->AddUserTasks(collection.get());
  118. added = true;
  119. }
  120. bool WindowsIntegration::processEvent(
  121. HWND hWnd,
  122. UINT msg,
  123. WPARAM wParam,
  124. LPARAM lParam,
  125. LRESULT *result) {
  126. if (msg && msg == _taskbarCreatedMsgId && !_taskbarList) {
  127. _taskbarList = base::WinRT::TryCreateInstance<ITaskbarList3>(
  128. CLSID_TaskbarList,
  129. CLSCTX_ALL);
  130. if (_taskbarList) {
  131. createCustomJumpList();
  132. }
  133. }
  134. switch (msg) {
  135. case WM_ENDSESSION:
  136. Core::Quit();
  137. break;
  138. case WM_TIMECHANGE:
  139. Core::App().checkAutoLockIn(100);
  140. break;
  141. case WM_WTSSESSION_CHANGE:
  142. if (wParam == WTS_SESSION_LOGOFF
  143. || wParam == WTS_SESSION_LOCK) {
  144. Core::App().setScreenIsLocked(true);
  145. } else if (wParam == WTS_SESSION_LOGON
  146. || wParam == WTS_SESSION_UNLOCK) {
  147. Core::App().setScreenIsLocked(false);
  148. }
  149. break;
  150. case WM_SETTINGCHANGE:
  151. RefreshTaskbarThemeValue();
  152. #if QT_VERSION < QT_VERSION_CHECK(6, 5, 0)
  153. Core::App().settings().setSystemDarkMode(Platform::IsDarkMode());
  154. #endif // Qt < 6.5.0
  155. Core::App().tray().updateIconCounters();
  156. if (_jumpList) {
  157. refreshCustomJumpList();
  158. }
  159. break;
  160. }
  161. return false;
  162. }
  163. std::unique_ptr<Integration> CreateIntegration() {
  164. return std::make_unique<WindowsIntegration>();
  165. }
  166. } // namespace Platform