Warning, file /network/kdeconnect-kde/indicator/indicatorhelper_win.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 * SPDX-FileCopyrightText: 2019 Weixuan XIAO <veyx.shaw@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include <QDebug> 0008 #include <QFile> 0009 #include <QIcon> 0010 #include <QSettings> 0011 #include <QStandardPaths> 0012 0013 #include <iostream> 0014 0015 #include <Windows.h> 0016 #include <tlhelp32.h> 0017 0018 #include <winrt/Windows.Foundation.Collections.h> 0019 #include <winrt/Windows.UI.ViewManagement.h> 0020 0021 #include "indicator_debug.h" 0022 #include "indicatorhelper.h" 0023 0024 winrt::Windows::UI::ViewManagement::UISettings uiSettings; 0025 0026 IndicatorHelper::IndicatorHelper(const QUrl &indicatorUrl) 0027 : m_indicatorUrl(indicatorUrl) 0028 { 0029 uiSettings = winrt::Windows::UI::ViewManagement::UISettings(); 0030 } 0031 0032 IndicatorHelper::~IndicatorHelper() 0033 { 0034 this->terminateProcess(processes::dbus_daemon, m_indicatorUrl); 0035 this->terminateProcess(processes::kdeconnect_app, m_indicatorUrl); 0036 this->terminateProcess(processes::kdeconnect_handler, m_indicatorUrl); 0037 this->terminateProcess(processes::kdeconnect_settings, m_indicatorUrl); 0038 this->terminateProcess(processes::kdeconnect_sms, m_indicatorUrl); 0039 this->terminateProcess(processes::kdeconnect_daemon, m_indicatorUrl); 0040 } 0041 0042 void IndicatorHelper::preInit() 0043 { 0044 } 0045 0046 void IndicatorHelper::postInit() 0047 { 0048 } 0049 0050 void IndicatorHelper::iconPathHook() 0051 { 0052 // FIXME: This doesn't seem to be enough for QIcon::fromTheme to find the icons, so we still have to use the full path when setting the icon 0053 const QString iconPath = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("icons"), QStandardPaths::LocateDirectory); 0054 if (!iconPath.isNull()) { 0055 QStringList themeSearchPaths = QIcon::themeSearchPaths(); 0056 themeSearchPaths << iconPath; 0057 QIcon::setThemeSearchPaths(themeSearchPaths); 0058 } 0059 } 0060 0061 int IndicatorHelper::daemonHook(QProcess &kdeconnectd) 0062 { 0063 kdeconnectd.start(processes::kdeconnect_daemon); 0064 return 0; 0065 } 0066 0067 void onThemeChanged(QSystemTrayIcon &systray) 0068 { 0069 // Since this is a system tray icon, we care about the system theme and not the app theme 0070 QSettings registry(QStringLiteral("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"), QSettings::Registry64Format); 0071 bool isLightTheme = registry.value(QStringLiteral("SystemUsesLightTheme")).toBool(); 0072 if (isLightTheme) { 0073 systray.setIcon( 0074 QIcon(QStandardPaths::locate(QStandardPaths::AppLocalDataLocation, QStringLiteral("icons/hicolor/scalable/apps/kdeconnectindicator.svg")))); 0075 } else { 0076 systray.setIcon( 0077 QIcon(QStandardPaths::locate(QStandardPaths::AppLocalDataLocation, QStringLiteral("icons/hicolor/scalable/apps/kdeconnectindicatordark.svg")))); 0078 } 0079 } 0080 0081 void IndicatorHelper::systrayIconHook(QSystemTrayIcon &systray) 0082 { 0083 // Set a callback so we can detect changes to light/dark themes and manually call the callback once the first time 0084 uiSettings.ColorValuesChanged([&systray](auto &&unused1, auto &&unused2) { 0085 onThemeChanged(systray); 0086 }); 0087 onThemeChanged(systray); 0088 } 0089 0090 bool IndicatorHelper::terminateProcess(const QString &processName, const QUrl &indicatorUrl) const 0091 { 0092 HANDLE hProcessSnap; 0093 HANDLE hProcess; 0094 0095 hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 0096 if (hProcessSnap == INVALID_HANDLE_VALUE) { 0097 qCWarning(KDECONNECT_INDICATOR) << "Failed to get snapshot of processes."; 0098 return FALSE; 0099 } 0100 0101 PROCESSENTRY32 pe32; 0102 pe32.dwSize = sizeof(PROCESSENTRY32); 0103 0104 if (!Process32First(hProcessSnap, &pe32)) { 0105 qCWarning(KDECONNECT_INDICATOR) << "Failed to get handle for the first process."; 0106 CloseHandle(hProcessSnap); 0107 return FALSE; 0108 } 0109 0110 do { 0111 if (QString::fromWCharArray((wchar_t *)pe32.szExeFile) == processName) { 0112 hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID); 0113 0114 if (hProcess == NULL) { 0115 qCWarning(KDECONNECT_INDICATOR) << "Failed to get handle for the process:" << processName; 0116 return FALSE; 0117 } else { 0118 const DWORD processPathSize = 4096; 0119 CHAR processPathString[processPathSize]; 0120 0121 BOOL gotProcessPath = QueryFullProcessImageNameA(hProcess, 0, (LPSTR)processPathString, (PDWORD)&processPathSize); 0122 0123 if (gotProcessPath) { 0124 const QUrl processUrl = QUrl::fromLocalFile(QString::fromStdString(processPathString)); // to replace \\ with / 0125 if (indicatorUrl.isParentOf(processUrl)) { 0126 BOOL terminateSuccess = TerminateProcess(hProcess, 0); 0127 if (!terminateSuccess) { 0128 qCWarning(KDECONNECT_INDICATOR) << "Failed to terminate process:" << processName; 0129 return FALSE; 0130 } 0131 } 0132 } 0133 } 0134 } 0135 } while (Process32Next(hProcessSnap, &pe32)); 0136 0137 CloseHandle(hProcessSnap); 0138 return TRUE; 0139 }