File indexing completed on 2024-04-14 14:20:16

0001 /*
0002    This file is part of the KDE libraries
0003    Copyright (C) 2004-2008 Jarosław Staniek <staniek@kde.org>
0004 
0005    This library is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU Library General Public
0007    License version 2 as published by the Free Software Foundation.
0008 
0009    This library is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this library; see the file COPYING.LIB.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017    Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #include <QApplication>
0021 #include <klocale.h>
0022 #include <kwindowsystem.h>
0023 
0024 #include <QTranslator>
0025 #include <QLocale>
0026 #include <QLibraryInfo>
0027 #include <QLibrary>
0028 
0029 #include <stdio.h>
0030 
0031 /**
0032  * MS Windows-related actions for KApplication startup.
0033  *
0034  * - Use Qt translation which will be usable for QFileDialog
0035  *    and other Qt-only GUIs. The "qt_<language>.qm" file should be stored
0036  *    in the same place as .po files for a given language.
0037  *
0038  * - Increase the default open file limit with the stdio API from 512 to 2048
0039  *   (2048 is the hard limit on Windows)
0040  * @internal
0041 */
0042 void KApplication_init_windows()
0043 {
0044     //QString qt_transl_file = ::locate( "locale", KLocale::global()->language()
0045     //  + "/LC_MESSAGES/qt_" + KLocale::global()->language() + ".qm" );
0046 
0047     QString qt_transl_file = QString("qt_") + QLocale::system().name();
0048     qt_transl_file.truncate(5);
0049     QTranslator *qt_transl = new QTranslator();
0050     if (qt_transl->load(qt_transl_file,
0051                         QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
0052         qApp->installTranslator(qt_transl);
0053     } else {
0054         delete qt_transl;
0055     }
0056 
0057     // For apps like KMail which have lots of open files, the default is too low
0058     // so increase it to the maximum.
0059 #ifndef _WIN32_WCE
0060     _setmaxstdio(2048);
0061 #endif
0062 
0063 }
0064 
0065 // <copy of kdepim/libkdepim/utils.cpp, TODO: move to a shared helper library>
0066 
0067 #include <windows.h>
0068 #include <winperf.h>
0069 #include <psapi.h>
0070 #include <signal.h>
0071 #include <unistd.h>
0072 
0073 #include <QList>
0074 #include <QtDebug>
0075 
0076 static PPERF_OBJECT_TYPE FirstObject(PPERF_DATA_BLOCK PerfData)
0077 {
0078     return (PPERF_OBJECT_TYPE)((PBYTE)PerfData + PerfData->HeaderLength);
0079 }
0080 
0081 static PPERF_INSTANCE_DEFINITION FirstInstance(PPERF_OBJECT_TYPE PerfObj)
0082 {
0083     return (PPERF_INSTANCE_DEFINITION)((PBYTE)PerfObj + PerfObj->DefinitionLength);
0084 }
0085 
0086 static PPERF_OBJECT_TYPE NextObject(PPERF_OBJECT_TYPE PerfObj)
0087 {
0088     return (PPERF_OBJECT_TYPE)((PBYTE)PerfObj + PerfObj->TotalByteLength);
0089 }
0090 
0091 static PPERF_COUNTER_DEFINITION FirstCounter(PPERF_OBJECT_TYPE PerfObj)
0092 {
0093     return (PPERF_COUNTER_DEFINITION)((PBYTE)PerfObj + PerfObj->HeaderLength);
0094 }
0095 
0096 static PPERF_INSTANCE_DEFINITION NextInstance(PPERF_INSTANCE_DEFINITION PerfInst)
0097 {
0098     PPERF_COUNTER_BLOCK PerfCntrBlk
0099         = (PPERF_COUNTER_BLOCK)((PBYTE)PerfInst + PerfInst->ByteLength);
0100     return (PPERF_INSTANCE_DEFINITION)((PBYTE)PerfCntrBlk + PerfCntrBlk->ByteLength);
0101 }
0102 
0103 static PPERF_COUNTER_DEFINITION NextCounter(PPERF_COUNTER_DEFINITION PerfCntr)
0104 {
0105     return (PPERF_COUNTER_DEFINITION)((PBYTE)PerfCntr + PerfCntr->ByteLength);
0106 }
0107 
0108 static PPERF_COUNTER_BLOCK CounterBlock(PPERF_INSTANCE_DEFINITION PerfInst)
0109 {
0110     return (PPERF_COUNTER_BLOCK)((LPBYTE) PerfInst + PerfInst->ByteLength);
0111 }
0112 
0113 #define GETPID_TOTAL 64 * 1024
0114 #define GETPID_BYTEINCREMENT 1024
0115 #define GETPID_PROCESS_OBJECT_INDEX 230
0116 #define GETPID_PROC_ID_COUNTER 784
0117 
0118 QString fromWChar(const wchar_t *string, int size = -1)
0119 {
0120     return (sizeof(wchar_t) == sizeof(QChar)) ? QString::fromUtf16((ushort *)string, size)
0121            : QString::fromUcs4((uint *)string, size);
0122 }
0123 
0124 #ifndef _WIN32_WCE
0125 void KApplication_getProcessesIdForName(const QString &processName, QList<int> &pids)
0126 {
0127     qDebug() << "KApplication_getProcessesIdForName" << processName;
0128     PPERF_OBJECT_TYPE perfObject;
0129     PPERF_INSTANCE_DEFINITION perfInstance;
0130     PPERF_COUNTER_DEFINITION perfCounter, curCounter;
0131     PPERF_COUNTER_BLOCK counterPtr;
0132     DWORD bufSize = GETPID_TOTAL;
0133     PPERF_DATA_BLOCK perfData = (PPERF_DATA_BLOCK) malloc(bufSize);
0134 
0135     char key[64];
0136     sprintf(key, "%d %d", GETPID_PROCESS_OBJECT_INDEX, GETPID_PROC_ID_COUNTER);
0137     LONG lRes;
0138     while ((lRes = RegQueryValueExA(HKEY_PERFORMANCE_DATA,
0139                                     key,
0140                                     NULL,
0141                                     NULL,
0142                                     (LPBYTE) perfData,
0143                                     &bufSize)) == ERROR_MORE_DATA) {
0144         // get a buffer that is big enough
0145         bufSize += GETPID_BYTEINCREMENT;
0146         perfData = (PPERF_DATA_BLOCK) realloc(perfData, bufSize);
0147     }
0148 
0149     // Get the first object type.
0150     perfObject = FirstObject(perfData);
0151 
0152     // Process all objects.
0153     for (uint i = 0; i < perfData->NumObjectTypes; i++) {
0154         if (perfObject->ObjectNameTitleIndex != GETPID_PROCESS_OBJECT_INDEX) {
0155             perfObject = NextObject(perfObject);
0156             continue;
0157         }
0158         pids.clear();
0159         perfCounter = FirstCounter(perfObject);
0160         perfInstance = FirstInstance(perfObject);
0161         // retrieve the instances
0162         qDebug() << "INSTANCES: " << perfObject->NumInstances;
0163         for (int instance = 0; instance < perfObject->NumInstances; instance++) {
0164             curCounter = perfCounter;
0165             const QString foundProcessName(
0166                 fromWChar((wchar_t *)((PBYTE)perfInstance + perfInstance->NameOffset)));
0167             qDebug() << "foundProcessName: " << foundProcessName;
0168             if (foundProcessName == processName) {
0169                 // retrieve the counters
0170                 for (uint counter = 0; counter < perfObject->NumCounters; counter++) {
0171                     if (curCounter->CounterNameTitleIndex == GETPID_PROC_ID_COUNTER) {
0172                         counterPtr = CounterBlock(perfInstance);
0173                         DWORD *value = (DWORD *)((LPBYTE) counterPtr + curCounter->CounterOffset);
0174                         pids.append(int(*value));
0175                         qDebug() << "found PID: " << int(*value);
0176                         break;
0177                     }
0178                     curCounter = NextCounter(curCounter);
0179                 }
0180             }
0181             perfInstance = NextInstance(perfInstance);
0182         }
0183     }
0184     free(perfData);
0185     RegCloseKey(HKEY_PERFORMANCE_DATA);
0186 }
0187 
0188 bool KApplication_otherProcessesExist(const QString &processName)
0189 {
0190     QList<int> pids;
0191     KApplication_getProcessesIdForName(processName, pids);
0192     int myPid = getpid();
0193     foreach (int pid, pids) {
0194         if (myPid != pid) {
0195 //      kDebug() << "Process ID is " << pid;
0196             return true;
0197         }
0198     }
0199     return false;
0200 }
0201 
0202 bool KApplication_killProcesses(const QString &processName)
0203 {
0204     QList<int> pids;
0205     KApplication_getProcessesIdForName(processName, pids);
0206     if (pids.empty()) {
0207         return true;
0208     }
0209     qWarning() << "Killing process \"" << processName << " (pid=" << pids[0] << ")..";
0210     int overallResult = 0;
0211     foreach (int pid, pids) {
0212         int result = kill(pid, SIGTERM);
0213         if (result == 0) {
0214             continue;
0215         }
0216         result = kill(pid, SIGKILL);
0217         if (result != 0) {
0218             overallResult = result;
0219         }
0220     }
0221     return overallResult == 0;
0222 }
0223 
0224 struct EnumWindowsStruct {
0225     EnumWindowsStruct() : windowId(0) {}
0226     int pid;
0227     HWND windowId;
0228 };
0229 
0230 BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
0231 {
0232     if (GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE) {
0233         DWORD pidwin;
0234         GetWindowThreadProcessId(hwnd, &pidwin);
0235         if (pidwin == ((EnumWindowsStruct *)lParam)->pid) {
0236             ((EnumWindowsStruct *)lParam)->windowId = hwnd;
0237             return false;
0238         }
0239     }
0240     return true;
0241 }
0242 
0243 void KApplication_activateWindowForProcess(const QString &executableName)
0244 {
0245     QList<int> pids;
0246     KApplication_getProcessesIdForName(executableName, pids);
0247     int myPid = getpid();
0248     int foundPid = 0;
0249     foreach (int pid, pids) {
0250         if (myPid != pid) {
0251             qDebug() << "activateWindowForProcess(): PID to activate:" << pid;
0252             foundPid = pid;
0253             break;
0254         }
0255     }
0256     if (foundPid == 0) {
0257         return;
0258     }
0259     EnumWindowsStruct winStruct;
0260     winStruct.pid = foundPid;
0261     EnumWindows(EnumWindowsProc, (LPARAM)&winStruct);
0262     if (winStruct.windowId == NULL) {
0263         return;
0264     }
0265     KWindowSystem::forceActiveWindow((WId)winStruct.windowId, 0);
0266 }
0267 #endif
0268 
0269 // </copy>