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;
52bool qt_sm_blockUserInput =
false;
54QSmSocketReceiver* sm_receiver =
nullptr;
57void sm_setProperty(
const char *name,
const char *type,
58 int num_vals, SmPropValue *vals);
59void sm_saveYourselfCallback(SmcConn smcConn, SmPointer clientData,
60 int saveType, Bool shutdown ,
int interactStyle, Bool fast);
61void sm_saveYourselfPhase2Callback(SmcConn smcConn, SmPointer clientData) ;
62void sm_dieCallback(SmcConn smcConn, SmPointer clientData) ;
63void sm_shutdownCancelledCallback(SmcConn smcConn, SmPointer clientData);
64void sm_saveCompleteCallback(SmcConn smcConn, SmPointer clientData);
65void sm_interactCallback(SmcConn smcConn, SmPointer clientData);
70 sm_waitingForInteraction =
false;
71 sm_interactionActive =
false;
72 sm_interactStyle = SmInteractStyleNone;
74 qt_sm_blockUserInput =
false;
75 sm_isshutdown =
false;
83void sm_setProperty(
const char *name,
const char *type,
84 int num_vals, SmPropValue *vals)
88 prop.name =
const_cast<
char*>(name);
89 prop.type =
const_cast<
char*>(type);
90 prop.num_vals = num_vals;
95 SmcSetProperties(smcConnection, 1, props);
98 names[0] =
const_cast<
char*>(name);
99 SmcDeleteProperties(smcConnection, 1, names);
103void sm_setProperty(
const QString &name,
const QString &value)
105 QByteArray v = value.toUtf8();
107 prop.length = v.size();
108 prop.value = (SmPointer)
const_cast<
char *>(v.constData());
109 sm_setProperty(name.toLatin1().data(), SmARRAY8, 1, &prop);
112void sm_setProperty(
const QString &name,
const QStringList &value)
114 SmPropValue *prop =
new SmPropValue[value.size()];
116 QList<QByteArray> vl;
117 vl.reserve(value.size());
118 for (QStringList::ConstIterator it = value.begin(); it != value.end(); ++it) {
119 prop[count].length = (*it).size();
120 vl.append((*it).toUtf8());
121 prop[count].value = (
char*)vl.constLast().data();
124 sm_setProperty(name.toLatin1().data(), SmLISTofARRAY8, count, prop);
131 unsigned int save_yourself_in_progress : 1;
132 unsigned int shutdown_in_progress : 1;
135void sm_saveYourselfCallback(SmcConn smcConn, SmPointer clientData,
136 int saveType, Bool shutdown ,
int interactStyle, Bool )
138 if (smcConn != smcConnection)
142 sm_isshutdown = shutdown;
143 sm_saveType = saveType;
144 sm_interactStyle = interactStyle;
148 ((QT_smcConn*)smcConn)->save_yourself_in_progress =
true;
150 ((QT_smcConn*)smcConn)->shutdown_in_progress =
true;
160 qt_sm_blockUserInput =
true;
164 gettimeofday(&tv,
nullptr);
165 sm->setSessionKey(QString::number(qulonglong(tv.tv_sec)) +
167 QString::number(qulonglong(tv.tv_usec)));
169 QStringList arguments = QCoreApplication::arguments();
170 QString argument0 = arguments.isEmpty() ? QCoreApplication::applicationFilePath()
174 sm_setProperty(QString::fromLatin1(SmProgram), argument0);
176 struct passwd *entryPtr =
nullptr;
177#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && (_POSIX_THREAD_SAFE_FUNCTIONS - 0
> 0
)
178 QVarLengthArray<
char, 1024> buf(qMax<
long>(sysconf(_SC_GETPW_R_SIZE_MAX), 1024L));
180 while (getpwuid_r(geteuid(), &entry, buf.data(), buf.size(), &entryPtr) == ERANGE) {
181 if (buf.size() >= 32768) {
183 static char badusername[] =
"";
185 entry.pw_name = badusername;
190 buf.resize(buf.size() * 2);
193 entryPtr = getpwuid(geteuid());
196 sm_setProperty(QString::fromLatin1(SmUserID), QString::fromLocal8Bit(entryPtr->pw_name));
200 restart << argument0 <<
"-session"_L1 << sm->sessionId() + u'_' + sm->sessionKey();
202 QFileInfo fi(QCoreApplication::applicationFilePath());
203 if (qAppName().compare(fi.fileName(), Qt::CaseInsensitive) != 0)
204 restart <<
"-name"_L1 << qAppName();
205 sm->setRestartCommand(restart);
207 sm->setDiscardCommand(discard);
209 switch (sm_saveType) {
212 if (sm_isshutdown && sm_cancel)
225 if (sm_phase2 && !sm_in_phase2) {
226 SmcRequestSaveYourselfPhase2(smcConnection, sm_saveYourselfPhase2Callback, (SmPointer*) sm);
227 qt_sm_blockUserInput =
false;
232 if (sm_interactionActive) {
233 SmcInteractDone(smcConnection, sm_isshutdown && sm_cancel);
234 sm_interactionActive =
false;
235 }
else if (sm_cancel && sm_isshutdown) {
237 SmcInteractDone(smcConnection, True);
238 sm_interactionActive =
false;
243 sm_setProperty(QString::fromLatin1(SmRestartCommand), sm->restartCommand());
244 sm_setProperty(QString::fromLatin1(SmDiscardCommand), sm->discardCommand());
248 prop.length =
sizeof(
int);
249 int value = sm->restartHint();
250 prop.value = (SmPointer) &value;
251 sm_setProperty(SmRestartStyleHint, SmCARD8, 1, &prop);
254 SmcSaveYourselfDone(smcConnection, !sm_cancel);
258void sm_dieCallback(SmcConn smcConn, SmPointer )
260 if (smcConn != smcConnection)
263 QWindowSystemInterface::handleApplicationTermination<QWindowSystemInterface::SynchronousDelivery>();
266void sm_shutdownCancelledCallback(SmcConn smcConn, SmPointer clientData)
268 if (smcConn != smcConnection)
270 if (sm_waitingForInteraction)
275void sm_saveCompleteCallback(SmcConn smcConn, SmPointer )
277 if (smcConn != smcConnection)
282void sm_interactCallback(SmcConn smcConn, SmPointer clientData)
284 if (smcConn != smcConnection)
286 if (sm_waitingForInteraction)
290void sm_saveYourselfPhase2Callback(SmcConn smcConn, SmPointer clientData)
292 if (smcConn != smcConnection)
298void QSmSocketReceiver::socketActivated()
300 IceProcessMessages(SmcGetIceConnection(smcConnection),
nullptr,
nullptr);
309 , m_eventLoop(
nullptr)
313 char* myId =
nullptr;
314 QByteArray b_id = id.toLatin1();
315 char* prevId = b_id.data();
318 cb.save_yourself.callback = sm_saveYourselfCallback;
319 cb.save_yourself.client_data = (SmPointer)
this;
320 cb.die.callback = sm_dieCallback;
321 cb.die.client_data = (SmPointer)
this;
322 cb.save_complete.callback = sm_saveCompleteCallback;
323 cb.save_complete.client_data = (SmPointer)
this;
324 cb.shutdown_cancelled.callback = sm_shutdownCancelledCallback;
325 cb.shutdown_cancelled.client_data = (SmPointer)
this;
328 if (!qEnvironmentVariableIsSet(
"SESSION_MANAGER"))
331 smcConnection = SmcOpenConnection(
nullptr,
nullptr, 1, 0,
332 SmcSaveYourselfProcMask |
334 SmcSaveCompleteProcMask |
335 SmcShutdownCancelledProcMask,
341 setSessionId(QString::fromLatin1(myId));
344 QString error = QString::fromLocal8Bit(cerror);
346 qWarning(
"Qt: Session management error: %s", qPrintable(error));
348 sm_receiver =
new QSmSocketReceiver(IceConnectionNumber(SmcGetIceConnection(smcConnection)));
354 SmcCloseConnection(smcConnection, 0,
nullptr);
355 smcConnection =
nullptr;
362 return (
void*) smcConnection;
367 if (sm_interactionActive)
370 if (sm_waitingForInteraction)
373 if (sm_interactStyle == SmInteractStyleAny) {
374 sm_waitingForInteraction = SmcInteractRequest(smcConnection,
379 if (sm_waitingForInteraction) {
380 QEventLoop eventLoop;
381 m_eventLoop = &eventLoop;
383 m_eventLoop =
nullptr;
385 sm_waitingForInteraction =
false;
387 sm_interactionActive =
true;
388 qt_sm_blockUserInput =
false;
397 if (sm_interactionActive)
400 if (sm_waitingForInteraction)
403 if (sm_interactStyle == SmInteractStyleAny || sm_interactStyle == SmInteractStyleErrors) {
404 sm_waitingForInteraction = SmcInteractRequest(smcConnection,
409 if (sm_waitingForInteraction) {
410 QEventLoop eventLoop;
411 m_eventLoop = &eventLoop;
413 m_eventLoop =
nullptr;
415 sm_waitingForInteraction =
false;
417 sm_interactionActive =
true;
418 qt_sm_blockUserInput =
false;
427 if (sm_interactionActive) {
428 SmcInteractDone(smcConnection, False);
429 sm_interactionActive =
false;
430 if (sm_smActive && sm_isshutdown)
431 qt_sm_blockUserInput =
true;
442 sm_setProperty(name, value);
447 sm_setProperty(name, value);
465#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