Force windows of type desktop to be opaque
Summary: Plasmashell's desktop windows are RGBA which forces the compositor to perform blending and render the background. That is absolutely pointless as there is no window behind the desktop window it could blend to. All it does is destroying KWin's more optimized code path and forcing additional rendering which will never be visible (including shader push/pop). With this change KWin forces desktop windows (both X11 and Wayland) to be considered as opaque by setting the depth to 24. Thus blending is disabled and the background is not rendered. Test Plan: Verified with apitrace that KWin goes in the opaque rendering path for desktop windows. Reviewers: #kwin, #plasma Subscribers: kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D2382
This commit is contained in:
parent
9b30cfef1d
commit
7bca270f97
6 changed files with 213 additions and 2 deletions
|
@ -46,6 +46,7 @@ if (XCB_ICCCM_FOUND)
|
|||
integrationTest(NAME testDontCrashAuroraeDestroyDeco SRCS dont_crash_aurorae_destroy_deco.cpp LIBS XCB::ICCCM)
|
||||
integrationTest(NAME testPlasmaWindow SRCS plasmawindow_test.cpp LIBS XCB::ICCCM)
|
||||
integrationTest(NAME testScreenEdgeClientShow SRCS screenedge_client_show_test.cpp LIBS XCB::ICCCM)
|
||||
integrationTest(NAME testX11DesktopWindow SRCS desktop_window_x11_test.cpp LIBS XCB::ICCCM)
|
||||
endif()
|
||||
|
||||
add_subdirectory(scripting)
|
||||
|
|
178
autotests/integration/desktop_window_x11_test.cpp
Normal file
178
autotests/integration/desktop_window_x11_test.cpp
Normal file
|
@ -0,0 +1,178 @@
|
|||
/********************************************************************
|
||||
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 "deleted.h"
|
||||
#include "screenedge.h"
|
||||
#include "screens.h"
|
||||
#include "wayland_server.h"
|
||||
#include "workspace.h"
|
||||
#include "shell_client.h"
|
||||
#include "xcbutils.h"
|
||||
#include <kwineffects.h>
|
||||
|
||||
#include <netwm.h>
|
||||
#include <xcb/xcb_icccm.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
static const QString s_socketName = QStringLiteral("wayland_test_kwin_x11_desktop_window-0");
|
||||
|
||||
class X11DesktopWindowTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
void init();
|
||||
void cleanup();
|
||||
void testDesktopWindow();
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
void X11DesktopWindowTest::initTestCase()
|
||||
{
|
||||
qRegisterMetaType<KWin::ShellClient*>();
|
||||
qRegisterMetaType<KWin::AbstractClient*>();
|
||||
qRegisterMetaType<KWin::Deleted*>();
|
||||
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));
|
||||
QVERIFY(waylandServer()->init(s_socketName.toLocal8Bit()));
|
||||
|
||||
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 X11DesktopWindowTest::init()
|
||||
{
|
||||
screens()->setCurrent(0);
|
||||
Cursor::setPos(QPoint(640, 512));
|
||||
}
|
||||
|
||||
void X11DesktopWindowTest::cleanup()
|
||||
{
|
||||
}
|
||||
|
||||
struct XcbConnectionDeleter
|
||||
{
|
||||
static inline void cleanup(xcb_connection_t *pointer)
|
||||
{
|
||||
xcb_disconnect(pointer);
|
||||
}
|
||||
};
|
||||
|
||||
void X11DesktopWindowTest::testDesktopWindow()
|
||||
{
|
||||
// this test creates a desktop window with an RGBA visual and verifies that it's only considered
|
||||
// as an RGB (opaque) window in KWin
|
||||
|
||||
// create an xcb window
|
||||
QScopedPointer<xcb_connection_t, XcbConnectionDeleter> c(xcb_connect(nullptr, nullptr));
|
||||
QVERIFY(!xcb_connection_has_error(c.data()));
|
||||
|
||||
xcb_window_t w = xcb_generate_id(c.data());
|
||||
const QRect windowGeometry(0, 0, 1280, 1024);
|
||||
|
||||
// helper to find the visual
|
||||
auto findDepth = [&c] () -> xcb_visualid_t {
|
||||
// find a visual with 32 depth
|
||||
const xcb_setup_t *setup = xcb_get_setup(c.data());
|
||||
|
||||
for (auto screen = xcb_setup_roots_iterator(setup); screen.rem; xcb_screen_next(&screen)) {
|
||||
for (auto depth = xcb_screen_allowed_depths_iterator(screen.data); depth.rem; xcb_depth_next(&depth)) {
|
||||
if (depth.data->depth != 32) {
|
||||
continue;
|
||||
}
|
||||
const int len = xcb_depth_visuals_length(depth.data);
|
||||
const xcb_visualtype_t *visuals = xcb_depth_visuals(depth.data);
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
return visuals[0].visual_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
auto visualId = findDepth();
|
||||
auto colormapId = xcb_generate_id(c.data());
|
||||
auto cmCookie = xcb_create_colormap_checked(c.data(), XCB_COLORMAP_ALLOC_NONE, colormapId, rootWindow(), visualId);
|
||||
QVERIFY(!xcb_request_check(c.data(), cmCookie));
|
||||
|
||||
const uint32_t values[] = {XCB_PIXMAP_NONE, defaultScreen()->black_pixel, colormapId};
|
||||
auto cookie = xcb_create_window_checked(c.data(), 32, w, rootWindow(),
|
||||
windowGeometry.x(),
|
||||
windowGeometry.y(),
|
||||
windowGeometry.width(),
|
||||
windowGeometry.height(),
|
||||
0, XCB_WINDOW_CLASS_INPUT_OUTPUT, visualId, XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL | XCB_CW_COLORMAP, values);
|
||||
QVERIFY(!xcb_request_check(c.data(), cookie));
|
||||
xcb_size_hints_t hints;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
|
||||
xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
|
||||
xcb_icccm_set_wm_normal_hints(c.data(), w, &hints);
|
||||
NETWinInfo info(c.data(), w, rootWindow(), NET::WMAllProperties, NET::WM2AllProperties);
|
||||
info.setWindowType(NET::Desktop);
|
||||
xcb_map_window(c.data(), w);
|
||||
xcb_flush(c.data());
|
||||
|
||||
// verify through a geometry request that it's depth 32
|
||||
Xcb::WindowGeometry geo(w);
|
||||
QCOMPARE(geo->depth, uint8_t(32));
|
||||
|
||||
// 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());
|
||||
QCOMPARE(client->windowType(), NET::Desktop);
|
||||
QCOMPARE(client->geometry(), windowGeometry);
|
||||
QVERIFY(client->isDesktop());
|
||||
QCOMPARE(client->depth(), 24);
|
||||
QVERIFY(!client->hasAlpha());
|
||||
|
||||
// and destroy the window again
|
||||
xcb_unmap_window(c.data(), w);
|
||||
xcb_destroy_window(c.data(), w);
|
||||
xcb_flush(c.data());
|
||||
c.reset();
|
||||
|
||||
QSignalSpy windowClosedSpy(client, &Client::windowClosed);
|
||||
QVERIFY(windowClosedSpy.isValid());
|
||||
QVERIFY(windowClosedSpy.wait());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WAYLANDTEST_MAIN(KWin::X11DesktopWindowTest)
|
||||
#include "desktop_window_x11_test.moc"
|
|
@ -49,6 +49,8 @@ private Q_SLOTS:
|
|||
void testAcceptsFocus_data();
|
||||
void testAcceptsFocus();
|
||||
|
||||
void testDesktopIsOpaque();
|
||||
|
||||
private:
|
||||
ConnectionThread *m_connection = nullptr;
|
||||
KWayland::Client::Compositor *m_compositor = nullptr;
|
||||
|
@ -176,5 +178,26 @@ void PlasmaSurfaceTest::testAcceptsFocus()
|
|||
QTEST(c->isActive(), "active");
|
||||
}
|
||||
|
||||
void PlasmaSurfaceTest::testDesktopIsOpaque()
|
||||
{
|
||||
QScopedPointer<Surface> surface(Test::createSurface());
|
||||
QVERIFY(!surface.isNull());
|
||||
QScopedPointer<ShellSurface> shellSurface(Test::createShellSurface(surface.data()));
|
||||
QVERIFY(!shellSurface.isNull());
|
||||
QScopedPointer<PlasmaShellSurface> plasmaSurface(m_plasmaShell->createSurface(surface.data()));
|
||||
QVERIFY(!plasmaSurface.isNull());
|
||||
plasmaSurface->setRole(PlasmaShellSurface::Role::Desktop);
|
||||
|
||||
// now render to map the window
|
||||
auto c = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
||||
|
||||
QVERIFY(c);
|
||||
QCOMPARE(c->windowType(), NET::Desktop);
|
||||
QVERIFY(c->isDesktop());
|
||||
|
||||
QVERIFY(!c->hasAlpha());
|
||||
QCOMPARE(c->depth(), 24);
|
||||
}
|
||||
|
||||
WAYLANDTEST_MAIN(PlasmaSurfaceTest)
|
||||
#include "plasma_surface_test.moc"
|
||||
|
|
|
@ -115,6 +115,8 @@ void TestShellClient::testMapUnmapMap()
|
|||
QVERIFY(client->isShown(true));
|
||||
QCOMPARE(client->isHiddenInternal(), false);
|
||||
QCOMPARE(client->readyForPainting(), true);
|
||||
QCOMPARE(client->depth(), 32);
|
||||
QVERIFY(client->hasAlpha());
|
||||
QCOMPARE(workspace()->activeClient(), client);
|
||||
QVERIFY(effectsWindowShownSpy.isEmpty());
|
||||
|
||||
|
@ -135,13 +137,15 @@ void TestShellClient::testMapUnmapMap()
|
|||
|
||||
QSignalSpy windowShownSpy(client, &ShellClient::windowShown);
|
||||
QVERIFY(windowShownSpy.isValid());
|
||||
Test::render(surface.data(), QSize(100, 50), Qt::blue);
|
||||
Test::render(surface.data(), QSize(100, 50), Qt::blue, QImage::Format_RGB32);
|
||||
QCOMPARE(clientAddedSpy.count(), 1);
|
||||
QVERIFY(windowShownSpy.wait());
|
||||
QCOMPARE(windowShownSpy.count(), 1);
|
||||
QCOMPARE(clientAddedSpy.count(), 1);
|
||||
QCOMPARE(client->readyForPainting(), true);
|
||||
QCOMPARE(client->isHiddenInternal(), false);
|
||||
QCOMPARE(client->depth(), 24);
|
||||
QVERIFY(!client->hasAlpha());
|
||||
QCOMPARE(workspace()->activeClient(), client);
|
||||
QCOMPARE(effectsWindowShownSpy.count(), 1);
|
||||
QCOMPARE(effectsWindowShownSpy.first().first().value<EffectWindow*>(), client->effectWindow());
|
||||
|
|
|
@ -107,6 +107,11 @@ bool Client::manage(xcb_window_t w, bool isMapped)
|
|||
m_motif.init(window());
|
||||
info = new WinInfo(this, m_client, rootWindow(), properties, properties2);
|
||||
|
||||
if (isDesktop() && bit_depth == 32) {
|
||||
// force desktop windows to be opaque. It's a desktop after all, there is no window below
|
||||
bit_depth = 24;
|
||||
}
|
||||
|
||||
// If it's already mapped, ignore hint
|
||||
bool init_minimize = !isMapped && (info->initialMappingState() == NET::Iconic);
|
||||
|
||||
|
|
|
@ -368,7 +368,7 @@ void ShellClient::addDamage(const QRegion &damage)
|
|||
doSetGeometry(QRect(position, m_clientSize + QSize(borderLeft() + borderRight(), borderTop() + borderBottom())));
|
||||
}
|
||||
markAsMapped();
|
||||
setDepth(s->buffer()->hasAlphaChannel() ? 32 : 24);
|
||||
setDepth((s->buffer()->hasAlphaChannel() && !isDesktop()) ? 32 : 24);
|
||||
repaints_region += damage.translated(clientPos());
|
||||
Toplevel::addDamage(damage);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue