root/middleware-offline/trunk/_src/eidmw/eidgui/qtsingleapplication_x11.cpp @ 5

Revision 5, 10.9 KB (checked in by vsilva, 9 years ago)

Initial comit

Line 
1/****************************************************************************
2**
3** Copyright (C) 2003-2007 Trolltech ASA. All rights reserved.
4**
5** This file is part of a Qt Solutions component.
6**
7** Licensees holding a valid Qt Solutions License Agreement may use this
8** file in accordance with the rights, responsibilities, and obligations
9** contained therein. Please consult your licensing agreement or contact
10** sales@trolltech.com if any conditions of this licensing are not clear
11** to you.
12**
13** Further information about Qt Solutions licensing is available at:
14** http://www.trolltech.com/products/qt/addon/solutions/
15** or by contacting info@trolltech.com.
16**
17** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
18** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19**
20****************************************************************************/
21#include "qtsingleapplication.h"
22#include <QtGui/QWidget>
23#include <QtCore/QByteArray>
24#include <QtCore/QString>
25#include <QtCore/QList>
26#include <QtGui/QDesktopWidget>
27#include <QtGui/QApplication>
28#include <QtCore/QDebug>
29#include <unistd.h>
30#include <pwd.h>
31#include <sys/types.h>
32#include <X11/Xatom.h>
33#include <X11/Xlib.h>
34#include <QtGui/QX11Info>
35
36
37class QtSingletonListener : public QWidget
38{
39public:
40    QtSingletonListener(Atom atom, QWidget* par = 0)
41        : QWidget(par)
42    {
43        QByteArray yes = "YES";
44        XChangeProperty(QX11Info::display(),
45                        winId(),
46                        atom, atom, 8,
47                        PropModeReplace,
48                        reinterpret_cast<unsigned char *>(yes.data()), 3);
49    }
50};
51
52class QtSingletonSysPrivate
53{
54public:
55    Atom selAtom;
56    Atom typAtom;
57    Atom listenAtom;
58    QWidget *listener;
59    QByteArray xpcs;
60    bool owner;
61
62    QString login() const;
63    QByteArray toXPCS(const QString &str) const; // X Portable Character Set
64
65    void sendMessageTo(Window wid, Atom sel, Atom typ,
66                       const QString &message) const;
67    bool getProperty(char** data, unsigned long* nitems,
68                     Window win, Atom sel, Atom typ) const;
69    void findWindows(QList<Window> &windows);
70};
71
72QByteArray QtSingletonSysPrivate::toXPCS(const QString &str) const
73{
74    QString strtmp(str);
75    if (strtmp.isEmpty() || strtmp[0] != '_')
76        strtmp.prepend('_');
77    QByteArray tmp = strtmp.toLocal8Bit();
78    for (int i = 0; i < tmp.size(); ++i) {
79        if (!xpcs.contains(tmp[i]))
80            tmp[i] = '_';
81    }
82    return tmp;
83}
84
85bool QtSingletonSysPrivate::getProperty(char** data, unsigned long* nitems,
86                                        Window win, Atom sel, Atom typ) const
87{
88    if (data == 0 || nitems == 0)
89        return false;
90
91    Atom actualType;
92    int  actualFormat, ret;
93    long length = 1024;
94    unsigned long bafter;
95    for (;;) {
96        *data = 0;
97        *nitems = 0;
98
99        ret = XGetWindowProperty(QX11Info::display(),
100                                 win,
101                                 sel,
102                                 0L, length,
103                                 False,
104                                 typ,
105                                 &actualType,
106                                 &actualFormat,
107                                 nitems,
108                                 &bafter,
109                                 reinterpret_cast<unsigned char **>(data));
110        if (ret == Success && actualType == typ && *nitems > 0) {
111            if (bafter == 0)
112                return TRUE;
113            else {
114                if (actualFormat == 8)
115                    length += (bafter / 4) + 1;
116                else if (actualFormat == 16)
117                    length += (bafter / 2) + 1;
118                else if (actualFormat == 32)
119                    length += bafter;
120            }
121        } else {
122            if (*nitems > 0 && *data != 0)
123                XFree(*data);
124            return FALSE;
125        }
126        if (*nitems > 0 && *data != 0)
127            XFree(*data);
128    }
129    return FALSE;
130}
131
132void QtSingletonSysPrivate::findWindows(QList<Window> &windows)
133{
134    Window root, parent;
135    Window* children = 0;
136    unsigned int nchildren;
137    QDesktopWidget* desktop = qApp->desktop();
138    char* data;
139    unsigned long nitems;
140
141    for (int i = 0; i < desktop->numScreens(); ++i) {
142        if (XQueryTree(QX11Info::display(),
143                       desktop->screen(i)->winId(),
144                       &root, &parent,
145                       &children, &nchildren) == 0)
146            continue;
147        if (nchildren > 0 && children != 0) {
148            for (unsigned int i = 0; i < nchildren; ++i) {
149                if (getProperty(&data, &nitems, children[i],
150                                listenAtom, listenAtom)) {
151                    if (data != 0)
152                        XFree(data);
153                    windows.append(children[i]);
154                }
155            }
156            XFree(children);
157        }
158    }
159}
160
161QString QtSingletonSysPrivate::login() const
162{
163    struct passwd *pwd = getpwuid(getuid());
164    if (pwd) {
165        return QString(pwd->pw_name);
166    }
167    return QString();
168}
169
170void QtSingletonSysPrivate::sendMessageTo(Window wid, Atom sel, Atom typ,
171                                          const QString &message) const
172{
173    if (typ != None) {
174        QByteArray umsg = message.toUtf8();
175        XChangeProperty(QX11Info::display(),
176                        wid,
177                        sel, typ, 8,
178                        PropModeReplace,
179                        reinterpret_cast<unsigned char *>(umsg.data()),
180                        umsg.size());
181    }
182}
183
184void QtSingleApplication::sysInit()
185{
186    sysd = new QtSingletonSysPrivate;
187    sysd->selAtom = None;
188    sysd->typAtom = None;
189    sysd->listenAtom = None;
190    sysd->listener = 0;
191    sysd->xpcs.resize(95);
192    sysd->xpcs = QByteArray("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~");
193    sysd->owner = false;
194}
195
196void QtSingleApplication::sysCleanup()
197{
198    if (sysd) {
199        // make the old owner the current owner
200        if (sysd->owner) {
201            Window newowner = None;
202
203            // We don't want any of the windows to be destroyed
204            // while we're looping over them. So we grab the server.
205            XGrabServer(QX11Info::display());
206
207            QList<Window> windows;
208            sysd->findWindows(windows);
209            QList<Window>::ConstIterator it = windows.begin();
210            while (it != windows.end()) {
211                if (*it != sysd->listener->winId())
212                    newowner = *it;
213                ++it;
214            }
215            if (newowner != None)
216                sysd->sendMessageTo(newowner,
217                                    sysd->selAtom, sysd->typAtom,
218                                    "a");
219
220            XUngrabServer(QX11Info::display());
221
222            // Make sure that the server releases the grab as soon
223            // as possible.
224            XFlush(QX11Info::display());
225        }
226        delete sysd->listener;
227        delete sysd;
228    }
229}
230
231void QtSingleApplication::initialize(bool activate)
232{
233    if (sysd->selAtom != None)
234        return;
235
236    QByteArray login = sysd->toXPCS(id()+sysd->login());
237    sysd->selAtom = XInternAtom(QX11Info::display(),
238                                login,
239                                False);
240    sysd->typAtom = XInternAtom(QX11Info::display(),
241                                "_QTSINGLEAPPLICATION",
242                                False);
243    sysd->listenAtom = XInternAtom(QX11Info::display(),
244                                   login+"_LISTENER",
245                                   False);
246
247    if (sysd->selAtom != None) {
248        sysd->listener = new QtSingletonListener(sysd->listenAtom);
249        Window lid = sysd->listener->winId();
250        XSetSelectionOwner(QX11Info::display(),
251                           sysd->selAtom,
252                           lid,
253                           CurrentTime);
254        if (XGetSelectionOwner(QX11Info::display(), sysd->selAtom) == lid)
255            sysd->owner = true;
256    }
257
258    if (activate)
259        connect(this, SIGNAL(messageReceived(const QString&)),
260                this, SLOT(activateWindow()));
261}
262
263bool QtSingleApplication::isRunning() const
264{
265    QByteArray login = sysd->toXPCS(id()+sysd->login());
266    Atom tmp = XInternAtom(QX11Info::display(),
267                           login,
268                           True);
269
270    if (tmp != None) {
271        WId wid = XGetSelectionOwner(QX11Info::display(),
272                                     tmp);
273        return (wid != None);
274    }
275    return FALSE;
276}
277
278bool QtSingleApplication::sendMessage(const QString &message, int)
279{
280    QByteArray login = sysd->toXPCS(id()+sysd->login());
281    Atom sel = XInternAtom(QX11Info::display(),
282                           login,
283                           True);
284    if (sel == None)
285        return FALSE;
286    WId wid = XGetSelectionOwner(QX11Info::display(), sel);
287    if (wid != None) {
288        Atom typ = XInternAtom(QX11Info::display(),
289                                "_QTSINGLEAPPLICATION",
290                                True);
291        if (typ != None) {
292            sysd->sendMessageTo(wid, sel, typ, message);
293            return TRUE;
294        }
295    }
296    return FALSE;
297}
298
299/*!
300    \internal
301*/
302
303bool QtSingleApplication::x11EventFilter(XEvent *msg)
304{
305    if (sysd->listener != 0) {
306        if (msg->type == PropertyNotify) {
307            XPropertyEvent pev = msg->xproperty;
308            if (pev.window == sysd->listener->winId()) {
309                if (!sysd->owner) {
310                    // We aren't the current owner, but some program changed our
311                    // property. This will happen if more than one
312                    // QtSingleApplication instance of the same type is running
313                    // and one of them closes and we were the previous owner
314                    // of the selection. Try to make ourselves the new owner
315                    Window lid = sysd->listener->winId();
316                    XSetSelectionOwner(QX11Info::display(),
317                                       sysd->selAtom,
318                                       lid,
319                                       CurrentTime);
320                    if (XGetSelectionOwner(QX11Info::display(), sysd->selAtom) == lid)
321                        sysd->owner = true;
322                    return TRUE;
323                }
324                char* data = 0;
325                unsigned long nitems = 0;
326                if (sysd->getProperty(&data, &nitems, pev.window,
327                                      sysd->selAtom, sysd->typAtom)) {
328                    QString str = QString::fromUtf8(reinterpret_cast<char *>(data), nitems);
329                    if (data)
330                        XFree(data);
331                    emit messageReceived(str);
332
333                    return TRUE;
334                }
335                if (data)
336                    XFree(data);
337            }
338        } else if (msg->type == SelectionClear) {
339            if (msg->xselectionclear.selection == sysd->selAtom)
340                sysd->owner = false;
341        }
342    }
343    return QApplication::x11EventFilter(msg);
344}
Note: See TracBrowser for help on using the browser.