Bring back Qt4 X11 session management functionality.

Added QXcbSessionManager to the Xcb plugin.
QXcbSessionManager inherits from QPlatformSessionManager, it's a port of
QSessionManager as it is in Qt 4.8.
Minor changes also in QPlatformSessionManager and QGuiApplication to
hook it up.

Task-number: QTBUG-28228
Task-number: QTBUG-30011
Task-number: QTBUG-33033
Change-Id: I50b33d05a1e32c5278dea339f693713acc870a70
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
Reviewed-by: David Faure <david.faure@kdab.com>
This commit is contained in:
Teo Mrnjavac 2013-09-11 17:22:45 +02:00 committed by The Qt Project
parent f4ebb06189
commit 060b862b61
11 changed files with 670 additions and 4 deletions

6
configure vendored
View File

@ -5348,6 +5348,12 @@ if [ "$CFG_XCB" != "no" ]; then
QT_CONFIG="$QT_CONFIG xcb-xlib"
fi
if [ "$CFG_SM" != "no" ] && [ -n "$PKG_CONFIG" ]; then
if $PKG_CONFIG --exists "sm" 2>/dev/null && $PKG_CONFIG --exists "ice" 2>/dev/null; then
QT_CONFIG="$QT_CONFIG xcb-sm"
fi
fi
# auto-detect Xrender support
if [ "$CFG_XRENDER" != "no" ]; then
if compileTest x11/xrender "Xrender"; then

View File

@ -1162,9 +1162,9 @@ void QGuiApplicationPrivate::init()
init_plugins(pluginList);
QWindowSystemInterface::flushWindowSystemEvents();
#ifndef QT_NO_SESSIONMANAGER
Q_Q(QGuiApplication);
#ifndef QT_NO_SESSIONMANAGER
// connect to the session manager
session_manager = new QSessionManager(q, session_id, session_key);
#endif

View File

@ -184,6 +184,9 @@ private:
#endif
friend class QFontDatabasePrivate;
friend class QPlatformIntegration;
#ifndef QT_NO_SESSIONMANAGER
friend class QPlatformSessionManager;
#endif
};
QT_END_NAMESPACE

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
** Copyright (C) 2013 Teo Mrnjavac <teo@kde.org>
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
@ -42,6 +43,10 @@
#include "qplatformsessionmanager.h"
#include "qguiapplication_p.h"
#ifndef QT_NO_SESSIONMANAGER
QT_BEGIN_NAMESPACE
QPlatformSessionManager::QPlatformSessionManager(const QString &id, const QString &key)
@ -113,6 +118,12 @@ QStringList QPlatformSessionManager::discardCommand() const
return m_discardCommand;
}
void QPlatformSessionManager::setManagerProperty(const QString &name, const QString &value)
{
Q_UNUSED(name)
Q_UNUSED(value)
}
void QPlatformSessionManager::setManagerProperty(const QString &name, const QStringList &value)
{
Q_UNUSED(name)
@ -128,4 +139,16 @@ void QPlatformSessionManager::requestPhase2()
{
}
void QPlatformSessionManager::appCommitData()
{
qGuiApp->d_func()->commitData();
}
void QPlatformSessionManager::appSaveState()
{
qGuiApp->d_func()->saveState();
}
QT_END_NAMESPACE
#endif // QT_NO_SESSIONMANAGER

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
** Copyright (C) 2013 Teo Mrnjavac <teo@kde.org>
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
@ -57,6 +58,8 @@
#include <QtGui/qsessionmanager.h>
#ifndef QT_NO_SESSIONMANAGER
QT_BEGIN_NAMESPACE
class Q_GUI_EXPORT QPlatformSessionManager
@ -82,16 +85,22 @@ public:
virtual void setDiscardCommand(const QStringList &command);
virtual QStringList discardCommand() const;
virtual void setManagerProperty(const QString &name, const QString &value);
virtual void setManagerProperty(const QString &name, const QStringList &value);
virtual bool isPhase2() const;
virtual void requestPhase2();
protected:
virtual void appCommitData();
virtual void appSaveState();
QString m_sessionId;
QString m_sessionKey;
private:
QStringList m_restartCommand;
QStringList m_discardCommand;
const QString m_sessionId;
const QString m_sessionKey;
QSessionManager::RestartHint m_restartHint;
Q_DISABLE_COPY(QPlatformSessionManager)
@ -99,4 +108,6 @@ private:
QT_END_NAMESPACE
#endif // QT_NO_SESSIONMANAGER
#endif // QPLATFORMSESSIONMANAGER_H

View File

@ -365,7 +365,8 @@ QStringList QSessionManager::discardCommand() const
void QSessionManager::setManagerProperty(const QString &name,
const QString &value)
{
setManagerProperty(name, QStringList(value));
Q_D(QSessionManager);
d->platformSessionManager->setManagerProperty(name, value);
}
/*!

View File

@ -50,6 +50,10 @@
#include "qxcbclipboard.h"
#include "qxcbdrag.h"
#ifndef QT_NO_SESSIONMANAGER
#include "qxcbsessionmanager.h"
#endif
#include <xcb/xcb.h>
#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
@ -439,4 +443,11 @@ QByteArray QXcbIntegration::wmClass() const
return m_wmClass;
}
#ifndef QT_NO_SESSIONMANAGER
QPlatformSessionManager *QXcbIntegration::createPlatformSessionManager(const QString &id, const QString &key) const
{
return new QXcbSessionManager(id, key);
}
#endif
QT_END_NAMESPACE

View File

@ -101,6 +101,10 @@ public:
QByteArray wmClass() const;
#ifndef QT_NO_SESSIONMANAGER
QPlatformSessionManager *createPlatformSessionManager(const QString &id, const QString &key) const Q_DECL_OVERRIDE;
#endif
private:
QList<QXcbConnection *> m_connections;

View File

@ -0,0 +1,512 @@
/****************************************************************************
**
** Copyright (C) 2013 Teo Mrnjavac <teo@kde.org>
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qxcbsessionmanager.h"
#include <qguiapplication.h>
#include <qdatetime.h>
#include <qfileinfo.h>
#include <qplatformdefs.h>
#include <qsocketnotifier.h>
#include <X11/SM/SMlib.h>
class QSmSocketReceiver : public QObject
{
Q_OBJECT
public:
QSmSocketReceiver(int socket)
{
QSocketNotifier* sn = new QSocketNotifier(socket, QSocketNotifier::Read, this);
connect(sn, SIGNAL(activated(int)), this, SLOT(socketActivated(int)));
}
public Q_SLOTS:
void socketActivated(int);
};
static SmcConn smcConnection = 0;
static bool sm_interactionActive;
static bool sm_smActive;
static int sm_interactStyle;
static int sm_saveType;
static bool sm_cancel;
static bool sm_waitingForInteraction;
static bool sm_isshutdown;
static bool sm_phase2;
static bool sm_in_phase2;
bool qt_sm_blockUserInput = false;
static QSmSocketReceiver* sm_receiver = 0;
static void resetSmState();
static void sm_setProperty(const char *name, const char *type,
int num_vals, SmPropValue *vals);
static void sm_saveYourselfCallback(SmcConn smcConn, SmPointer clientData,
int saveType, Bool shutdown , int interactStyle, Bool fast);
static void sm_saveYourselfPhase2Callback(SmcConn smcConn, SmPointer clientData) ;
static void sm_dieCallback(SmcConn smcConn, SmPointer clientData) ;
static void sm_shutdownCancelledCallback(SmcConn smcConn, SmPointer clientData);
static void sm_saveCompleteCallback(SmcConn smcConn, SmPointer clientData);
static void sm_interactCallback(SmcConn smcConn, SmPointer clientData);
static void sm_performSaveYourself(QXcbSessionManager*);
static void resetSmState()
{
sm_waitingForInteraction = false;
sm_interactionActive = false;
sm_interactStyle = SmInteractStyleNone;
sm_smActive = false;
qt_sm_blockUserInput = false;
sm_isshutdown = false;
sm_phase2 = false;
sm_in_phase2 = false;
}
// theoretically it's possible to set several properties at once. For
// simplicity, however, we do just one property at a time
static void sm_setProperty(const char *name, const char *type,
int num_vals, SmPropValue *vals)
{
if (num_vals) {
SmProp prop;
prop.name = const_cast<char*>(name);
prop.type = const_cast<char*>(type);
prop.num_vals = num_vals;
prop.vals = vals;
SmProp* props[1];
props[0] = &prop;
SmcSetProperties(smcConnection, 1, props);
} else {
char* names[1];
names[0] = const_cast<char*>(name);
SmcDeleteProperties(smcConnection, 1, names);
}
}
static void sm_setProperty(const QString &name, const QString &value)
{
QByteArray v = value.toUtf8();
SmPropValue prop;
prop.length = v.length();
prop.value = (SmPointer) v.constData();
sm_setProperty(name.toLatin1().data(), SmARRAY8, 1, &prop);
}
static void sm_setProperty(const QString &name, const QStringList &value)
{
SmPropValue *prop = new SmPropValue[value.count()];
int count = 0;
QList<QByteArray> vl;
for (QStringList::ConstIterator it = value.begin(); it != value.end(); ++it) {
prop[count].length = (*it).length();
vl.append((*it).toUtf8());
prop[count].value = (char*)vl.last().data();
++count;
}
sm_setProperty(name.toLatin1().data(), SmLISTofARRAY8, count, prop);
delete [] prop;
}
// workaround for broken libsm, see below
struct QT_smcConn {
unsigned int save_yourself_in_progress : 1;
unsigned int shutdown_in_progress : 1;
};
static void sm_saveYourselfCallback(SmcConn smcConn, SmPointer clientData,
int saveType, Bool shutdown , int interactStyle, Bool /*fast*/)
{
if (smcConn != smcConnection)
return;
sm_cancel = false;
sm_smActive = true;
sm_isshutdown = shutdown;
sm_saveType = saveType;
sm_interactStyle = interactStyle;
// ugly workaround for broken libSM. libSM should do that _before_
// actually invoking the callback in sm_process.c
((QT_smcConn*)smcConn)->save_yourself_in_progress = true;
if (sm_isshutdown)
((QT_smcConn*)smcConn)->shutdown_in_progress = true;
sm_performSaveYourself((QXcbSessionManager*) clientData);
if (!sm_isshutdown) // we cannot expect a confirmation message in that case
resetSmState();
}
static void sm_performSaveYourself(QXcbSessionManager *sm)
{
if (sm_isshutdown)
qt_sm_blockUserInput = true;
// generate a new session key
timeval tv;
gettimeofday(&tv, 0);
sm->setSessionKey(QString::number(qulonglong(tv.tv_sec)) +
QLatin1Char('_') +
QString::number(qulonglong(tv.tv_usec)));
QStringList arguments = QCoreApplication::arguments();
QString argument0 = arguments.isEmpty() ? QCoreApplication::applicationFilePath()
: arguments.at(0);
// tell the session manager about our program in best POSIX style
sm_setProperty(QString::fromLatin1(SmProgram), argument0);
// tell the session manager about our user as well.
struct passwd *entryPtr = 0;
#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && (_POSIX_THREAD_SAFE_FUNCTIONS - 0 > 0)
QVarLengthArray<char, 1024> buf(qMax<long>(sysconf(_SC_GETPW_R_SIZE_MAX), 1024L));
struct passwd entry;
while (getpwuid_r(geteuid(), &entry, buf.data(), buf.size(), &entryPtr) == ERANGE) {
if (buf.size() >= 32768) {
// too big already, fail
static char badusername[] = "";
entryPtr = &entry;
entry.pw_name = badusername;
break;
}
// retry with a bigger buffer
buf.resize(buf.size() * 2);
}
#else
entryPtr = getpwuid(geteuid());
#endif
if (entryPtr)
sm_setProperty(QString::fromLatin1(SmUserID), QString::fromLocal8Bit(entryPtr->pw_name));
// generate a restart and discard command that makes sense
QStringList restart;
restart << argument0 << QLatin1String("-session")
<< sm->sessionId() + QLatin1Char('_') + sm->sessionKey();
QFileInfo fi = QCoreApplication::applicationFilePath();
if (qAppName().compare(fi.fileName(), Qt::CaseInsensitive) != 0)
restart << QLatin1String("-name") << qAppName();
sm->setRestartCommand(restart);
QStringList discard;
sm->setDiscardCommand(discard);
switch (sm_saveType) {
case SmSaveBoth:
sm->appCommitData();
if (sm_isshutdown && sm_cancel)
break; // we cancelled the shutdown, no need to save state
// fall through
case SmSaveLocal:
sm->appSaveState();
break;
case SmSaveGlobal:
sm->appCommitData();
break;
default:
break;
}
if (sm_phase2 && !sm_in_phase2) {
SmcRequestSaveYourselfPhase2(smcConnection, sm_saveYourselfPhase2Callback, (SmPointer*) sm);
qt_sm_blockUserInput = false;
} else {
// close eventual interaction monitors and cancel the
// shutdown, if required. Note that we can only cancel when
// performing a shutdown, it does not work for checkpoints
if (sm_interactionActive) {
SmcInteractDone(smcConnection, sm_isshutdown && sm_cancel);
sm_interactionActive = false;
} else if (sm_cancel && sm_isshutdown) {
if (sm->allowsErrorInteraction()) {
SmcInteractDone(smcConnection, True);
sm_interactionActive = false;
}
}
// set restart and discard command in session manager
sm_setProperty(QString::fromLatin1(SmRestartCommand), sm->restartCommand());
sm_setProperty(QString::fromLatin1(SmDiscardCommand), sm->discardCommand());
// set the restart hint
SmPropValue prop;
prop.length = sizeof(int);
int value = sm->restartHint();
prop.value = (SmPointer) &value;
sm_setProperty(SmRestartStyleHint, SmCARD8, 1, &prop);
// we are done
SmcSaveYourselfDone(smcConnection, !sm_cancel);
}
}
static void sm_dieCallback(SmcConn smcConn, SmPointer /* clientData */)
{
if (smcConn != smcConnection)
return;
resetSmState();
QEvent quitEvent(QEvent::Quit);
QGuiApplication::sendEvent(qApp, &quitEvent);
}
static void sm_shutdownCancelledCallback(SmcConn smcConn, SmPointer clientData)
{
if (smcConn != smcConnection)
return;
if (sm_waitingForInteraction)
((QXcbSessionManager *) clientData)->exitEventLoop();
resetSmState();
}
static void sm_saveCompleteCallback(SmcConn smcConn, SmPointer /*clientData */)
{
if (smcConn != smcConnection)
return;
resetSmState();
}
static void sm_interactCallback(SmcConn smcConn, SmPointer clientData)
{
if (smcConn != smcConnection)
return;
if (sm_waitingForInteraction)
((QXcbSessionManager *) clientData)->exitEventLoop();
}
static void sm_saveYourselfPhase2Callback(SmcConn smcConn, SmPointer clientData)
{
if (smcConn != smcConnection)
return;
sm_in_phase2 = true;
sm_performSaveYourself((QXcbSessionManager *) clientData);
}
void QSmSocketReceiver::socketActivated(int)
{
IceProcessMessages(SmcGetIceConnection(smcConnection), 0, 0);
}
// QXcbSessionManager starts here
QXcbSessionManager::QXcbSessionManager(const QString &id, const QString &key)
: QPlatformSessionManager(id, key)
, m_eventLoop(0)
{
resetSmState();
char cerror[256];
char* myId = 0;
QByteArray b_id = id.toLatin1();
char* prevId = b_id.data();
SmcCallbacks cb;
cb.save_yourself.callback = sm_saveYourselfCallback;
cb.save_yourself.client_data = (SmPointer) this;
cb.die.callback = sm_dieCallback;
cb.die.client_data = (SmPointer) this;
cb.save_complete.callback = sm_saveCompleteCallback;
cb.save_complete.client_data = (SmPointer) this;
cb.shutdown_cancelled.callback = sm_shutdownCancelledCallback;
cb.shutdown_cancelled.client_data = (SmPointer) this;
// avoid showing a warning message below
if (!qEnvironmentVariableIsSet("SESSION_MANAGER"))
return;
smcConnection = SmcOpenConnection(0, 0, 1, 0,
SmcSaveYourselfProcMask |
SmcDieProcMask |
SmcSaveCompleteProcMask |
SmcShutdownCancelledProcMask,
&cb,
prevId,
&myId,
256, cerror);
setSessionId(QString::fromLatin1(myId));
::free(myId); // it was allocated by C
QString error = QString::fromLocal8Bit(cerror);
if (!smcConnection)
qWarning("Qt: Session management error: %s", qPrintable(error));
else
sm_receiver = new QSmSocketReceiver(IceConnectionNumber(SmcGetIceConnection(smcConnection)));
}
QXcbSessionManager::~QXcbSessionManager()
{
if (smcConnection)
SmcCloseConnection(smcConnection, 0, 0);
smcConnection = 0;
delete sm_receiver;
}
void* QXcbSessionManager::handle() const
{
return (void*) smcConnection;
}
void QXcbSessionManager::setSessionId(const QString &id)
{
m_sessionId = id;
}
void QXcbSessionManager::setSessionKey(const QString &key)
{
m_sessionKey = key;
}
bool QXcbSessionManager::allowsInteraction()
{
if (sm_interactionActive)
return true;
if (sm_waitingForInteraction)
return false;
if (sm_interactStyle == SmInteractStyleAny) {
sm_waitingForInteraction = SmcInteractRequest(smcConnection,
SmDialogNormal,
sm_interactCallback,
(SmPointer*) this);
}
if (sm_waitingForInteraction) {
QEventLoop eventLoop;
m_eventLoop = &eventLoop;
eventLoop.exec();
m_eventLoop = 0;
sm_waitingForInteraction = false;
if (sm_smActive) { // not cancelled
sm_interactionActive = true;
qt_sm_blockUserInput = false;
return true;
}
}
return false;
}
bool QXcbSessionManager::allowsErrorInteraction()
{
if (sm_interactionActive)
return true;
if (sm_waitingForInteraction)
return false;
if (sm_interactStyle == SmInteractStyleAny || sm_interactStyle == SmInteractStyleErrors) {
sm_waitingForInteraction = SmcInteractRequest(smcConnection,
SmDialogError,
sm_interactCallback,
(SmPointer*) this);
}
if (sm_waitingForInteraction) {
QEventLoop eventLoop;
m_eventLoop = &eventLoop;
eventLoop.exec();
m_eventLoop = 0;
sm_waitingForInteraction = false;
if (sm_smActive) { // not cancelled
sm_interactionActive = true;
qt_sm_blockUserInput = false;
return true;
}
}
return false;
}
void QXcbSessionManager::release()
{
if (sm_interactionActive) {
SmcInteractDone(smcConnection, False);
sm_interactionActive = false;
if (sm_smActive && sm_isshutdown)
qt_sm_blockUserInput = true;
}
}
void QXcbSessionManager::cancel()
{
sm_cancel = true;
}
void QXcbSessionManager::setManagerProperty(const QString &name, const QString &value)
{
sm_setProperty(name, value);
}
void QXcbSessionManager::setManagerProperty(const QString &name, const QStringList &value)
{
sm_setProperty(name, value);
}
bool QXcbSessionManager::isPhase2() const
{
return sm_in_phase2;
}
void QXcbSessionManager::requestPhase2()
{
sm_phase2 = true;
}
void QXcbSessionManager::appCommitData()
{
QPlatformSessionManager::appCommitData();
}
void QXcbSessionManager::appSaveState()
{
QPlatformSessionManager::appSaveState();
}
void QXcbSessionManager::exitEventLoop()
{
m_eventLoop->exit();
}
#include "qxcbsessionmanager.moc"

View File

@ -0,0 +1,88 @@
/****************************************************************************
**
** Copyright (C) 2013 Teo Mrnjavac <teo@kde.org>
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QXCBSESSIONMANAGER_H
#define QXCBSESSIONMANAGER_H
#include <qpa/qplatformsessionmanager.h>
QT_BEGIN_NAMESPACE
class QEventLoop;
class QXcbSessionManager : public QPlatformSessionManager
{
public:
QXcbSessionManager(const QString &id, const QString &key);
virtual ~QXcbSessionManager();
void *handle() const;
void setSessionId(const QString &id);
void setSessionKey(const QString &key);
bool allowsInteraction() Q_DECL_OVERRIDE;
bool allowsErrorInteraction() Q_DECL_OVERRIDE;
void release() Q_DECL_OVERRIDE;
void cancel() Q_DECL_OVERRIDE;
void setManagerProperty(const QString &name, const QString &value) Q_DECL_OVERRIDE;
void setManagerProperty(const QString &name, const QStringList &value) Q_DECL_OVERRIDE;
bool isPhase2() const Q_DECL_OVERRIDE;
void requestPhase2() Q_DECL_OVERRIDE;
void appCommitData() Q_DECL_OVERRIDE;
void appSaveState() Q_DECL_OVERRIDE;
void exitEventLoop();
private:
QEventLoop *m_eventLoop;
Q_DISABLE_COPY(QXcbSessionManager)
};
QT_END_NAMESPACE
#endif //QXCBSESSIONMANAGER_H

View File

@ -72,6 +72,13 @@ contains(QT_CONFIG, xcb-render) {
LIBS += -lxcb-render -lxcb-render-util -lXrender
}
# build with session management support
contains(QT_CONFIG, xcb-sm) {
LIBS += -lSM -lICE
SOURCES += qxcbsessionmanager.cpp
HEADERS += qxcbsessionmanager.h
}
contains(QT_CONFIG, opengl) {
contains(QT_CONFIG, opengles2) {
DEFINES += XCB_USE_EGL