diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -1,5 +1,6 @@ add_definitions(-DKWIN_UNIT_TEST) remove_definitions(-DQT_USE_QSTRINGBUILDER) +add_subdirectory(libxrenderutils) add_subdirectory(wayland) if (HAVE_INPUT) add_subdirectory(libinput) diff --git a/autotests/libxrenderutils/CMakeLists.txt b/autotests/libxrenderutils/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/autotests/libxrenderutils/CMakeLists.txt @@ -0,0 +1,11 @@ +add_executable(blendPictureTest blendpicture_test.cpp) +target_link_libraries(blendPictureTest + kwinxrenderutils + Qt5::Test + Qt5::Gui + Qt5::X11Extras + XCB::XCB + XCB::RENDER + XCB::XFIXES + ) +ecm_mark_as_test(blendPictureTest) diff --git a/autotests/libxrenderutils/blendpicture_test.cpp b/autotests/libxrenderutils/blendpicture_test.cpp new file mode 100644 --- /dev/null +++ b/autotests/libxrenderutils/blendpicture_test.cpp @@ -0,0 +1,59 @@ +/******************************************************************** +KWin - the KDE window manager +This file is part of the KDE project. + +Copyright (C) 2016 Martin Gräßlin + +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 . +*********************************************************************/ +#include +#include +#include + +#include "../../libkwineffects/kwinxrenderutils.h" + +class BlendPictureTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + + void testDontCrashOnTeardown(); +}; + +void BlendPictureTest::initTestCase() +{ + KWin::XRenderUtils::init(QX11Info::connection(), QX11Info::appRootWindow()); +} + +void BlendPictureTest::cleanupTestCase() +{ + KWin::XRenderUtils::cleanup(); +} + +void BlendPictureTest::testDontCrashOnTeardown() +{ + // this test uses xrenderBlendPicture - the only idea is to trigger the creation + // closing the application should not crash + // see BUG 363251 + const auto picture = KWin::xRenderBlendPicture(0.5); + // and a second one + const auto picture2 = KWin::xRenderBlendPicture(0.6); + Q_UNUSED(picture) + Q_UNUSED(picture2) +} + +QTEST_MAIN(BlendPictureTest) +#include "blendpicture_test.moc" diff --git a/libkwineffects/kwinxrenderutils.h b/libkwineffects/kwinxrenderutils.h --- a/libkwineffects/kwinxrenderutils.h +++ b/libkwineffects/kwinxrenderutils.h @@ -180,6 +180,11 @@ */ KWINXRENDERUTILS_EXPORT const xcb_render_directformat_t *findPictFormatInfo(xcb_render_pictformat_t format); +/** + * @internal + **/ +KWINXRENDERUTILS_EXPORT void cleanup(); + } // namespace XRenderUtils } // namespace KWin diff --git a/libkwineffects/kwinxrenderutils.cpp b/libkwineffects/kwinxrenderutils.cpp --- a/libkwineffects/kwinxrenderutils.cpp +++ b/libkwineffects/kwinxrenderutils.cpp @@ -21,6 +21,7 @@ #include "kwinxrenderutils.h" #include "logging_p.h" +#include #include #include #include @@ -32,13 +33,21 @@ { static xcb_connection_t *s_connection = nullptr; static xcb_window_t s_rootWindow = XCB_WINDOW_NONE; +static XRenderPicture s_blendPicture(XCB_RENDER_PICTURE_NONE); void init(xcb_connection_t *connection, xcb_window_t rootWindow) { s_connection = connection; s_rootWindow = rootWindow; } +void cleanup() +{ + s_blendPicture = XRenderPicture(XCB_RENDER_PICTURE_NONE); + s_connection = nullptr; + s_rootWindow = XCB_WINDOW_NONE; +} + } // namespace // adapted from Qt, because this really sucks ;) @@ -78,16 +87,15 @@ XRenderPicture xRenderBlendPicture(double opacity) { - static XRenderPicture s_blendPicture(XCB_RENDER_PICTURE_NONE); static xcb_render_color_t s_blendColor = {0, 0, 0, 0}; s_blendColor.alpha = uint16_t(opacity * 0xffff); - if (s_blendPicture == XCB_RENDER_PICTURE_NONE) { - s_blendPicture = xRenderFill(s_blendColor); + if (XRenderUtils::s_blendPicture == XCB_RENDER_PICTURE_NONE) { + XRenderUtils::s_blendPicture = xRenderFill(s_blendColor); } else { xcb_rectangle_t rect = {0, 0, 1, 1}; - xcb_render_fill_rectangles(XRenderUtils::s_connection, XCB_RENDER_PICT_OP_SRC, s_blendPicture, s_blendColor, 1, &rect); + xcb_render_fill_rectangles(XRenderUtils::s_connection, XCB_RENDER_PICT_OP_SRC, XRenderUtils::s_blendPicture, s_blendColor, 1, &rect); } - return s_blendPicture; + return XRenderUtils::s_blendPicture; } static xcb_render_picture_t createPicture(xcb_pixmap_t pix, int depth) @@ -150,8 +158,10 @@ XRenderPictureData::~XRenderPictureData() { - if (picture != XCB_RENDER_PICTURE_NONE) + if (picture != XCB_RENDER_PICTURE_NONE) { + Q_ASSERT(qApp); xcb_render_free_picture(XRenderUtils::s_connection, picture); + } } XFixesRegion::XFixesRegion(const QRegion ®ion) diff --git a/workspace.cpp b/workspace.cpp --- a/workspace.cpp +++ b/workspace.cpp @@ -465,6 +465,9 @@ // TODO: ungrabXServer(); + if (kwinApp()->operationMode() == Application::OperationModeX11) { + XRenderUtils::cleanup(); + } Xcb::Extensions::destroy(); _self = 0; }