[kwin] Add sanity checks for the QPA plugin

KWin requires the xcb plugin otherwise KWin crashes when the first
xcb/xlib code is called. First KWin tries to set the QT_QPA_PLATFORM
to "xcb", but that doesn't protect against the command line switch.

Thus KWin also verifies that after constructing the QGuiApplication
the platform name is set to xcb, if not it exits gracefully with a
useful error message instead a crash.

To make that work the KWinSelectionOwner has to be changed to a
pointer and be delayed constructed, otherwise the crash already happens
in the KSelectionOwner.

Furthermore a small sanity check on the plugin is performed by checking
whether KWin can get the XDisplay from the QPA. If not it means that the
QPA plugin was compiled with -no-xcb-xlib which KWin doesn't support, it
still uses XLib at various places. If KWin doesn't get the Display, it
exits gracefully with a clear error message.

CCBUG: 331880
REVIEW: 116669
This commit is contained in:
Martin Gräßlin 2014-03-09 12:37:21 +01:00
parent 0d6dfd83a1
commit 72882f6aba
2 changed files with 23 additions and 7 deletions

View file

@ -185,7 +185,7 @@ int Application::crashes = 0;
Application::Application(int &argc, char **argv)
: QApplication(argc, argv)
, owner(screen_number)
, owner()
, m_eventFilter(new XcbEventFilter())
, m_replace(false)
, m_configLock(false)
@ -237,12 +237,13 @@ void Application::start()
if (screen_number == -1)
screen_number = QX11Info::appScreen();
connect(&owner, &KSelectionOwner::failedToClaimOwnership, []{
owner.reset(new KWinSelectionOwner(screen_number));
connect(owner.data(), &KSelectionOwner::failedToClaimOwnership, []{
fputs(i18n("kwin: unable to claim manager selection, another wm running? (try using --replace)\n").toLocal8Bit().constData(), stderr);
::exit(1);
});
connect(&owner, SIGNAL(lostOwnership()), SLOT(lostSelection()));
connect(&owner, &KSelectionOwner::claimedOwnership, [this]{
connect(owner.data(), SIGNAL(lostOwnership()), SLOT(lostSelection()));
connect(owner.data(), &KSelectionOwner::claimedOwnership, [this]{
// we want all QQuickWindows with an alpha buffer
QQuickWindow::setDefaultAlphaBuffer(true);
@ -284,7 +285,7 @@ void Application::start()
crashChecking();
// we need to do an XSync here, otherwise the QPA might crash us later on
Xcb::sync();
owner.claim(m_replace, true);
owner->claim(m_replace, true);
atoms = new Atoms;
}
@ -292,7 +293,7 @@ void Application::start()
Application::~Application()
{
delete Workspace::self();
if (owner.ownerWindow() != XCB_WINDOW_NONE) // If there was no --replace (no new WM)
if (!owner.isNull() && owner->ownerWindow() != XCB_WINDOW_NONE) // If there was no --replace (no new WM)
Xcb::setInputFocus(XCB_INPUT_FOCUS_POINTER_ROOT);
delete options;
delete atoms;
@ -478,6 +479,9 @@ KWIN_EXPORT int kdemain(int argc, char * argv[])
// for several bug reports about high CPU usage (bug #239963)
setenv("QT_NO_GLIB", "1", true);
// enforce xcb plugin, unfortunately command line switch has precedence
setenv("QT_QPA_PLATFORM", "xcb", true);
org::kde::KSMServerInterface ksmserver(QStringLiteral("org.kde.ksmserver"), QStringLiteral("/KSMServer"), QDBusConnection::sessionBus());
ksmserver.suspendStartup(QStringLiteral(KWIN_NAME));
KWin::Application a(argc, argv);
@ -518,6 +522,18 @@ KWIN_EXPORT int kdemain(int argc, char * argv[])
a.setConfigLock(parser.isSet(lockOption));
a.setReplace(parser.isSet(replaceOption));
// perform sanity checks
if (a.platformName().toLower() != QStringLiteral("xcb")) {
fprintf(stderr, "%s: FATAL ERROR expecting platform xcb but got platform %s\n",
argv[0], qPrintable(a.platformName()));
exit(1);
}
if (!KWin::display()) {
fprintf(stderr, "%s: FATAL ERROR KWin requires Xlib support in the xcb plugin. Do not configure Qt with -no-xcb-xlib\n",
argv[0]);
exit(1);
}
a.start();
ksmserver.resumeStartup(QStringLiteral(KWIN_NAME));

2
main.h
View file

@ -102,7 +102,7 @@ private Q_SLOTS:
private:
void crashChecking();
KWinSelectionOwner owner;
QScopedPointer<KWinSelectionOwner> owner;
QScopedPointer<XcbEventFilter> m_eventFilter;
bool m_replace;
bool m_configLock;