Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qxcbsessionmanager.cpp
Go to the documentation of this file.
1// Copyright (C) 2013 Teo Mrnjavac <teo@kde.org>
2// Copyright (C) 2016 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
6
7#ifndef QT_NO_SESSIONMANAGER
8
9#include <QtCore/qvarlengtharray.h>
10#include <qpa/qwindowsysteminterface.h>
11
12#include <qguiapplication.h>
13#include <qdatetime.h>
14#include <qfileinfo.h>
15#include <qplatformdefs.h>
16#include <qsocketnotifier.h>
17#include <X11/SM/SMlib.h>
18#include <errno.h> // ERANGE
19
20#include <cerrno> // ERANGE
21
22using namespace Qt::StringLiterals;
23
25{
27public:
33
34public Q_SLOTS:
35 void socketActivated();
36};
37
38
39static SmcConn smcConnection = nullptr;
41static bool sm_smActive;
43static int sm_saveType;
44static bool sm_cancel;
46static bool sm_isshutdown;
47static bool sm_phase2;
48static bool sm_in_phase2;
50
52
53static void resetSmState();
54static void sm_setProperty(const char *name, const char *type,
55 int num_vals, SmPropValue *vals);
56static void sm_saveYourselfCallback(SmcConn smcConn, SmPointer clientData,
57 int saveType, Bool shutdown , int interactStyle, Bool fast);
58static void sm_saveYourselfPhase2Callback(SmcConn smcConn, SmPointer clientData) ;
59static void sm_dieCallback(SmcConn smcConn, SmPointer clientData) ;
60static void sm_shutdownCancelledCallback(SmcConn smcConn, SmPointer clientData);
61static void sm_saveCompleteCallback(SmcConn smcConn, SmPointer clientData);
62static void sm_interactCallback(SmcConn smcConn, SmPointer clientData);
64
65static void resetSmState()
66{
69 sm_interactStyle = SmInteractStyleNone;
70 sm_smActive = false;
72 sm_isshutdown = false;
73 sm_phase2 = false;
74 sm_in_phase2 = false;
75}
76
77
78// theoretically it's possible to set several properties at once. For
79// simplicity, however, we do just one property at a time
80static void sm_setProperty(const char *name, const char *type,
81 int num_vals, SmPropValue *vals)
82{
83 if (num_vals) {
84 SmProp prop;
85 prop.name = const_cast<char*>(name);
86 prop.type = const_cast<char*>(type);
87 prop.num_vals = num_vals;
88 prop.vals = vals;
89
90 SmProp* props[1];
91 props[0] = &prop;
92 SmcSetProperties(smcConnection, 1, props);
93 } else {
94 char* names[1];
95 names[0] = const_cast<char*>(name);
96 SmcDeleteProperties(smcConnection, 1, names);
97 }
98}
99
100static void sm_setProperty(const QString &name, const QString &value)
101{
102 QByteArray v = value.toUtf8();
103 SmPropValue prop;
104 prop.length = v.size();
105 prop.value = (SmPointer) const_cast<char *>(v.constData());
106 sm_setProperty(name.toLatin1().data(), SmARRAY8, 1, &prop);
107}
108
109static void sm_setProperty(const QString &name, const QStringList &value)
110{
111 SmPropValue *prop = new SmPropValue[value.size()];
112 int count = 0;
113 QList<QByteArray> vl;
114 vl.reserve(value.size());
116 prop[count].length = (*it).size();
117 vl.append((*it).toUtf8());
118 prop[count].value = (char*)vl.constLast().data();
119 ++count;
120 }
121 sm_setProperty(name.toLatin1().data(), SmLISTofARRAY8, count, prop);
122 delete [] prop;
123}
124
125
126// workaround for broken libsm, see below
129 unsigned int shutdown_in_progress : 1;
130};
131
132static void sm_saveYourselfCallback(SmcConn smcConn, SmPointer clientData,
133 int saveType, Bool shutdown , int interactStyle, Bool /*fast*/)
134{
135 if (smcConn != smcConnection)
136 return;
137 sm_cancel = false;
138 sm_smActive = true;
139 sm_isshutdown = shutdown;
140 sm_saveType = saveType;
141 sm_interactStyle = interactStyle;
142
143 // ugly workaround for broken libSM. libSM should do that _before_
144 // actually invoking the callback in sm_process.c
145 ((QT_smcConn*)smcConn)->save_yourself_in_progress = true;
146 if (sm_isshutdown)
147 ((QT_smcConn*)smcConn)->shutdown_in_progress = true;
148
150 if (!sm_isshutdown) // we cannot expect a confirmation message in that case
151 resetSmState();
152}
153
155{
156 if (sm_isshutdown)
158
159 // generate a new session key
160 timeval tv;
161 gettimeofday(&tv, nullptr);
162 sm->setSessionKey(QString::number(qulonglong(tv.tv_sec)) +
163 u'_' +
164 QString::number(qulonglong(tv.tv_usec)));
165
168 : arguments.at(0);
169
170 // tell the session manager about our program in best POSIX style
171 sm_setProperty(QString::fromLatin1(SmProgram), argument0);
172 // tell the session manager about our user as well.
173 struct passwd *entryPtr = nullptr;
174#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && (_POSIX_THREAD_SAFE_FUNCTIONS - 0 > 0)
175 QVarLengthArray<char, 1024> buf(qMax<long>(sysconf(_SC_GETPW_R_SIZE_MAX), 1024L));
176 struct passwd entry;
177 while (getpwuid_r(geteuid(), &entry, buf.data(), buf.size(), &entryPtr) == ERANGE) {
178 if (buf.size() >= 32768) {
179 // too big already, fail
180 static char badusername[] = "";
181 entryPtr = &entry;
182 entry.pw_name = badusername;
183 break;
184 }
185
186 // retry with a bigger buffer
187 buf.resize(buf.size() * 2);
188 }
189#else
190 entryPtr = getpwuid(geteuid());
191#endif
192 if (entryPtr)
193 sm_setProperty(QString::fromLatin1(SmUserID), QString::fromLocal8Bit(entryPtr->pw_name));
194
195 // generate a restart and discard command that makes sense
196 QStringList restart;
197 restart << argument0 << "-session"_L1 << sm->sessionId() + u'_' + sm->sessionKey();
198
200 if (qAppName().compare(fi.fileName(), Qt::CaseInsensitive) != 0)
201 restart << "-name"_L1 << qAppName();
202 sm->setRestartCommand(restart);
203 QStringList discard;
204 sm->setDiscardCommand(discard);
205
206 switch (sm_saveType) {
207 case SmSaveBoth:
208 sm->appCommitData();
210 break; // we cancelled the shutdown, no need to save state
212 case SmSaveLocal:
213 sm->appSaveState();
214 break;
215 case SmSaveGlobal:
216 sm->appCommitData();
217 break;
218 default:
219 break;
220 }
221
222 if (sm_phase2 && !sm_in_phase2) {
223 SmcRequestSaveYourselfPhase2(smcConnection, sm_saveYourselfPhase2Callback, (SmPointer*) sm);
224 qt_sm_blockUserInput = false;
225 } else {
226 // close eventual interaction monitors and cancel the
227 // shutdown, if required. Note that we can only cancel when
228 // performing a shutdown, it does not work for checkpoints
230 SmcInteractDone(smcConnection, sm_isshutdown && sm_cancel);
231 sm_interactionActive = false;
232 } else if (sm_cancel && sm_isshutdown) {
233 if (sm->allowsErrorInteraction()) {
234 SmcInteractDone(smcConnection, True);
235 sm_interactionActive = false;
236 }
237 }
238
239 // set restart and discard command in session manager
240 sm_setProperty(QString::fromLatin1(SmRestartCommand), sm->restartCommand());
241 sm_setProperty(QString::fromLatin1(SmDiscardCommand), sm->discardCommand());
242
243 // set the restart hint
244 SmPropValue prop;
245 prop.length = sizeof(int);
246 int value = sm->restartHint();
247 prop.value = (SmPointer) &value;
248 sm_setProperty(SmRestartStyleHint, SmCARD8, 1, &prop);
249
250 // we are done
251 SmcSaveYourselfDone(smcConnection, !sm_cancel);
252 }
253}
254
255static void sm_dieCallback(SmcConn smcConn, SmPointer /* clientData */)
256{
257 if (smcConn != smcConnection)
258 return;
259 resetSmState();
260 QWindowSystemInterface::handleApplicationTermination<QWindowSystemInterface::SynchronousDelivery>();
261}
262
263static void sm_shutdownCancelledCallback(SmcConn smcConn, SmPointer clientData)
264{
265 if (smcConn != smcConnection)
266 return;
268 ((QXcbSessionManager *) clientData)->exitEventLoop();
269 resetSmState();
270}
271
272static void sm_saveCompleteCallback(SmcConn smcConn, SmPointer /*clientData */)
273{
274 if (smcConn != smcConnection)
275 return;
276 resetSmState();
277}
278
279static void sm_interactCallback(SmcConn smcConn, SmPointer clientData)
280{
281 if (smcConn != smcConnection)
282 return;
284 ((QXcbSessionManager *) clientData)->exitEventLoop();
285}
286
287static void sm_saveYourselfPhase2Callback(SmcConn smcConn, SmPointer clientData)
288{
289 if (smcConn != smcConnection)
290 return;
291 sm_in_phase2 = true;
293}
294
295
297{
298 IceProcessMessages(SmcGetIceConnection(smcConnection), nullptr, nullptr);
299}
300
301
302// QXcbSessionManager starts here
303
306 , m_eventLoop(nullptr)
307{
308 resetSmState();
309 char cerror[256];
310 char* myId = nullptr;
311 QByteArray b_id = id.toLatin1();
312 char* prevId = b_id.data();
313
314 SmcCallbacks cb;
315 cb.save_yourself.callback = sm_saveYourselfCallback;
316 cb.save_yourself.client_data = (SmPointer) this;
317 cb.die.callback = sm_dieCallback;
318 cb.die.client_data = (SmPointer) this;
319 cb.save_complete.callback = sm_saveCompleteCallback;
320 cb.save_complete.client_data = (SmPointer) this;
321 cb.shutdown_cancelled.callback = sm_shutdownCancelledCallback;
322 cb.shutdown_cancelled.client_data = (SmPointer) this;
323
324 // avoid showing a warning message below
325 if (!qEnvironmentVariableIsSet("SESSION_MANAGER"))
326 return;
327
328 smcConnection = SmcOpenConnection(nullptr, nullptr, 1, 0,
329 SmcSaveYourselfProcMask |
330 SmcDieProcMask |
331 SmcSaveCompleteProcMask |
332 SmcShutdownCancelledProcMask,
333 &cb,
334 prevId,
335 &myId,
336 256, cerror);
337
339 ::free(myId); // it was allocated by C
340
342 if (!smcConnection)
343 qWarning("Qt: Session management error: %s", qPrintable(error));
344 else
345 sm_receiver = new QSmSocketReceiver(IceConnectionNumber(SmcGetIceConnection(smcConnection)));
346}
347
349{
350 if (smcConnection)
351 SmcCloseConnection(smcConnection, 0, nullptr);
352 smcConnection = nullptr;
353 delete sm_receiver;
354}
355
356
358{
359 return (void*) smcConnection;
360}
361
363{
365 return true;
366
368 return false;
369
370 if (sm_interactStyle == SmInteractStyleAny) {
371 sm_waitingForInteraction = SmcInteractRequest(smcConnection,
372 SmDialogNormal,
374 (SmPointer*) this);
375 }
377 QEventLoop eventLoop;
378 m_eventLoop = &eventLoop;
379 eventLoop.exec();
380 m_eventLoop = nullptr;
381
383 if (sm_smActive) { // not cancelled
385 qt_sm_blockUserInput = false;
386 return true;
387 }
388 }
389 return false;
390}
391
393{
395 return true;
396
398 return false;
399
400 if (sm_interactStyle == SmInteractStyleAny || sm_interactStyle == SmInteractStyleErrors) {
401 sm_waitingForInteraction = SmcInteractRequest(smcConnection,
402 SmDialogError,
404 (SmPointer*) this);
405 }
407 QEventLoop eventLoop;
408 m_eventLoop = &eventLoop;
409 eventLoop.exec();
410 m_eventLoop = nullptr;
411
413 if (sm_smActive) { // not cancelled
415 qt_sm_blockUserInput = false;
416 return true;
417 }
418 }
419 return false;
420}
421
423{
425 SmcInteractDone(smcConnection, False);
426 sm_interactionActive = false;
429 }
430}
431
433{
434 sm_cancel = true;
435}
436
441
446
448{
449 return sm_in_phase2;
450}
451
453{
454 sm_phase2 = true;
455}
456
458{
459 m_eventLoop->exit();
460}
461
462#include "qxcbsessionmanager.moc"
463
464#endif
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:611
static QString applicationFilePath()
Returns the file path of the application executable.
static QStringList arguments()
\inmodule QtCore
Definition qeventloop.h:16
int exec(ProcessEventsFlags flags=AllEvents)
Enters the main event loop and waits until exit() is called.
void exit(int returnCode=0)
Tells the event loop to exit with a return code.
bool isEmpty() const noexcept
Definition qlist.h:401
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
const_iterator ConstIterator
Definition qlist.h:250
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
iterator begin()
Definition qset.h:136
iterator end()
Definition qset.h:140
\inmodule QtCore
\inmodule QtCore
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5949
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
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
bool allowsErrorInteraction() override
void setSessionId(const QString &id)
QSet< QString >::iterator it
QList< QVariant > arguments
@ CaseInsensitive
#define Q_FALLTHROUGH()
QString qAppName()
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qWarning
Definition qlogging.h:166
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
GLsizei const GLfloat * v
[13]
GLuint64 key
GLenum GLuint id
[7]
GLenum GLenum GLsizei count
GLenum type
GLenum GLuint GLenum GLsizei const GLchar * buf
GLenum GLuint GLsizei const GLenum * props
GLuint name
GLuint GLuint * names
GLuint entry
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
#define qPrintable(string)
Definition qstring.h:1531
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
#define Q_OBJECT
#define Q_SLOTS
static int compare(quint64 a, quint64 b)
quint64 qulonglong
Definition qtypes.h:64
static int sm_interactStyle
static int sm_saveType
static bool sm_phase2
static bool sm_interactionActive
static void sm_setProperty(const char *name, const char *type, int num_vals, SmPropValue *vals)
static void sm_saveYourselfPhase2Callback(SmcConn smcConn, SmPointer clientData)
static bool sm_in_phase2
static bool sm_smActive
static bool sm_waitingForInteraction
static void sm_saveYourselfCallback(SmcConn smcConn, SmPointer clientData, int saveType, Bool shutdown, int interactStyle, Bool fast)
static void sm_dieCallback(SmcConn smcConn, SmPointer clientData)
static void sm_saveCompleteCallback(SmcConn smcConn, SmPointer clientData)
bool qt_sm_blockUserInput
static void resetSmState()
static void sm_shutdownCancelledCallback(SmcConn smcConn, SmPointer clientData)
static QSmSocketReceiver * sm_receiver
static void sm_performSaveYourself(QXcbSessionManager *)
static SmcConn smcConnection
static bool sm_cancel
static void sm_interactCallback(SmcConn smcConn, SmPointer clientData)
static bool sm_isshutdown
QObject::connect nullptr
QTcpSocket * socket
[1]
unsigned int shutdown_in_progress
unsigned int save_yourself_in_progress