Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 5943452e4c
Fetching contributors…

Cannot retrieve contributors at this time

executable file 343 lines (312 sloc) 11.014 kb
/****************************************************************************
**
** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info.com)
**
** This file is part of a Qt Solutions component.
**
** Commercial Usage
** Licensees holding valid Qt Solutions licenses may use this file in
** accordance with the Qt Solutions Commercial License Agreement provided
** with the Software or, alternatively, in accordance with the terms
** contained in a written agreement between you and Nokia.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales.com.
**
****************************************************************************/
#include "qtsingleapplication.h"
#include <QtGui/QWidget>
#include <QtCore/QByteArray>
#include <QtCore/QString>
#include <QtCore/QList>
#include <QtGui/QDesktopWidget>
#include <QtGui/QApplication>
#include <QtCore/QDebug>
#include <unistd.h>
#include <pwd.h>
#include <sys/types.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <QtGui/QX11Info>
class QtSingletonListener : public QWidget
{
public:
QtSingletonListener(Atom atom, QWidget* par = 0)
: QWidget(par)
{
QByteArray yes = "YES";
XChangeProperty(QX11Info::display(),
winId(),
atom, atom, 8,
PropModeReplace,
reinterpret_cast<unsigned char *>(yes.data()), 3);
}
};
class QtSingletonSysPrivate
{
public:
Atom selAtom;
Atom typAtom;
Atom listenAtom;
QWidget *listener;
QByteArray xpcs;
bool owner;
QString login() const;
QByteArray toXPCS(const QString &str) const; // X Portable Character Set
void sendMessageTo(Window wid, Atom sel, Atom typ,
const QString &message) const;
bool getProperty(char** data, unsigned long* nitems,
Window win, Atom sel, Atom typ) const;
void findWindows(QList<Window> &windows);
};
QByteArray QtSingletonSysPrivate::toXPCS(const QString &str) const
{
QString strtmp(str);
if (strtmp.isEmpty() || strtmp[0] != '_')
strtmp.prepend('_');
QByteArray tmp = strtmp.toLocal8Bit();
for (int i = 0; i < tmp.size(); ++i) {
if (!xpcs.contains(tmp[i]))
tmp[i] = '_';
}
return tmp;
}
bool QtSingletonSysPrivate::getProperty(char** data, unsigned long* nitems,
Window win, Atom sel, Atom typ) const
{
if (data == 0 || nitems == 0)
return false;
Atom actualType;
int actualFormat, ret;
long length = 1024;
unsigned long bafter;
for (;;) {
*data = 0;
*nitems = 0;
ret = XGetWindowProperty(QX11Info::display(),
win,
sel,
0L, length,
False,
typ,
&actualType,
&actualFormat,
nitems,
&bafter,
reinterpret_cast<unsigned char **>(data));
if (ret == Success && actualType == typ && *nitems > 0) {
if (bafter == 0)
return TRUE;
else {
if (actualFormat == 8)
length += (bafter / 4) + 1;
else if (actualFormat == 16)
length += (bafter / 2) + 1;
else if (actualFormat == 32)
length += bafter;
}
} else {
if (*nitems > 0 && *data != 0)
XFree(*data);
return FALSE;
}
if (*nitems > 0 && *data != 0)
XFree(*data);
}
return FALSE;
}
void QtSingletonSysPrivate::findWindows(QList<Window> &windows)
{
Window root, parent;
Window* children = 0;
unsigned int nchildren;
QDesktopWidget* desktop = qApp->desktop();
char* data;
unsigned long nitems;
for (int i = 0; i < desktop->numScreens(); ++i) {
if (XQueryTree(QX11Info::display(),
desktop->screen(i)->winId(),
&root, &parent,
&children, &nchildren) == 0)
continue;
if (nchildren > 0 && children != 0) {
for (unsigned int i = 0; i < nchildren; ++i) {
if (getProperty(&data, &nitems, children[i],
listenAtom, listenAtom)) {
if (data != 0)
XFree(data);
windows.append(children[i]);
}
}
XFree(children);
}
}
}
QString QtSingletonSysPrivate::login() const
{
struct passwd *pwd = getpwuid(getuid());
if (pwd) {
return QString(pwd->pw_name);
}
return QString();
}
void QtSingletonSysPrivate::sendMessageTo(Window wid, Atom sel, Atom typ,
const QString &message) const
{
if (typ != None) {
QByteArray umsg = message.toUtf8();
XChangeProperty(QX11Info::display(),
wid,
sel, typ, 8,
PropModeReplace,
reinterpret_cast<unsigned char *>(umsg.data()),
umsg.size());
}
}
void QtSingleApplication::sysInit()
{
sysd = new QtSingletonSysPrivate;
sysd->selAtom = None;
sysd->typAtom = None;
sysd->listenAtom = None;
sysd->listener = 0;
sysd->xpcs.resize(95);
sysd->xpcs = QByteArray("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~");
sysd->owner = false;
}
void QtSingleApplication::sysCleanup()
{
if (sysd) {
// make the old owner the current owner
if (sysd->owner) {
Window newowner = None;
// We don't want any of the windows to be destroyed
// while we're looping over them. So we grab the server.
XGrabServer(QX11Info::display());
QList<Window> windows;
sysd->findWindows(windows);
QList<Window>::ConstIterator it = windows.begin();
while (it != windows.end()) {
if (*it != sysd->listener->winId())
newowner = *it;
++it;
}
if (newowner != None)
sysd->sendMessageTo(newowner,
sysd->selAtom, sysd->typAtom,
"a");
XUngrabServer(QX11Info::display());
// Make sure that the server releases the grab as soon
// as possible.
XFlush(QX11Info::display());
}
delete sysd->listener;
delete sysd;
}
}
void QtSingleApplication::initialize(bool activate)
{
if (sysd->selAtom != None)
return;
QByteArray login = sysd->toXPCS(id()+sysd->login());
sysd->selAtom = XInternAtom(QX11Info::display(),
login,
False);
sysd->typAtom = XInternAtom(QX11Info::display(),
"_QTSINGLEAPPLICATION",
False);
sysd->listenAtom = XInternAtom(QX11Info::display(),
login+"_LISTENER",
False);
if (sysd->selAtom != None) {
sysd->listener = new QtSingletonListener(sysd->listenAtom);
Window lid = sysd->listener->winId();
XSetSelectionOwner(QX11Info::display(),
sysd->selAtom,
lid,
CurrentTime);
if (XGetSelectionOwner(QX11Info::display(), sysd->selAtom) == lid)
sysd->owner = true;
}
if (activate)
connect(this, SIGNAL(messageReceived(const QString&)),
this, SLOT(activateWindow()));
}
bool QtSingleApplication::isRunning() const
{
QByteArray login = sysd->toXPCS(id()+sysd->login());
Atom tmp = XInternAtom(QX11Info::display(),
login,
True);
if (tmp != None) {
WId wid = XGetSelectionOwner(QX11Info::display(),
tmp);
return (wid != None);
}
return FALSE;
}
bool QtSingleApplication::sendMessage(const QString &message, int)
{
QByteArray login = sysd->toXPCS(id()+sysd->login());
Atom sel = XInternAtom(QX11Info::display(),
login,
True);
if (sel == None)
return FALSE;
WId wid = XGetSelectionOwner(QX11Info::display(), sel);
if (wid != None) {
Atom typ = XInternAtom(QX11Info::display(),
"_QTSINGLEAPPLICATION",
True);
if (typ != None) {
sysd->sendMessageTo(wid, sel, typ, message);
return TRUE;
}
}
return FALSE;
}
/*!
\internal
*/
bool QtSingleApplication::x11EventFilter(XEvent *msg)
{
if (sysd->listener != 0) {
if (msg->type == PropertyNotify) {
XPropertyEvent pev = msg->xproperty;
if (pev.window == sysd->listener->winId()) {
if (!sysd->owner) {
// We aren't the current owner, but some program changed our
// property. This will happen if more than one
// QtSingleApplication instance of the same type is running
// and one of them closes and we were the previous owner
// of the selection. Try to make ourselves the new owner
Window lid = sysd->listener->winId();
XSetSelectionOwner(QX11Info::display(),
sysd->selAtom,
lid,
CurrentTime);
if (XGetSelectionOwner(QX11Info::display(), sysd->selAtom) == lid)
sysd->owner = true;
return TRUE;
}
char* data = 0;
unsigned long nitems = 0;
if (sysd->getProperty(&data, &nitems, pev.window,
sysd->selAtom, sysd->typAtom)) {
QString str = QString::fromUtf8(reinterpret_cast<char *>(data), nitems);
if (data)
XFree(data);
emit messageReceived(str);
return TRUE;
}
if (data)
XFree(data);
}
} else if (msg->type == SelectionClear) {
if (msg->xselectionclear.selection == sysd->selAtom)
sysd->owner = false;
}
}
return QApplication::x11EventFilter(msg);
}
Jump to Line
Something went wrong with that request. Please try again.