Merge branch 'Plasma/5.6'
This commit is contained in:
commit
e64450c807
9 changed files with 253 additions and 7 deletions
|
@ -147,3 +147,12 @@ if (XCB_ICCCM_FOUND)
|
|||
add_test(kwin-testStruts testStruts)
|
||||
ecm_mark_as_test(testStruts)
|
||||
endif()
|
||||
|
||||
########################################################
|
||||
# Dont Crash Empty Deco Test
|
||||
########################################################
|
||||
set( testDontCrashEmptyDeco_SRCS dont_crash_empty_deco.cpp kwin_wayland_test.cpp )
|
||||
add_executable(testDontCrashEmptyDeco ${testDontCrashEmptyDeco_SRCS})
|
||||
target_link_libraries( testDontCrashEmptyDeco kwin Qt5::Test)
|
||||
add_test(kwin-testDontCrashEmptyDeco testDontCrashEmptyDeco)
|
||||
ecm_mark_as_test(testDontCrashEmptyDeco)
|
||||
|
|
224
autotests/wayland/dont_crash_empty_deco.cpp
Normal file
224
autotests/wayland/dont_crash_empty_deco.cpp
Normal file
|
@ -0,0 +1,224 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#include "kwin_wayland_test.h"
|
||||
#include "platform.h"
|
||||
#include "client.h"
|
||||
#include "cursor.h"
|
||||
#include "screenedge.h"
|
||||
#include "screens.h"
|
||||
#include "wayland_server.h"
|
||||
#include "workspace.h"
|
||||
#include "shell_client.h"
|
||||
#include <kwineffects.h>
|
||||
|
||||
#include <KWayland/Client/connection_thread.h>
|
||||
#include <KWayland/Client/compositor.h>
|
||||
#include <KWayland/Client/event_queue.h>
|
||||
#include <KWayland/Client/registry.h>
|
||||
#include <KWayland/Client/pointer.h>
|
||||
#include <KWayland/Client/server_decoration.h>
|
||||
#include <KWayland/Client/shell.h>
|
||||
#include <KWayland/Client/seat.h>
|
||||
#include <KWayland/Client/shm_pool.h>
|
||||
#include <KWayland/Client/surface.h>
|
||||
|
||||
#include <KDecoration2/Decoration>
|
||||
|
||||
#include <linux/input.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
static const QString s_socketName = QStringLiteral("wayland_test_kwin_dont_crash_empty_decoration-0");
|
||||
|
||||
class DontCrashEmptyDecorationTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
void init();
|
||||
void cleanup();
|
||||
void testBug361551();
|
||||
|
||||
private:
|
||||
KWayland::Client::ConnectionThread *m_connection = nullptr;
|
||||
KWayland::Client::Compositor *m_compositor = nullptr;
|
||||
KWayland::Client::ServerSideDecorationManager *m_deco = nullptr;
|
||||
KWayland::Client::Seat *m_seat = nullptr;
|
||||
KWayland::Client::ShmPool *m_shm = nullptr;
|
||||
KWayland::Client::Shell *m_shell = nullptr;
|
||||
KWayland::Client::EventQueue *m_queue = nullptr;
|
||||
QThread *m_thread = nullptr;
|
||||
};
|
||||
|
||||
void DontCrashEmptyDecorationTest::initTestCase()
|
||||
{
|
||||
if (!QFile::exists(QStringLiteral("/dev/dri/card0"))) {
|
||||
QSKIP("Needs a dri device");
|
||||
}
|
||||
qRegisterMetaType<KWin::ShellClient*>();
|
||||
qRegisterMetaType<KWin::AbstractClient*>();
|
||||
QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated);
|
||||
QVERIFY(workspaceCreatedSpy.isValid());
|
||||
kwinApp()->platform()->setInitialWindowSize(QSize(1280, 1024));
|
||||
QMetaObject::invokeMethod(kwinApp()->platform(), "setOutputCount", Qt::DirectConnection, Q_ARG(int, 2));
|
||||
waylandServer()->init(s_socketName.toLocal8Bit());
|
||||
|
||||
// this test needs to enforce OpenGL compositing to get into the crashy condition
|
||||
qputenv("KWIN_COMPOSE", QByteArrayLiteral("O2"));
|
||||
kwinApp()->start();
|
||||
QVERIFY(workspaceCreatedSpy.wait());
|
||||
QCOMPARE(screens()->count(), 2);
|
||||
QCOMPARE(screens()->geometry(0), QRect(0, 0, 1280, 1024));
|
||||
QCOMPARE(screens()->geometry(1), QRect(1280, 0, 1280, 1024));
|
||||
setenv("QT_QPA_PLATFORM", "wayland", true);
|
||||
waylandServer()->initWorkspace();
|
||||
}
|
||||
|
||||
void DontCrashEmptyDecorationTest::init()
|
||||
{
|
||||
using namespace KWayland::Client;
|
||||
// setup connection
|
||||
m_connection = new ConnectionThread;
|
||||
QSignalSpy connectedSpy(m_connection, &ConnectionThread::connected);
|
||||
QVERIFY(connectedSpy.isValid());
|
||||
m_connection->setSocketName(s_socketName);
|
||||
|
||||
m_thread = new QThread(this);
|
||||
m_connection->moveToThread(m_thread);
|
||||
m_thread->start();
|
||||
|
||||
m_connection->initConnection();
|
||||
QVERIFY(connectedSpy.wait());
|
||||
|
||||
m_queue = new EventQueue(this);
|
||||
QVERIFY(!m_queue->isValid());
|
||||
m_queue->setup(m_connection);
|
||||
QVERIFY(m_queue->isValid());
|
||||
|
||||
Registry registry;
|
||||
registry.setEventQueue(m_queue);
|
||||
QSignalSpy compositorSpy(®istry, &Registry::compositorAnnounced);
|
||||
QSignalSpy shmSpy(®istry, &Registry::shmAnnounced);
|
||||
QSignalSpy shellSpy(®istry, &Registry::shellAnnounced);
|
||||
QSignalSpy seatSpy(®istry, &Registry::seatAnnounced);
|
||||
QSignalSpy decorationSpy(®istry, &Registry::serverSideDecorationManagerAnnounced);
|
||||
QSignalSpy allAnnounced(®istry, &Registry::interfacesAnnounced);
|
||||
QVERIFY(allAnnounced.isValid());
|
||||
QVERIFY(shmSpy.isValid());
|
||||
QVERIFY(shellSpy.isValid());
|
||||
QVERIFY(compositorSpy.isValid());
|
||||
QVERIFY(seatSpy.isValid());
|
||||
QVERIFY(decorationSpy.isValid());
|
||||
registry.create(m_connection->display());
|
||||
QVERIFY(registry.isValid());
|
||||
registry.setup();
|
||||
QVERIFY(allAnnounced.wait());
|
||||
QVERIFY(!compositorSpy.isEmpty());
|
||||
QVERIFY(!shmSpy.isEmpty());
|
||||
QVERIFY(!shellSpy.isEmpty());
|
||||
QVERIFY(!seatSpy.isEmpty());
|
||||
QVERIFY(!decorationSpy.isEmpty());
|
||||
|
||||
m_compositor = registry.createCompositor(compositorSpy.first().first().value<quint32>(), compositorSpy.first().last().value<quint32>(), this);
|
||||
QVERIFY(m_compositor->isValid());
|
||||
m_shm = registry.createShmPool(shmSpy.first().first().value<quint32>(), shmSpy.first().last().value<quint32>(), this);
|
||||
QVERIFY(m_shm->isValid());
|
||||
m_shell = registry.createShell(shellSpy.first().first().value<quint32>(), shellSpy.first().last().value<quint32>(), this);
|
||||
QVERIFY(m_shell->isValid());
|
||||
m_seat = registry.createSeat(seatSpy.first().first().value<quint32>(), seatSpy.first().last().value<quint32>(), this);
|
||||
QVERIFY(m_seat->isValid());
|
||||
m_deco = registry.createServerSideDecorationManager(decorationSpy.first().first().value<quint32>(), decorationSpy.first().last().value<quint32>());
|
||||
QVERIFY(m_deco->isValid());
|
||||
QSignalSpy hasPointerSpy(m_seat, &Seat::hasPointerChanged);
|
||||
QVERIFY(hasPointerSpy.isValid());
|
||||
QVERIFY(hasPointerSpy.wait());
|
||||
|
||||
screens()->setCurrent(0);
|
||||
Cursor::setPos(QPoint(640, 512));
|
||||
}
|
||||
|
||||
void DontCrashEmptyDecorationTest::cleanup()
|
||||
{
|
||||
delete m_compositor;
|
||||
m_compositor = nullptr;
|
||||
delete m_deco;
|
||||
m_deco = nullptr;
|
||||
delete m_seat;
|
||||
m_seat = nullptr;
|
||||
delete m_shm;
|
||||
m_shm = nullptr;
|
||||
delete m_shell;
|
||||
m_shell = nullptr;
|
||||
delete m_queue;
|
||||
m_queue = nullptr;
|
||||
if (m_thread) {
|
||||
m_connection->deleteLater();
|
||||
m_thread->quit();
|
||||
m_thread->wait();
|
||||
delete m_thread;
|
||||
m_thread = nullptr;
|
||||
m_connection = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void DontCrashEmptyDecorationTest::testBug361551()
|
||||
{
|
||||
// this test verifies that resizing an X11 window to an invalid size does not result in crash on unmap
|
||||
// when the DecorationRenderer gets copied to the Deleted
|
||||
// there a repaint is scheduled and the resulting texture is invalid if the window size is invalid
|
||||
|
||||
// create an xcb window
|
||||
xcb_connection_t *c = xcb_connect(nullptr, nullptr);
|
||||
QVERIFY(!xcb_connection_has_error(c));
|
||||
|
||||
xcb_window_t w = xcb_generate_id(c);
|
||||
xcb_create_window(c, XCB_COPY_FROM_PARENT, w, rootWindow(), 0, 0, 10, 10, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr);
|
||||
xcb_map_window(c, w);
|
||||
xcb_flush(c);
|
||||
|
||||
// we should get a client for it
|
||||
QSignalSpy windowCreatedSpy(workspace(), &Workspace::clientAdded);
|
||||
QVERIFY(windowCreatedSpy.isValid());
|
||||
QVERIFY(windowCreatedSpy.wait());
|
||||
Client *client = windowCreatedSpy.first().first().value<Client*>();
|
||||
QVERIFY(client);
|
||||
QCOMPARE(client->window(), w);
|
||||
QVERIFY(client->isDecorated());
|
||||
|
||||
// let's set a stupid geometry
|
||||
client->setGeometry(0, 0, 0, 0);
|
||||
QCOMPARE(client->geometry(), QRect(0, 0, 0, 0));
|
||||
|
||||
// and destroy the window again
|
||||
xcb_unmap_window(c, w);
|
||||
xcb_destroy_window(c, w);
|
||||
xcb_flush(c);
|
||||
xcb_disconnect(c);
|
||||
|
||||
QSignalSpy windowClosedSpy(client, &Client::windowClosed);
|
||||
QVERIFY(windowClosedSpy.isValid());
|
||||
QVERIFY(windowClosedSpy.wait());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WAYLANDTEST_MAIN(KWin::DontCrashEmptyDecorationTest)
|
||||
#include "dont_crash_empty_deco.moc"
|
|
@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
*********************************************************************/
|
||||
#include "kwin_wayland_test.h"
|
||||
#include "../../platform.h"
|
||||
#include "../../composite.h"
|
||||
#include "../../effects.h"
|
||||
#include "../../wayland_server.h"
|
||||
#include "../../workspace.h"
|
||||
|
@ -112,8 +113,7 @@ void WaylandTestApplication::continueStartupWithScreens()
|
|||
waylandServer()->initOutputs();
|
||||
|
||||
createCompositor();
|
||||
|
||||
startXwaylandServer();
|
||||
connect(Compositor::self(), &Compositor::sceneCreated, this, &WaylandTestApplication::startXwaylandServer);
|
||||
}
|
||||
|
||||
void WaylandTestApplication::continueStartupWithX()
|
||||
|
@ -190,6 +190,7 @@ void WaylandTestApplication::createX11Connection()
|
|||
|
||||
void WaylandTestApplication::startXwaylandServer()
|
||||
{
|
||||
disconnect(Compositor::self(), &Compositor::sceneCreated, this, &WaylandTestApplication::startXwaylandServer);
|
||||
int pipeFds[2];
|
||||
if (pipe(pipeFds) != 0) {
|
||||
std::cerr << "FATAL ERROR failed to create pipe to start Xwayland " << std::endl;
|
||||
|
|
|
@ -275,6 +275,7 @@ void Compositor::slotCompositingOptionsInitialized()
|
|||
}
|
||||
return;
|
||||
}
|
||||
emit sceneCreated();
|
||||
|
||||
if (Workspace::self()) {
|
||||
startupWithWorkspace();
|
||||
|
|
|
@ -186,6 +186,7 @@ public Q_SLOTS:
|
|||
Q_SIGNALS:
|
||||
void compositingToggled(bool active);
|
||||
void aboutToDestroy();
|
||||
void sceneCreated();
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *te);
|
||||
|
|
|
@ -23,6 +23,7 @@ Comment[sv]=Övertona animering när verktygstips eller underrättelser ändrar
|
|||
Comment[uk]=Анімація зі зміною освітленості під час зміни геометрії панелей підказок і сповіщень
|
||||
Comment[x-test]=xxCross fade animation when Tooltips or Notifications change their geometryxx
|
||||
Comment[zh_CN]=在工具提示或者通知大小变化时交叉淡入淡出的动画
|
||||
Comment[zh_TW]=當工具提示或通知變更位置時交錯的淡出動畫
|
||||
Encoding=UTF-8
|
||||
Icon=preferences-system-windows-effect-morphingpopups
|
||||
Name=Morphing popups
|
||||
|
@ -49,6 +50,7 @@ Name[sv]=Föränderliga meddelanderutor
|
|||
Name[uk]=Аморфні контекстні панелі
|
||||
Name[x-test]=xxMorphing popupsxx
|
||||
Name[zh_CN]=变形气泡通知
|
||||
Name[zh_TW]=交錯彈出視窗
|
||||
Type=Service
|
||||
X-KDE-ParentApp=
|
||||
X-KDE-PluginInfo-Author=Marco Martin
|
||||
|
|
|
@ -18,6 +18,7 @@ You should have received a copy of the GNU General Public License
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#include "main_wayland.h"
|
||||
#include "composite.h"
|
||||
#include "workspace.h"
|
||||
#include <config-kwin.h>
|
||||
// kwin
|
||||
|
@ -151,8 +152,7 @@ void ApplicationWayland::continueStartupWithScreens()
|
|||
return;
|
||||
}
|
||||
createCompositor();
|
||||
|
||||
startXwaylandServer();
|
||||
connect(Compositor::self(), &Compositor::sceneCreated, this, &ApplicationWayland::startXwaylandServer);
|
||||
}
|
||||
|
||||
void ApplicationWayland::continueStartupWithX()
|
||||
|
@ -279,6 +279,7 @@ void ApplicationWayland::createX11Connection()
|
|||
|
||||
void ApplicationWayland::startXwaylandServer()
|
||||
{
|
||||
disconnect(Compositor::self(), &Compositor::sceneCreated, this, &ApplicationWayland::startXwaylandServer);
|
||||
int pipeFds[2];
|
||||
if (pipe(pipeFds) != 0) {
|
||||
std::cerr << "FATAL ERROR failed to create pipe to start Xwayland " << std::endl;
|
||||
|
|
|
@ -2501,6 +2501,11 @@ void SceneOpenGLDecorationRenderer::render()
|
|||
resetImageSizesDirty();
|
||||
}
|
||||
|
||||
if (!m_texture) {
|
||||
// for invalid sizes we get no texture, see BUG 361551
|
||||
return;
|
||||
}
|
||||
|
||||
QRect left, top, right, bottom;
|
||||
client()->client()->layoutDecorationRects(left, top, right, bottom);
|
||||
|
||||
|
|
|
@ -100,9 +100,11 @@ void WaylandServer::terminateClientConnections()
|
|||
{
|
||||
destroyInternalConnection();
|
||||
destroyInputMethodConnection();
|
||||
const auto connections = m_display->connections();
|
||||
for (auto it = connections.begin(); it != connections.end(); ++it) {
|
||||
(*it)->destroy();
|
||||
if (m_display) {
|
||||
const auto connections = m_display->connections();
|
||||
for (auto it = connections.begin(); it != connections.end(); ++it) {
|
||||
(*it)->destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue