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:
parent
f4ebb06189
commit
060b862b61
6
configure
vendored
6
configure
vendored
@ -5348,6 +5348,12 @@ if [ "$CFG_XCB" != "no" ]; then
|
|||||||
QT_CONFIG="$QT_CONFIG xcb-xlib"
|
QT_CONFIG="$QT_CONFIG xcb-xlib"
|
||||||
fi
|
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
|
# auto-detect Xrender support
|
||||||
if [ "$CFG_XRENDER" != "no" ]; then
|
if [ "$CFG_XRENDER" != "no" ]; then
|
||||||
if compileTest x11/xrender "Xrender"; then
|
if compileTest x11/xrender "Xrender"; then
|
||||||
|
@ -1162,9 +1162,9 @@ void QGuiApplicationPrivate::init()
|
|||||||
init_plugins(pluginList);
|
init_plugins(pluginList);
|
||||||
QWindowSystemInterface::flushWindowSystemEvents();
|
QWindowSystemInterface::flushWindowSystemEvents();
|
||||||
|
|
||||||
|
#ifndef QT_NO_SESSIONMANAGER
|
||||||
Q_Q(QGuiApplication);
|
Q_Q(QGuiApplication);
|
||||||
|
|
||||||
#ifndef QT_NO_SESSIONMANAGER
|
|
||||||
// connect to the session manager
|
// connect to the session manager
|
||||||
session_manager = new QSessionManager(q, session_id, session_key);
|
session_manager = new QSessionManager(q, session_id, session_key);
|
||||||
#endif
|
#endif
|
||||||
|
@ -184,6 +184,9 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
friend class QFontDatabasePrivate;
|
friend class QFontDatabasePrivate;
|
||||||
friend class QPlatformIntegration;
|
friend class QPlatformIntegration;
|
||||||
|
#ifndef QT_NO_SESSIONMANAGER
|
||||||
|
friend class QPlatformSessionManager;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
|
** 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).
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
** Contact: http://www.qt-project.org/legal
|
** Contact: http://www.qt-project.org/legal
|
||||||
**
|
**
|
||||||
@ -42,6 +43,10 @@
|
|||||||
|
|
||||||
#include "qplatformsessionmanager.h"
|
#include "qplatformsessionmanager.h"
|
||||||
|
|
||||||
|
#include "qguiapplication_p.h"
|
||||||
|
|
||||||
|
#ifndef QT_NO_SESSIONMANAGER
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
QPlatformSessionManager::QPlatformSessionManager(const QString &id, const QString &key)
|
QPlatformSessionManager::QPlatformSessionManager(const QString &id, const QString &key)
|
||||||
@ -113,6 +118,12 @@ QStringList QPlatformSessionManager::discardCommand() const
|
|||||||
return m_discardCommand;
|
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)
|
void QPlatformSessionManager::setManagerProperty(const QString &name, const QStringList &value)
|
||||||
{
|
{
|
||||||
Q_UNUSED(name)
|
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
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // QT_NO_SESSIONMANAGER
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
|
** 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).
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
** Contact: http://www.qt-project.org/legal
|
** Contact: http://www.qt-project.org/legal
|
||||||
**
|
**
|
||||||
@ -57,6 +58,8 @@
|
|||||||
|
|
||||||
#include <QtGui/qsessionmanager.h>
|
#include <QtGui/qsessionmanager.h>
|
||||||
|
|
||||||
|
#ifndef QT_NO_SESSIONMANAGER
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class Q_GUI_EXPORT QPlatformSessionManager
|
class Q_GUI_EXPORT QPlatformSessionManager
|
||||||
@ -82,16 +85,22 @@ public:
|
|||||||
virtual void setDiscardCommand(const QStringList &command);
|
virtual void setDiscardCommand(const QStringList &command);
|
||||||
virtual QStringList discardCommand() const;
|
virtual QStringList discardCommand() const;
|
||||||
|
|
||||||
|
virtual void setManagerProperty(const QString &name, const QString &value);
|
||||||
virtual void setManagerProperty(const QString &name, const QStringList &value);
|
virtual void setManagerProperty(const QString &name, const QStringList &value);
|
||||||
|
|
||||||
virtual bool isPhase2() const;
|
virtual bool isPhase2() const;
|
||||||
virtual void requestPhase2();
|
virtual void requestPhase2();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void appCommitData();
|
||||||
|
virtual void appSaveState();
|
||||||
|
|
||||||
|
QString m_sessionId;
|
||||||
|
QString m_sessionKey;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QStringList m_restartCommand;
|
QStringList m_restartCommand;
|
||||||
QStringList m_discardCommand;
|
QStringList m_discardCommand;
|
||||||
const QString m_sessionId;
|
|
||||||
const QString m_sessionKey;
|
|
||||||
QSessionManager::RestartHint m_restartHint;
|
QSessionManager::RestartHint m_restartHint;
|
||||||
|
|
||||||
Q_DISABLE_COPY(QPlatformSessionManager)
|
Q_DISABLE_COPY(QPlatformSessionManager)
|
||||||
@ -99,4 +108,6 @@ private:
|
|||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // QT_NO_SESSIONMANAGER
|
||||||
|
|
||||||
#endif // QPLATFORMSESSIONMANAGER_H
|
#endif // QPLATFORMSESSIONMANAGER_H
|
||||||
|
@ -365,7 +365,8 @@ QStringList QSessionManager::discardCommand() const
|
|||||||
void QSessionManager::setManagerProperty(const QString &name,
|
void QSessionManager::setManagerProperty(const QString &name,
|
||||||
const QString &value)
|
const QString &value)
|
||||||
{
|
{
|
||||||
setManagerProperty(name, QStringList(value));
|
Q_D(QSessionManager);
|
||||||
|
d->platformSessionManager->setManagerProperty(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -50,6 +50,10 @@
|
|||||||
#include "qxcbclipboard.h"
|
#include "qxcbclipboard.h"
|
||||||
#include "qxcbdrag.h"
|
#include "qxcbdrag.h"
|
||||||
|
|
||||||
|
#ifndef QT_NO_SESSIONMANAGER
|
||||||
|
#include "qxcbsessionmanager.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
|
|
||||||
#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
|
#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
|
||||||
@ -439,4 +443,11 @@ QByteArray QXcbIntegration::wmClass() const
|
|||||||
return m_wmClass;
|
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
|
QT_END_NAMESPACE
|
||||||
|
@ -101,6 +101,10 @@ public:
|
|||||||
|
|
||||||
QByteArray wmClass() const;
|
QByteArray wmClass() const;
|
||||||
|
|
||||||
|
#ifndef QT_NO_SESSIONMANAGER
|
||||||
|
QPlatformSessionManager *createPlatformSessionManager(const QString &id, const QString &key) const Q_DECL_OVERRIDE;
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<QXcbConnection *> m_connections;
|
QList<QXcbConnection *> m_connections;
|
||||||
|
|
||||||
|
512
src/plugins/platforms/xcb/qxcbsessionmanager.cpp
Normal file
512
src/plugins/platforms/xcb/qxcbsessionmanager.cpp
Normal 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] = ∝
|
||||||
|
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"
|
88
src/plugins/platforms/xcb/qxcbsessionmanager.h
Normal file
88
src/plugins/platforms/xcb/qxcbsessionmanager.h
Normal 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
|
@ -72,6 +72,13 @@ contains(QT_CONFIG, xcb-render) {
|
|||||||
LIBS += -lxcb-render -lxcb-render-util -lXrender
|
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, opengl) {
|
||||||
contains(QT_CONFIG, opengles2) {
|
contains(QT_CONFIG, opengles2) {
|
||||||
DEFINES += XCB_USE_EGL
|
DEFINES += XCB_USE_EGL
|
||||||
|
Loading…
Reference in New Issue
Block a user