main_window_win.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  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/main_window_win.h"
  8. #include "styles/style_window.h"
  9. #include "platform/platform_specific.h"
  10. #include "platform/platform_notifications_manager.h"
  11. #include "platform/win/tray_win.h"
  12. #include "platform/win/windows_dlls.h"
  13. #include "platform/win/integration_win.h"
  14. #include "window/notifications_manager.h"
  15. #include "window/window_session_controller.h"
  16. #include "mainwindow.h"
  17. #include "main/main_session.h"
  18. #include "base/crc32hash.h"
  19. #include "base/platform/win/base_windows_wrl.h"
  20. #include "base/platform/base_platform_info.h"
  21. #include "core/application.h"
  22. #include "core/sandbox.h"
  23. #include "lang/lang_keys.h"
  24. #include "storage/localstorage.h"
  25. #include "ui/widgets/popup_menu.h"
  26. #include "ui/ui_utility.h"
  27. #include "window/themes/window_theme.h"
  28. #include "window/window_controller.h"
  29. #include "history/history.h"
  30. #include <QtWidgets/QStyleFactory>
  31. #include <QtWidgets/QApplication>
  32. #include <QtGui/QWindow>
  33. #include <QtGui/QScreen>
  34. #include <QtCore/QOperatingSystemVersion>
  35. #include <Shobjidl.h>
  36. #include <shellapi.h>
  37. #include <WtsApi32.h>
  38. #include <dwmapi.h>
  39. #include <windows.ui.viewmanagement.h>
  40. #include <UIViewSettingsInterop.h>
  41. #include <Windowsx.h>
  42. #include <VersionHelpers.h>
  43. // Taken from qtbase/src/gui/image/qpixmap_win.cpp
  44. HICON qt_pixmapToWinHICON(const QPixmap &);
  45. HBITMAP qt_imageToWinHBITMAP(const QImage &, int hbitmapFormat);
  46. namespace ViewManagement = ABI::Windows::UI::ViewManagement;
  47. namespace Platform {
  48. namespace {
  49. // Mouse down on tray icon deactivates the application.
  50. // So there is no way to know for sure if the tray icon was clicked from
  51. // active application or from inactive application. So we assume that
  52. // if the application was deactivated less than 0.5s ago, then the tray
  53. // icon click (both left or right button) was made from the active app.
  54. constexpr auto kKeepActiveForTrayIcon = crl::time(500);
  55. using namespace Microsoft::WRL;
  56. // Taken from qtbase/src/gui/image/qpixmap_win.cpp
  57. enum HBitmapFormat {
  58. HBitmapNoAlpha,
  59. HBitmapPremultipliedAlpha,
  60. HBitmapAlpha
  61. };
  62. class EventFilter final : public QAbstractNativeEventFilter {
  63. public:
  64. explicit EventFilter(not_null<MainWindow*> window);
  65. private:
  66. bool nativeEventFilter(
  67. const QByteArray &eventType,
  68. void *message,
  69. native_event_filter_result *result) override;
  70. bool mainWindowEvent(
  71. HWND hWnd,
  72. UINT msg,
  73. WPARAM wParam,
  74. LPARAM lParam,
  75. LRESULT *result);
  76. const not_null<MainWindow*> _window;
  77. };
  78. [[nodiscard]] HICON NativeIcon(const QIcon &icon, QSize size) {
  79. if (!icon.isNull()) {
  80. const auto pixmap = icon.pixmap(icon.actualSize(size));
  81. if (!pixmap.isNull()) {
  82. return qt_pixmapToWinHICON(pixmap);
  83. }
  84. }
  85. return nullptr;
  86. }
  87. struct RealSize {
  88. QSize value;
  89. bool maximized = false;
  90. };
  91. [[nodiscard]] RealSize DetectRealSize(HWND hwnd) {
  92. auto result = RECT();
  93. auto placement = WINDOWPLACEMENT();
  94. if (!GetWindowPlacement(hwnd, &placement)) {
  95. return {};
  96. } else if (placement.flags & WPF_RESTORETOMAXIMIZED) {
  97. const auto monitor = MonitorFromRect(
  98. &placement.rcNormalPosition,
  99. MONITOR_DEFAULTTONULL);
  100. if (!monitor) {
  101. return {};
  102. }
  103. auto info = MONITORINFO{ .cbSize = sizeof(MONITORINFO) };
  104. if (!GetMonitorInfo(monitor, &info)) {
  105. return {};
  106. }
  107. result = info.rcWork;
  108. } else {
  109. CopyRect(&result, &placement.rcNormalPosition);
  110. }
  111. return {
  112. { int(result.right - result.left), int(result.bottom - result.top) },
  113. ((placement.flags & WPF_RESTORETOMAXIMIZED) != 0)
  114. };
  115. }
  116. [[nodiscard]] QImage PrepareLogoPreview(
  117. QSize size,
  118. QImage::Format format,
  119. int radius = 0) {
  120. auto result = QImage(size, QImage::Format_RGB32);
  121. result.fill(st::windowBg->c);
  122. const auto logo = Window::Logo();
  123. const auto width = size.width();
  124. const auto height = size.height();
  125. const auto side = logo.width();
  126. const auto skip = width / 8;
  127. const auto use = std::min({ width - skip, height - skip, side });
  128. auto p = QPainter(&result);
  129. if (use == side) {
  130. p.drawImage((width - side) / 2, (height - side) / 2, logo);
  131. } else {
  132. const auto scaled = logo.scaled(
  133. use,
  134. use,
  135. Qt::KeepAspectRatio,
  136. Qt::SmoothTransformation);
  137. p.drawImage((width - use) / 2, (height - use) / 2, scaled);
  138. }
  139. p.end();
  140. return radius
  141. ? Images::Round(std::move(result), Images::CornersMask(radius))
  142. : result;
  143. }
  144. EventFilter::EventFilter(not_null<MainWindow*> window) : _window(window) {
  145. }
  146. bool EventFilter::nativeEventFilter(
  147. const QByteArray &eventType,
  148. void *message,
  149. native_event_filter_result *result) {
  150. return Core::Sandbox::Instance().customEnterFromEventLoop([&] {
  151. const auto msg = static_cast<MSG*>(message);
  152. if (msg->hwnd == _window->psHwnd()
  153. || msg->hwnd && !_window->psHwnd()) {
  154. return mainWindowEvent(
  155. msg->hwnd,
  156. msg->message,
  157. msg->wParam,
  158. msg->lParam,
  159. (LRESULT*)result);
  160. }
  161. return false;
  162. });
  163. }
  164. bool EventFilter::mainWindowEvent(
  165. HWND hWnd,
  166. UINT msg,
  167. WPARAM wParam,
  168. LPARAM lParam,
  169. LRESULT *result) {
  170. switch (msg) {
  171. case WM_DESTROY: {
  172. _window->destroyedFromSystem();
  173. } return false;
  174. case WM_ACTIVATE: {
  175. if (LOWORD(wParam) != WA_INACTIVE) {
  176. _window->shadowsActivate();
  177. } else {
  178. _window->shadowsDeactivate();
  179. }
  180. } return false;
  181. case WM_SIZE: {
  182. if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED || wParam == SIZE_MINIMIZED) {
  183. if (wParam == SIZE_RESTORED && _window->windowState() == Qt::WindowNoState) {
  184. _window->positionUpdated();
  185. }
  186. }
  187. } return false;
  188. case WM_MOVE: {
  189. _window->positionUpdated();
  190. } return false;
  191. case WM_DWMSENDICONICTHUMBNAIL: {
  192. if (!Core::App().passcodeLocked()) {
  193. return false;
  194. }
  195. const auto size = QSize(int(HIWORD(lParam)), int(LOWORD(lParam)));
  196. return _window->setDwmThumbnail(size);
  197. }
  198. case WM_DWMSENDICONICLIVEPREVIEWBITMAP: {
  199. if (!Core::App().passcodeLocked()) {
  200. return false;
  201. }
  202. const auto size = DetectRealSize(hWnd);
  203. const auto radius = size.maximized ? 0 : style::ConvertScale(8);
  204. return _window->setDwmPreview(size.value, radius);
  205. }
  206. }
  207. return false;
  208. }
  209. } // namespace
  210. struct MainWindow::Private {
  211. explicit Private(not_null<MainWindow*> window) : filter(window) {
  212. }
  213. EventFilter filter;
  214. ComPtr<ViewManagement::IUIViewSettings> viewSettings;
  215. };
  216. MainWindow::BitmapPointer::BitmapPointer(HBITMAP value) : _value(value) {
  217. }
  218. MainWindow::BitmapPointer::BitmapPointer(BitmapPointer &&other)
  219. : _value(base::take(other._value)) {
  220. }
  221. MainWindow::BitmapPointer &MainWindow::BitmapPointer::operator=(
  222. BitmapPointer &&other) {
  223. if (_value != other._value) {
  224. reset();
  225. _value = base::take(other._value);
  226. }
  227. return *this;
  228. }
  229. MainWindow::BitmapPointer::~BitmapPointer() {
  230. reset();
  231. }
  232. HBITMAP MainWindow::BitmapPointer::get() const {
  233. return _value;
  234. }
  235. MainWindow::BitmapPointer::operator bool() const {
  236. return _value != nullptr;
  237. }
  238. void MainWindow::BitmapPointer::release() {
  239. _value = nullptr;
  240. }
  241. void MainWindow::BitmapPointer::reset(HBITMAP value) {
  242. if (_value != value) {
  243. if (const auto old = std::exchange(_value, value)) {
  244. DeleteObject(old);
  245. }
  246. }
  247. }
  248. MainWindow::MainWindow(not_null<Window::Controller*> controller)
  249. : Window::MainWindow(controller)
  250. , _private(std::make_unique<Private>(this))
  251. , _taskbarHiderWindow(std::make_unique<QWindow>()) {
  252. qApp->installNativeEventFilter(&_private->filter);
  253. setupNativeWindowFrame();
  254. SetWindowPriority(this, controller->isPrimary() ? 2 : 1);
  255. using namespace rpl::mappers;
  256. Core::App().appDeactivatedValue(
  257. ) | rpl::distinct_until_changed(
  258. ) | rpl::filter(_1) | rpl::start_with_next([=] {
  259. _lastDeactivateTime = crl::now();
  260. }, lifetime());
  261. setupPreviewPasscodeLock();
  262. }
  263. void MainWindow::setupPreviewPasscodeLock() {
  264. Core::App().passcodeLockValue(
  265. ) | rpl::start_with_next([=](bool locked) {
  266. // Use iconic bitmap instead of the window content if passcoded.
  267. BOOL fForceIconic = locked ? TRUE : FALSE;
  268. BOOL fHasIconicBitmap = fForceIconic;
  269. DwmSetWindowAttribute(
  270. _hWnd,
  271. DWMWA_FORCE_ICONIC_REPRESENTATION,
  272. &fForceIconic,
  273. sizeof(fForceIconic));
  274. DwmSetWindowAttribute(
  275. _hWnd,
  276. DWMWA_HAS_ICONIC_BITMAP,
  277. &fHasIconicBitmap,
  278. sizeof(fHasIconicBitmap));
  279. }, lifetime());
  280. }
  281. void MainWindow::setupNativeWindowFrame() {
  282. auto nativeFrame = rpl::single(
  283. Core::App().settings().nativeWindowFrame()
  284. ) | rpl::then(
  285. Core::App().settings().nativeWindowFrameChanges()
  286. );
  287. rpl::combine(
  288. std::move(nativeFrame),
  289. Window::Theme::IsNightModeValue()
  290. ) | rpl::skip(1) | rpl::start_with_next([=](bool native, bool night) {
  291. validateWindowTheme(native, night);
  292. }, lifetime());
  293. }
  294. void MainWindow::shadowsActivate() {
  295. _hasActiveFrame = true;
  296. }
  297. void MainWindow::shadowsDeactivate() {
  298. _hasActiveFrame = false;
  299. }
  300. void MainWindow::destroyedFromSystem() {
  301. if (!Core::App().closeNonLastAsync(&controller())) {
  302. Core::Quit();
  303. }
  304. }
  305. bool MainWindow::setDwmThumbnail(QSize size) {
  306. validateDwmPreviewColors();
  307. if (size.isEmpty()) {
  308. return false;
  309. } else if (!_dwmThumbnail || _dwmThumbnailSize != size) {
  310. const auto result = PrepareLogoPreview(size, QImage::Format_RGB32);
  311. const auto bitmap = qt_imageToWinHBITMAP(result, HBitmapNoAlpha);
  312. if (!bitmap) {
  313. return false;
  314. }
  315. _dwmThumbnail.reset(bitmap);
  316. _dwmThumbnailSize = size;
  317. }
  318. DwmSetIconicThumbnail(_hWnd, _dwmThumbnail.get(), NULL);
  319. return true;
  320. }
  321. bool MainWindow::setDwmPreview(QSize size, int radius) {
  322. Expects(radius >= 0);
  323. validateDwmPreviewColors();
  324. if (size.isEmpty()) {
  325. return false;
  326. } else if (!_dwmPreview
  327. || _dwmPreviewSize != size
  328. || _dwmPreviewRadius != radius) {
  329. const auto format = (radius > 0)
  330. ? QImage::Format_ARGB32_Premultiplied
  331. : QImage::Format_RGB32;
  332. const auto result = PrepareLogoPreview(size, format, radius);
  333. const auto bitmap = qt_imageToWinHBITMAP(
  334. result,
  335. (radius > 0) ? HBitmapPremultipliedAlpha : HBitmapNoAlpha);
  336. if (!bitmap) {
  337. return false;
  338. }
  339. _dwmPreview.reset(bitmap);
  340. _dwmPreviewRadius = radius;
  341. _dwmPreviewSize = size;
  342. }
  343. const auto flags = 0;
  344. DwmSetIconicLivePreviewBitmap(_hWnd, _dwmPreview.get(), NULL, flags);
  345. return true;
  346. }
  347. void MainWindow::validateDwmPreviewColors() {
  348. if (_dwmBackground == st::windowBg->c) {
  349. return;
  350. }
  351. _dwmBackground = st::windowBg->c;
  352. _dwmThumbnail.reset();
  353. _dwmPreview.reset();
  354. }
  355. void MainWindow::forceIconRefresh() {
  356. const auto refresher = std::make_unique<QWidget>(this);
  357. refresher->setWindowFlags(
  358. static_cast<Qt::WindowFlags>(Qt::Tool) | Qt::FramelessWindowHint);
  359. refresher->setGeometry(x() + 1, y() + 1, 1, 1);
  360. auto palette = refresher->palette();
  361. palette.setColor(
  362. QPalette::Window,
  363. (isActiveWindow() ? st::titleBgActive : st::titleBg)->c);
  364. refresher->setPalette(palette);
  365. refresher->show();
  366. refresher->raise();
  367. refresher->activateWindow();
  368. updateTaskbarAndIconCounters();
  369. }
  370. void MainWindow::workmodeUpdated(Core::Settings::WorkMode mode) {
  371. using WorkMode = Core::Settings::WorkMode;
  372. switch (mode) {
  373. case WorkMode::WindowAndTray: {
  374. HWND psOwner = (HWND)GetWindowLongPtr(_hWnd, GWLP_HWNDPARENT);
  375. if (psOwner) {
  376. SetWindowLongPtr(_hWnd, GWLP_HWNDPARENT, 0);
  377. windowHandle()->setTransientParent(nullptr);
  378. forceIconRefresh();
  379. }
  380. } break;
  381. case WorkMode::TrayOnly: {
  382. HWND psOwner = (HWND)GetWindowLongPtr(_hWnd, GWLP_HWNDPARENT);
  383. if (!psOwner) {
  384. const auto hwnd = _taskbarHiderWindow->winId();
  385. SetWindowLongPtr(_hWnd, GWLP_HWNDPARENT, (LONG_PTR)hwnd);
  386. windowHandle()->setTransientParent(_taskbarHiderWindow.get());
  387. }
  388. } break;
  389. case WorkMode::WindowOnly: {
  390. HWND psOwner = (HWND)GetWindowLongPtr(_hWnd, GWLP_HWNDPARENT);
  391. if (psOwner) {
  392. SetWindowLongPtr(_hWnd, GWLP_HWNDPARENT, 0);
  393. windowHandle()->setTransientParent(nullptr);
  394. forceIconRefresh();
  395. }
  396. } break;
  397. }
  398. }
  399. bool MainWindow::hasTabletView() const {
  400. if (!_private->viewSettings) {
  401. return false;
  402. }
  403. auto mode = ViewManagement::UserInteractionMode();
  404. _private->viewSettings->get_UserInteractionMode(&mode);
  405. return (mode == ViewManagement::UserInteractionMode_Touch);
  406. }
  407. bool MainWindow::initGeometryFromSystem() {
  408. if (!hasTabletView() || !screen()) {
  409. return false;
  410. }
  411. Ui::RpWidget::setGeometry(screen()->availableGeometry());
  412. return true;
  413. }
  414. bool MainWindow::nativeEvent(
  415. const QByteArray &eventType,
  416. void *message,
  417. native_event_filter_result *result) {
  418. if (message) {
  419. const auto msg = static_cast<MSG*>(message);
  420. if (msg->message == WM_IME_STARTCOMPOSITION) {
  421. Core::Sandbox::Instance().customEnterFromEventLoop([&] {
  422. imeCompositionStartReceived();
  423. });
  424. }
  425. }
  426. return false;
  427. }
  428. void MainWindow::updateWindowIcon() {
  429. updateTaskbarAndIconCounters();
  430. }
  431. bool MainWindow::isActiveForTrayMenu() {
  432. return !_lastDeactivateTime
  433. || (_lastDeactivateTime + kKeepActiveForTrayIcon >= crl::now());
  434. }
  435. void MainWindow::unreadCounterChangedHook() {
  436. updateTaskbarAndIconCounters();
  437. }
  438. void MainWindow::updateTaskbarAndIconCounters() {
  439. const auto counter = Core::App().unreadBadge();
  440. const auto muted = Core::App().unreadBadgeMuted();
  441. const auto controller = sessionController();
  442. const auto session = controller ? &controller->session() : nullptr;
  443. const auto iconSizeSmall = QSize(
  444. GetSystemMetrics(SM_CXSMICON),
  445. GetSystemMetrics(SM_CYSMICON));
  446. const auto iconSizeBig = QSize(
  447. GetSystemMetrics(SM_CXICON),
  448. GetSystemMetrics(SM_CYICON));
  449. const auto supportMode = session && session->supportMode();
  450. auto iconSmallPixmap16 = Tray::IconWithCounter(
  451. Tray::CounterLayerArgs(16, counter, muted),
  452. true,
  453. false,
  454. supportMode);
  455. auto iconSmallPixmap32 = Tray::IconWithCounter(
  456. Tray::CounterLayerArgs(32, counter, muted),
  457. true,
  458. false,
  459. supportMode);
  460. QIcon iconSmall, iconBig;
  461. iconSmall.addPixmap(iconSmallPixmap16);
  462. iconSmall.addPixmap(iconSmallPixmap32);
  463. const auto integration = &Platform::WindowsIntegration::Instance();
  464. const auto taskbarList = integration->taskbarList();
  465. const auto bigCounter = taskbarList ? 0 : counter;
  466. iconBig.addPixmap(Tray::IconWithCounter(
  467. Tray::CounterLayerArgs(32, bigCounter, muted),
  468. false,
  469. false,
  470. supportMode));
  471. iconBig.addPixmap(Tray::IconWithCounter(
  472. Tray::CounterLayerArgs(64, bigCounter, muted),
  473. false,
  474. false,
  475. supportMode));
  476. destroyCachedIcons();
  477. _iconSmall = NativeIcon(iconSmall, iconSizeSmall);
  478. _iconBig = NativeIcon(iconBig, iconSizeBig);
  479. SendMessage(_hWnd, WM_SETICON, ICON_SMALL, (LPARAM)_iconSmall);
  480. SendMessage(_hWnd, WM_SETICON, ICON_BIG, (LPARAM)(_iconBig ? _iconBig : _iconSmall));
  481. if (taskbarList) {
  482. if (counter > 0) {
  483. const auto pixmap = [&](int size) {
  484. return Ui::PixmapFromImage(Window::GenerateCounterLayer(
  485. Tray::CounterLayerArgs(size, counter, muted)));
  486. };
  487. QIcon iconOverlay;
  488. iconOverlay.addPixmap(pixmap(16));
  489. iconOverlay.addPixmap(pixmap(32));
  490. _iconOverlay = NativeIcon(iconOverlay, iconSizeSmall);
  491. }
  492. const auto description = (counter > 0)
  493. ? tr::lng_unread_bar(tr::now, lt_count, counter).toStdWString()
  494. : std::wstring();
  495. taskbarList->SetOverlayIcon(_hWnd, _iconOverlay, description.c_str());
  496. }
  497. SetWindowPos(_hWnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  498. }
  499. void MainWindow::initHook() {
  500. _hWnd = reinterpret_cast<HWND>(winId());
  501. if (!_hWnd) {
  502. return;
  503. }
  504. WTSRegisterSessionNotification(_hWnd, NOTIFY_FOR_THIS_SESSION);
  505. using namespace base::Platform;
  506. auto factory = ComPtr<IUIViewSettingsInterop>();
  507. if (SupportsWRL()) {
  508. ABI::Windows::Foundation::GetActivationFactory(
  509. StringReferenceWrapper(
  510. RuntimeClass_Windows_UI_ViewManagement_UIViewSettings).Get(),
  511. &factory);
  512. if (factory) {
  513. // NB! No such method (or IUIViewSettingsInterop) in C++/WinRT :(
  514. factory->GetForWindow(
  515. _hWnd,
  516. IID_PPV_ARGS(&_private->viewSettings));
  517. }
  518. }
  519. validateWindowTheme(
  520. Core::App().settings().nativeWindowFrame(),
  521. Window::Theme::IsNightMode());
  522. }
  523. void MainWindow::validateWindowTheme(bool native, bool night) {
  524. if (!IsWindows8OrGreater()) {
  525. const auto empty = native ? nullptr : L" ";
  526. SetWindowTheme(_hWnd, empty, empty);
  527. QApplication::setStyle(QStyleFactory::create(u"Windows"_q));
  528. #if 0
  529. } else if (!Core::App().settings().systemDarkMode().has_value()/*
  530. || (!Dlls::AllowDarkModeForApp && !Dlls::SetPreferredAppMode)
  531. || !Dlls::AllowDarkModeForWindow
  532. || !Dlls::RefreshImmersiveColorPolicyState
  533. || !Dlls::FlushMenuThemes*/) {
  534. return;
  535. #endif
  536. } else if (!native) {
  537. SetWindowTheme(_hWnd, nullptr, nullptr);
  538. return;
  539. }
  540. // See "https://github.com/microsoft/terminal/blob/"
  541. // "eb480b6bbbd83a2aafbe62992d360838e0ab9da5/"
  542. // "src/interactivity/win32/windowtheme.cpp#L43-L63"
  543. auto darkValue = BOOL(night ? TRUE : FALSE);
  544. const auto updateStyle = [&] {
  545. static const auto kSystemVersion = QOperatingSystemVersion::current();
  546. if (kSystemVersion.microVersion() >= 18875 && Dlls::SetWindowCompositionAttribute) {
  547. Dlls::WINDOWCOMPOSITIONATTRIBDATA data = {
  548. Dlls::WINDOWCOMPOSITIONATTRIB::WCA_USEDARKMODECOLORS,
  549. &darkValue,
  550. sizeof(darkValue)
  551. };
  552. Dlls::SetWindowCompositionAttribute(_hWnd, &data);
  553. } else if (kSystemVersion.microVersion() >= 17763) {
  554. static const auto kDWMWA_USE_IMMERSIVE_DARK_MODE = (kSystemVersion.microVersion() >= 18985)
  555. ? DWORD(20)
  556. : DWORD(19);
  557. DwmSetWindowAttribute(
  558. _hWnd,
  559. kDWMWA_USE_IMMERSIVE_DARK_MODE,
  560. &darkValue,
  561. sizeof(darkValue));
  562. }
  563. };
  564. updateStyle();
  565. // See "https://osdn.net/projects/tortoisesvn/scm/svn/blobs/28812/"
  566. // "trunk/src/TortoiseIDiff/MainWindow.cpp"
  567. //
  568. // But for now it works event with a small part of that.
  569. //
  570. //const auto updateWindowTheme = [&] {
  571. // const auto set = [&](LPCWSTR name) {
  572. // return SetWindowTheme(_hWnd, name, nullptr);
  573. // };
  574. // if (!night || FAILED(set(L"DarkMode_Explorer"))) {
  575. // set(L"Explorer");
  576. // }
  577. //};
  578. //
  579. //if (night) {
  580. // if (Dlls::SetPreferredAppMode) {
  581. // Dlls::SetPreferredAppMode(Dlls::PreferredAppMode::AllowDark);
  582. // } else {
  583. // Dlls::AllowDarkModeForApp(TRUE);
  584. // }
  585. // Dlls::AllowDarkModeForWindow(_hWnd, TRUE);
  586. // updateWindowTheme();
  587. // updateStyle();
  588. // Dlls::FlushMenuThemes();
  589. // Dlls::RefreshImmersiveColorPolicyState();
  590. //} else {
  591. // updateWindowTheme();
  592. // Dlls::AllowDarkModeForWindow(_hWnd, FALSE);
  593. // updateStyle();
  594. // Dlls::FlushMenuThemes();
  595. // Dlls::RefreshImmersiveColorPolicyState();
  596. // if (Dlls::SetPreferredAppMode) {
  597. // Dlls::SetPreferredAppMode(Dlls::PreferredAppMode::Default);
  598. // } else {
  599. // Dlls::AllowDarkModeForApp(FALSE);
  600. // }
  601. //}
  602. // Didn't find any other way to definitely repaint with the new style.
  603. SendMessage(_hWnd, WM_NCACTIVATE, _hasActiveFrame ? 0 : 1, 0);
  604. SendMessage(_hWnd, WM_NCACTIVATE, _hasActiveFrame ? 1 : 0, 0);
  605. }
  606. HWND MainWindow::psHwnd() const {
  607. return _hWnd;
  608. }
  609. void MainWindow::destroyCachedIcons() {
  610. const auto destroy = [](HICON &icon) {
  611. if (icon) {
  612. DestroyIcon(icon);
  613. icon = nullptr;
  614. }
  615. };
  616. destroy(_iconBig);
  617. destroy(_iconSmall);
  618. destroy(_iconOverlay);
  619. }
  620. MainWindow::~MainWindow() {
  621. WTSUnRegisterSessionNotification(_hWnd);
  622. _private->viewSettings.Reset();
  623. destroyCachedIcons();
  624. }
  625. int32 ScreenNameChecksum(const QString &name) {
  626. constexpr int DeviceNameSize = base::array_size(MONITORINFOEX().szDevice);
  627. wchar_t buffer[DeviceNameSize] = { 0 };
  628. if (name.size() < DeviceNameSize) {
  629. name.toWCharArray(buffer);
  630. } else {
  631. memcpy(buffer, name.toStdWString().data(), sizeof(buffer));
  632. }
  633. return base::crc32(buffer, sizeof(buffer));
  634. }
  635. } // namespace Platform