8#ifndef QT_NO_SESSIONMANAGER
10#include <QtCore/qvarlengtharray.h>
11#include <qpa/qwindowsysteminterface.h>
13#include <qguiapplication.h>
16#include <qplatformdefs.h>
17#include <qsocketnotifier.h>
18#include <X11/SM/SMlib.h>
23using namespace Qt::StringLiterals;
27class QSmSocketReceiver :
public QObject
31 QSmSocketReceiver(
int socket)
33 QSocketNotifier* sn =
new QSocketNotifier(socket, QSocketNotifier::Read,
this);
34 connect(sn, SIGNAL(activated(QSocketDescriptor)),
this, SLOT(socketActivated()));
38 void socketActivated();
42SmcConn smcConnection =
nullptr;
43bool sm_interactionActive;
48bool sm_waitingForInteraction;
53QSmSocketReceiver* sm_receiver =
nullptr;
56void sm_setProperty(
const char *name,
const char *type,
57 int num_vals, SmPropValue *vals);
58void sm_saveYourselfCallback(SmcConn smcConn, SmPointer clientData,
59 int saveType, Bool shutdown ,
int interactStyle, Bool fast);
60void sm_saveYourselfPhase2Callback(SmcConn smcConn, SmPointer clientData) ;
61void sm_dieCallback(SmcConn smcConn, SmPointer clientData) ;
62void sm_shutdownCancelledCallback(SmcConn smcConn, SmPointer clientData);
63void sm_saveCompleteCallback(SmcConn smcConn, SmPointer clientData);
64void sm_interactCallback(SmcConn smcConn, SmPointer clientData);
69 sm_waitingForInteraction =
false;
70 sm_interactionActive =
false;
71 sm_interactStyle = SmInteractStyleNone;
73 sm_isshutdown =
false;
81void sm_setProperty(
const char *name,
const char *type,
82 int num_vals, SmPropValue *vals)
86 prop.name =
const_cast<
char*>(name);
87 prop.type =
const_cast<
char*>(type);
88 prop.num_vals = num_vals;
93 SmcSetProperties(smcConnection, 1, props);
96 names[0] =
const_cast<
char*>(name);
97 SmcDeleteProperties(smcConnection, 1, names);
101void sm_setProperty(
const QString &name,
const QString &value)
103 QByteArray v = value.toUtf8();
105 prop.length = v.size();
106 prop.value = (SmPointer)
const_cast<
char *>(v.constData());
107 sm_setProperty(name.toLatin1().data(), SmARRAY8, 1, &prop);
110void sm_setProperty(
const QString &name,
const QStringList &value)
112 SmPropValue *prop =
new SmPropValue[value.size()];
114 QList<QByteArray> vl;
115 vl.reserve(value.size());
116 for (QStringList::ConstIterator it = value.begin(); it != value.end(); ++it) {
117 prop[count].length = (*it).size();
118 vl.append((*it).toUtf8());
119 prop[count].value = (
char*)vl.constLast().data();
122 sm_setProperty(name.toLatin1().data(), SmLISTofARRAY8, count, prop);
129 unsigned int save_yourself_in_progress : 1;
130 unsigned int shutdown_in_progress : 1;
133void sm_saveYourselfCallback(SmcConn smcConn, SmPointer clientData,
134 int saveType, Bool shutdown ,
int interactStyle, Bool )
136 if (smcConn != smcConnection)
140 sm_isshutdown = shutdown;
141 sm_saveType = saveType;
142 sm_interactStyle = interactStyle;
146 ((QT_smcConn*)smcConn)->save_yourself_in_progress =
true;
148 ((QT_smcConn*)smcConn)->shutdown_in_progress =
true;
159 gettimeofday(&tv,
nullptr);
160 sm->setSessionKey(QString::number(qulonglong(tv.tv_sec)) +
162 QString::number(qulonglong(tv.tv_usec)));
164 QStringList arguments = QCoreApplication::arguments();
165 QString argument0 = arguments.isEmpty() ? QCoreApplication::applicationFilePath()
169 sm_setProperty(QString::fromLatin1(SmProgram), argument0);
171 struct passwd *entryPtr =
nullptr;
172#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && (_POSIX_THREAD_SAFE_FUNCTIONS - 0
> 0
)
173 QVarLengthArray<
char, 1024> buf(qMax<
long>(sysconf(_SC_GETPW_R_SIZE_MAX), 1024L));
175 while (getpwuid_r(geteuid(), &entry, buf.data(), buf.size(), &entryPtr) == ERANGE) {
176 if (buf.size() >= 32768) {
178 static char badusername[] =
"";
180 entry.pw_name = badusername;
185 buf.resize(buf.size() * 2);
188 entryPtr = getpwuid(geteuid());
191 sm_setProperty(QString::fromLatin1(SmUserID), QString::fromLocal8Bit(entryPtr->pw_name));
195 restart << argument0 <<
"-session"_L1 << sm->sessionId() + u'_' + sm->sessionKey();
197 QFileInfo fi(QCoreApplication::applicationFilePath());
198 if (qAppName().compare(fi.fileName(), Qt::CaseInsensitive) != 0)
199 restart <<
"-name"_L1 << qAppName();
200 sm->setRestartCommand(restart);
202 sm->setDiscardCommand(discard);
204 switch (sm_saveType) {
207 if (sm_isshutdown && sm_cancel)
220 if (sm_phase2 && !sm_in_phase2) {
221 SmcRequestSaveYourselfPhase2(smcConnection, sm_saveYourselfPhase2Callback, (SmPointer*) sm);
226 if (sm_interactionActive) {
227 SmcInteractDone(smcConnection, sm_isshutdown && sm_cancel);
228 sm_interactionActive =
false;
229 }
else if (sm_cancel && sm_isshutdown) {
231 SmcInteractDone(smcConnection, True);
232 sm_interactionActive =
false;
237 sm_setProperty(QString::fromLatin1(SmRestartCommand), sm->restartCommand());
238 sm_setProperty(QString::fromLatin1(SmDiscardCommand), sm->discardCommand());
242 prop.length =
sizeof(
int);
243 int value = sm->restartHint();
244 prop.value = (SmPointer) &value;
245 sm_setProperty(SmRestartStyleHint, SmCARD8, 1, &prop);
248 SmcSaveYourselfDone(smcConnection, !sm_cancel);
252void sm_dieCallback(SmcConn smcConn, SmPointer )
254 if (smcConn != smcConnection)
257 QWindowSystemInterface::handleApplicationTermination<QWindowSystemInterface::SynchronousDelivery>();
260void sm_shutdownCancelledCallback(SmcConn smcConn, SmPointer clientData)
262 if (smcConn != smcConnection)
264 if (sm_waitingForInteraction)
269void sm_saveCompleteCallback(SmcConn smcConn, SmPointer )
271 if (smcConn != smcConnection)
276void sm_interactCallback(SmcConn smcConn, SmPointer clientData)
278 if (smcConn != smcConnection)
280 if (sm_waitingForInteraction)
284void sm_saveYourselfPhase2Callback(SmcConn smcConn, SmPointer clientData)
286 if (smcConn != smcConnection)
292void QSmSocketReceiver::socketActivated()
294 IceProcessMessages(SmcGetIceConnection(smcConnection),
nullptr,
nullptr);
303 , m_eventLoop(
nullptr)
307 char* myId =
nullptr;
308 QByteArray b_id = id.toLatin1();
309 char* prevId = b_id.data();
312 cb.save_yourself.callback = sm_saveYourselfCallback;
313 cb.save_yourself.client_data = (SmPointer)
this;
314 cb.die.callback = sm_dieCallback;
315 cb.die.client_data = (SmPointer)
this;
316 cb.save_complete.callback = sm_saveCompleteCallback;
317 cb.save_complete.client_data = (SmPointer)
this;
318 cb.shutdown_cancelled.callback = sm_shutdownCancelledCallback;
319 cb.shutdown_cancelled.client_data = (SmPointer)
this;
322 if (!qEnvironmentVariableIsSet(
"SESSION_MANAGER"))
325 smcConnection = SmcOpenConnection(
nullptr,
nullptr, 1, 0,
326 SmcSaveYourselfProcMask |
328 SmcSaveCompleteProcMask |
329 SmcShutdownCancelledProcMask,
335 setSessionId(QString::fromLatin1(myId));
338 QString error = QString::fromLocal8Bit(cerror);
340 qWarning(
"Qt: Session management error: %s", qPrintable(error));
342 sm_receiver =
new QSmSocketReceiver(IceConnectionNumber(SmcGetIceConnection(smcConnection)));
348 SmcCloseConnection(smcConnection, 0,
nullptr);
349 smcConnection =
nullptr;
356 return (
void*) smcConnection;
361 if (sm_interactionActive)
364 if (sm_waitingForInteraction)
367 if (sm_interactStyle == SmInteractStyleAny) {
368 sm_waitingForInteraction = SmcInteractRequest(smcConnection,
373 if (sm_waitingForInteraction) {
374 QEventLoop eventLoop;
375 m_eventLoop = &eventLoop;
377 m_eventLoop =
nullptr;
379 sm_waitingForInteraction =
false;
381 sm_interactionActive =
true;
390 if (sm_interactionActive)
393 if (sm_waitingForInteraction)
396 if (sm_interactStyle == SmInteractStyleAny || sm_interactStyle == SmInteractStyleErrors) {
397 sm_waitingForInteraction = SmcInteractRequest(smcConnection,
402 if (sm_waitingForInteraction) {
403 QEventLoop eventLoop;
404 m_eventLoop = &eventLoop;
406 m_eventLoop =
nullptr;
408 sm_waitingForInteraction =
false;
410 sm_interactionActive =
true;
419 if (sm_interactionActive) {
420 SmcInteractDone(smcConnection, False);
421 sm_interactionActive =
false;
432 sm_setProperty(name, value);
437 sm_setProperty(name, value);
455#include "qxcbsessionmanager.moc"
QXcbSessionManager(const QString &id, const QString &key)
void requestPhase2() override
bool isPhase2() const override
void setManagerProperty(const QString &name, const QString &value) override
bool allowsInteraction() override
virtual ~QXcbSessionManager()
bool allowsErrorInteraction() override