~ubuntu-branches/ubuntu/karmic/psi/karmic

« back to all changes in this revision

Viewing changes to src/activeprofiles_win.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2008-08-28 18:46:52 UTC
  • mfrom: (1.2.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080828184652-iiik12dl91nq7cdi
Tags: 0.12-2
Uploading to unstable (Closes: Bug#494352)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * activeprofiles_win.cpp - Class for interacting with other app instances
 
3
 * Copyright (C) 2006  Maciej Niedzielski
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU General Public License
 
7
 * as published by the Free Software Foundation; either version 2
 
8
 * of the License, or (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this library; if not, write to the Free Software
 
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
18
 *
 
19
 */
 
20
 
 
21
#include "activeprofiles.h"
 
22
#include "applicationinfo.h"
 
23
#include "psicon.h"
 
24
 
 
25
#include <QCoreApplication>
 
26
#include <QWidget>
 
27
#include <QTimer>
 
28
#include <windows.h>
 
29
 
 
30
/*
 
31
        Implementor notes:
 
32
        
 
33
        This file uses WinAPI a lot. It is important to remember that we still want to support Win9x family.
 
34
        For that reason, we have to use QT_WA macro for functions that exist in two versions.
 
35
        
 
36
        Also note that writing QString("x").toLocal8Bit().constData() is a bad idea and must not be done.
 
37
*/
 
38
 
 
39
class ActiveProfiles::Private : public QWidget
 
40
{
 
41
public:
 
42
        Private(ActiveProfiles *aprof) : app(ApplicationInfo::IPCName()), home(ApplicationInfo::homeDir()), ap(aprof), profile(""), mutex(0), changesMutex(0) {
 
43
 
 
44
                app.replace('\\', '/'); // '\\' has a special meaning in mutex name
 
45
                home.replace('\\', '/');
 
46
 
 
47
                const QString m = QString("%1 ChangesMutex {4F5AEDA9-7D3D-4ebe-8614-FB338146CE80}").arg(app);
 
48
                const QString c = QString("%1 IPC Command {4F5AEDA9-7D3D-4ebe-8614-FB338146CE80}").arg(app);
 
49
                
 
50
                QT_WA(
 
51
                        changesMutex = CreateMutex(0, FALSE, (LPCWSTR)m.utf16());
 
52
                        psiIpcCommand = RegisterWindowMessage((LPCWSTR)c.utf16());
 
53
                ,
 
54
                        QByteArray a = m.toLocal8Bit(); // must not call constData() of a temp object
 
55
                        changesMutex = CreateMutexA(0, FALSE, (LPCSTR)a.constData());
 
56
                        a = c.toLocal8Bit();
 
57
                        psiIpcCommand = RegisterWindowMessageA((LPCSTR)a.constData());
 
58
                )
 
59
 
 
60
                if (!changesMutex) {
 
61
                        qWarning("Couldn't create IPC mutex");
 
62
                }
 
63
                if (!psiIpcCommand) {
 
64
                        qWarning("Couldn't register IPC WM_message");
 
65
                }
 
66
        }
 
67
 
 
68
        QString app, home, profile;
 
69
        ActiveProfiles * const ap;
 
70
        HANDLE mutex, changesMutex;
 
71
 
 
72
        QString mutexName(const QString &profile) const {
 
73
                return "ProfileMutex\0x01" + app + "\0x01" + home + "\0x01" + profile + "\0x01 {4F5AEDA9-7D3D-4ebe-8614-FB338146CE80}";
 
74
        }
 
75
 
 
76
        QString windowName(const QString &profile) const {
 
77
                return "ProfileWindow\0x01" + app + "\0x01" + home + "\0x01" + profile + "\0x01 {4F5AEDA9-7D3D-4ebe-8614-FB338146CE80}";
 
78
        }
 
79
 
 
80
        void startChanges()     {
 
81
                WaitForSingleObject(changesMutex, INFINITE);
 
82
        }
 
83
 
 
84
        void endChanges() {
 
85
                ReleaseMutex(changesMutex);
 
86
        }
 
87
 
 
88
        void setWindowText(const QString &text) {
 
89
                QT_WA(
 
90
                        SetWindowTextW(winId(), (LPCWSTR)text.utf16());
 
91
                ,
 
92
                        QByteArray a = text.toLocal8Bit();
 
93
                        SetWindowTextA(winId(), (LPCSTR)a.constData());
 
94
                )
 
95
        }
 
96
 
 
97
        // WM_PSICOMMAND
 
98
        static UINT psiIpcCommand;      // = RegisterWindowMessage()
 
99
        static WPARAM raiseCommand;     // = 1
 
100
 
 
101
        // WM_COPYDATA
 
102
        static const int stringListMessage = 1;
 
103
 
 
104
        bool sendMessage(const QString &to, UINT message, WPARAM wParam, LPARAM lParam) const;
 
105
        bool winEvent(MSG *msg, long *result);
 
106
 
 
107
        bool sendStringList(const QString &to, const QStringList &list) const;
 
108
};
 
109
 
 
110
UINT ActiveProfiles::Private::psiIpcCommand = 0;
 
111
WPARAM ActiveProfiles::Private::raiseCommand = 1;
 
112
 
 
113
bool ActiveProfiles::Private::sendMessage(const QString &to, UINT message, WPARAM wParam, LPARAM lParam) const
 
114
{
 
115
        HWND hwnd;
 
116
        QT_WA(
 
117
                hwnd = FindWindowW(0, (LPCWSTR)windowName(to).utf16());
 
118
        ,
 
119
                QByteArray a = windowName(to).toLocal8Bit();
 
120
                hwnd = FindWindowA(0, (LPCSTR)a.constData());
 
121
        )
 
122
 
 
123
        if (!hwnd)
 
124
                return false;
 
125
 
 
126
        SendMessageA(hwnd, message, wParam, lParam);
 
127
        return true;
 
128
}
 
129
 
 
130
bool ActiveProfiles::Private::sendStringList(const QString &to, const QStringList &list) const
 
131
{
 
132
        if (to.isEmpty())
 
133
                return false;
 
134
 
 
135
        QByteArray ba;
 
136
 
 
137
        ba.append(list[0].toUtf8());
 
138
        for (int i = 1; i < list.size(); ++i) {
 
139
                const int z = ba.size();
 
140
                ba.append(" " + list[i].toUtf8());
 
141
                ba[z] = '\0';
 
142
        }
 
143
 
 
144
        COPYDATASTRUCT cd;
 
145
        cd.dwData = stringListMessage;
 
146
        cd.cbData = ba.size()+1;
 
147
        cd.lpData = (void*)ba.data();
 
148
 
 
149
        return sendMessage(to, WM_COPYDATA, (WPARAM)winId(), (LPARAM)(LPVOID)&cd);
 
150
}
 
151
 
 
152
bool ActiveProfiles::Private::winEvent(MSG *msg, long *result)
 
153
{
 
154
        *result = 1;    // by default - not ok
 
155
 
 
156
        if (msg->message == WM_COPYDATA) {
 
157
                COPYDATASTRUCT *cd = (COPYDATASTRUCT *)msg->lParam;
 
158
                if (cd->dwData == stringListMessage) {
 
159
                        char *data = (char*)cd->lpData;
 
160
                        const char *end = data + cd->cbData - 1;
 
161
 
 
162
                        // handle this error here, not to worry later
 
163
                        if (*end != '\0') {
 
164
                                return true;
 
165
                        }
 
166
 
 
167
                        QStringList list;
 
168
 
 
169
                        while (data < end) {
 
170
                                QString s = QString::fromUtf8(data);
 
171
                                list << s;
 
172
                                data += strlen(data) + 1;
 
173
                        }
 
174
 
 
175
                        if (list[0] == "openUri") {
 
176
                                emit ap->openUri(list[1]);
 
177
                                *result = 0;    // ok
 
178
                        }
 
179
                }
 
180
                return true;
 
181
        }
 
182
        else if (msg->message == psiIpcCommand) {
 
183
                if (msg->wParam == raiseCommand) {
 
184
                        emit ap->raiseMainWindow();
 
185
                        *result = 0; // ok
 
186
                }
 
187
                return true;
 
188
        }
 
189
 
 
190
        return false;
 
191
}
 
192
 
 
193
ActiveProfiles::ActiveProfiles()
 
194
        : QObject(QCoreApplication::instance())
 
195
{
 
196
        d = new ActiveProfiles::Private(this);
 
197
}
 
198
 
 
199
ActiveProfiles::~ActiveProfiles()
 
200
{
 
201
        delete d;
 
202
        d = 0;
 
203
}
 
204
 
 
205
bool ActiveProfiles::setThisProfile(const QString &profile)
 
206
{
 
207
        if (profile == d->profile)
 
208
                return true;
 
209
 
 
210
        if (profile.isEmpty()) {
 
211
                unsetThisProfile();
 
212
                return true;
 
213
        }
 
214
 
 
215
        d->startChanges();
 
216
        HANDLE m;
 
217
        QT_WA(
 
218
                m = CreateMutexW(0, TRUE, (LPCWSTR)d->mutexName(profile).utf16());
 
219
        ,
 
220
                QByteArray a = d->mutexName(profile).toLocal8Bit();
 
221
                m = CreateMutexA(0, TRUE, (LPCSTR)a.constData());
 
222
        )       
 
223
                
 
224
        if (GetLastError() == ERROR_ALREADY_EXISTS) {
 
225
                CloseHandle(m);
 
226
                d->endChanges();
 
227
                return false;
 
228
        }
 
229
        else {
 
230
                if (d->mutex) {
 
231
                        CloseHandle(d->mutex);
 
232
                }
 
233
                d->mutex = m;
 
234
                d->profile = profile;
 
235
                d->setWindowText(d->windowName(profile));
 
236
                d->endChanges();
 
237
                return true;
 
238
        }
 
239
}
 
240
 
 
241
void ActiveProfiles::unsetThisProfile()
 
242
{
 
243
        d->startChanges();
 
244
        CloseHandle(d->mutex);
 
245
        d->mutex = 0;
 
246
        d->profile = QString::null;
 
247
        d->setWindowText("");
 
248
        d->endChanges();
 
249
}
 
250
 
 
251
QString ActiveProfiles::thisProfile() const
 
252
{
 
253
        return d->profile;
 
254
}
 
255
 
 
256
bool ActiveProfiles::isActive(const QString &profile) const
 
257
{       
 
258
        HANDLE m;
 
259
        QT_WA(
 
260
                m = OpenMutexW(0, FALSE, (LPCWSTR)d->mutexName(profile).utf16());
 
261
        ,
 
262
                QByteArray a = d->mutexName(profile).toLocal8Bit();
 
263
                m = OpenMutexA(0, FALSE, (LPCSTR)a.constData());
 
264
        )
 
265
        if (GetLastError() == ERROR_FILE_NOT_FOUND) {
 
266
                return false;
 
267
        }
 
268
        else {
 
269
                CloseHandle(m);
 
270
                return true;
 
271
        }
 
272
}
 
273
 
 
274
bool ActiveProfiles::raiseOther(QString profile, bool withUI) const
 
275
{
 
276
        QLabel *lab = 0;
 
277
        if (withUI) {
 
278
                lab = new QLabel(tr("This psi profile is already running...<br>please wait..."));
 
279
                QTimer::singleShot(250, lab, SLOT(show()));
 
280
        }
 
281
 
 
282
        bool res = d->sendMessage(profile, d->psiIpcCommand, d->raiseCommand, 0);
 
283
 
 
284
        if (withUI) {
 
285
                lab->hide();
 
286
                delete lab;
 
287
        }
 
288
 
 
289
        return res;
 
290
}
 
291
 
 
292
bool ActiveProfiles::sendOpenUri(const QString &uri, const QString &profile) const
 
293
{
 
294
        QStringList list;
 
295
        list << "openUri" << uri;
 
296
        return d->sendStringList(isActive(profile)? profile : pickProfile(), list);
 
297
}