diff --git a/autotests/kwindoweffectstest.cpp b/autotests/kwindoweffectstest.cpp index d567084..089001b 100644 --- a/autotests/kwindoweffectstest.cpp +++ b/autotests/kwindoweffectstest.cpp @@ -1,467 +1,465 @@ /* * Copyright 2013 Martin Gräßlin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include #include #include #include #include #include #include #include Q_DECLARE_METATYPE(KWindowEffects::SlideFromLocation) Q_DECLARE_METATYPE(KWindowEffects::Effect) class KWindowEffectsTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void testSlideWindow_data(); void testSlideWindow(); void testSlideWindowRemove(); void testSlideWindowWidget_data(); void testSlideWindowWidget(); void testSlideWindowWidgetRemove(); void testPresentWindows_data(); void testPresentWindows(); void testPresentWindowsEmptyGroup(); void testPresentWindowsGroup_data(); void testPresentWindowsGroup(); void testHighlightWindows_data(); void testHighlightWindows(); void testHighlightWindowsEmpty(); void testBlur_data(); void testBlur(); void testBlurDisable(); void testMarkAsDashboard(); void testEffectAvailable_data(); void testEffectAvailable(); private: int32_t locationToValue(KWindowEffects::SlideFromLocation location) const; void performSlideWindowTest(xcb_window_t window, int offset, KWindowEffects::SlideFromLocation location) const; void performSlideWindowRemoveTest(xcb_window_t window); void performWindowsOnPropertyTest(xcb_atom_t atom, const QList &windows); void performAtomIsRemoveTest(xcb_window_t window, xcb_atom_t atom); void getHelperAtom(const QByteArray &name, xcb_atom_t *atom) const; xcb_atom_t m_slide; xcb_atom_t m_presentWindows; xcb_atom_t m_presentWindowsGroup; xcb_atom_t m_highlightWindows; xcb_atom_t m_thumbnails; xcb_atom_t m_blur; QScopedPointer m_window; QScopedPointer m_widget; }; void KWindowEffectsTest::initTestCase() { m_window.reset(new QWindow()); QVERIFY(m_window->winId() != XCB_WINDOW_NONE); m_widget.reset(new QWidget()); m_widget->show(); QVERIFY(m_widget->effectiveWinId() != XCB_WINDOW_NONE); getHelperAtom(QByteArrayLiteral("_KDE_SLIDE"), &m_slide); getHelperAtom(QByteArrayLiteral("_KDE_PRESENT_WINDOWS_DESKTOP"), &m_presentWindows); getHelperAtom(QByteArrayLiteral("_KDE_PRESENT_WINDOWS_GROUP"), &m_presentWindowsGroup); getHelperAtom(QByteArrayLiteral("_KDE_WINDOW_HIGHLIGHT"), &m_highlightWindows); getHelperAtom(QByteArrayLiteral("_KDE_WINDOW_PREVIEW"), &m_thumbnails); getHelperAtom(QByteArrayLiteral("_KDE_NET_WM_BLUR_BEHIND_REGION"), &m_blur); } void KWindowEffectsTest::getHelperAtom(const QByteArray &name, xcb_atom_t *atom) const { xcb_connection_t *c = QX11Info::connection(); xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(c, false, name.length(), name.constData()); QScopedPointer reply(xcb_intern_atom_reply(c, atomCookie, nullptr)); QVERIFY(!reply.isNull()); *atom = reply->atom; } void KWindowEffectsTest::testSlideWindow_data() { QTest::addColumn("offset"); QTest::addColumn("location"); QTest::newRow("Left") << 10 << KWindowEffects::LeftEdge; QTest::newRow("Right") << 20 << KWindowEffects::RightEdge; QTest::newRow("Top") << 0 << KWindowEffects::TopEdge; QTest::newRow("Bottom") << -1 << KWindowEffects::BottomEdge; } void KWindowEffectsTest::testSlideWindow() { QFETCH(int, offset); QFETCH(KWindowEffects::SlideFromLocation, location); KWindowEffects::slideWindow(m_window->winId(), location, offset); performSlideWindowTest(m_window->winId(), offset, location); } void KWindowEffectsTest::testSlideWindowRemove() { xcb_window_t window = m_window->winId(); // first install the atom KWindowEffects::slideWindow(window, KWindowEffects::TopEdge, 0); performSlideWindowTest(window, 0, KWindowEffects::TopEdge); // now delete it KWindowEffects::slideWindow(window, KWindowEffects::NoEdge, 0); performSlideWindowRemoveTest(window); } void KWindowEffectsTest::testSlideWindowWidget_data() { QTest::addColumn("location"); QTest::newRow("Left") << KWindowEffects::LeftEdge; QTest::newRow("Right") << KWindowEffects::RightEdge; QTest::newRow("Top") << KWindowEffects::TopEdge; QTest::newRow("Bottom") << KWindowEffects::BottomEdge; } void KWindowEffectsTest::testSlideWindowWidget() { QFETCH(KWindowEffects::SlideFromLocation, location); KWindowEffects::slideWindow(m_widget->effectiveWinId(), location); performSlideWindowTest(m_widget->effectiveWinId(), -1, location); } void KWindowEffectsTest::testSlideWindowWidgetRemove() { xcb_window_t window = m_widget->effectiveWinId(); // first install the atom KWindowEffects::slideWindow(m_widget->effectiveWinId(), KWindowEffects::TopEdge); performSlideWindowTest(window, -1, KWindowEffects::TopEdge); // now delete it KWindowEffects::slideWindow(m_widget->effectiveWinId(), KWindowEffects::NoEdge); performSlideWindowRemoveTest(window); } void KWindowEffectsTest::performSlideWindowTest(xcb_window_t window, int offset, KWindowEffects::SlideFromLocation location) const { xcb_connection_t *c = QX11Info::connection(); xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(c, false, window, m_slide, m_slide, 0, 100); QScopedPointer reply(xcb_get_property_reply(c, cookie, nullptr)); QVERIFY(!reply.isNull()); QCOMPARE(reply->format, uint8_t(32)); QCOMPARE(reply->value_len, uint32_t(2)); QCOMPARE(reply->type, m_slide); int32_t *data = static_cast(xcb_get_property_value(reply.data())); QCOMPARE(data[0], offset); QCOMPARE(data[1], locationToValue(location)); } void KWindowEffectsTest::performSlideWindowRemoveTest(xcb_window_t window) { performAtomIsRemoveTest(window, m_slide); } void KWindowEffectsTest::performAtomIsRemoveTest(xcb_window_t window, xcb_atom_t atom) { xcb_connection_t *c = QX11Info::connection(); xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(c, false, window, atom, atom, 0, 100); QScopedPointer reply(xcb_get_property_reply(c, cookie, nullptr)); QVERIFY(!reply.isNull()); QCOMPARE(reply->type, xcb_atom_t(XCB_ATOM_NONE)); } int32_t KWindowEffectsTest::locationToValue(KWindowEffects::SlideFromLocation location) const { switch (location) { case KWindowEffects::LeftEdge: return 0; case KWindowEffects::TopEdge: return 1; case KWindowEffects::RightEdge: return 2; case KWindowEffects::BottomEdge: return 3; default: return -1; } } void KWindowEffectsTest::testPresentWindows_data() { QTest::addColumn("desktop"); QTest::newRow("all desktops") << -1; QTest::newRow("1") << 1; QTest::newRow("2") << 2; QTest::newRow("3") << 3; QTest::newRow("4") << 4; } void KWindowEffectsTest::testPresentWindows() { QFETCH(int, desktop); KWindowEffects::presentWindows(m_window->winId(), desktop); xcb_connection_t *c = QX11Info::connection(); xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(c, false, m_window->winId(), m_presentWindows, m_presentWindows, 0, 100); QScopedPointer reply(xcb_get_property_reply(c, cookie, nullptr)); QVERIFY(!reply.isNull()); QCOMPARE(reply->format, uint8_t(32)); QCOMPARE(reply->value_len, uint32_t(1)); QCOMPARE(reply->type, m_presentWindows); int32_t *data = static_cast(xcb_get_property_value(reply.data())); QCOMPARE(data[0], desktop); } void KWindowEffectsTest::testPresentWindowsEmptyGroup() { KWindowEffects::presentWindows(m_window->winId(), QList()); xcb_connection_t *c = QX11Info::connection(); xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(c, false, m_window->winId(), m_presentWindowsGroup, m_presentWindowsGroup, 0, 100); QScopedPointer reply(xcb_get_property_reply(c, cookie, nullptr)); QVERIFY(!reply.isNull()); QCOMPARE(reply->type, xcb_atom_t(XCB_ATOM_NONE)); } void KWindowEffectsTest::testPresentWindowsGroup_data() { QTest::addColumn >("windows"); QTest::newRow("one") << (QList() << m_window->winId()); QTest::newRow("two") << (QList() << m_window->winId() << m_widget->effectiveWinId()); } void KWindowEffectsTest::testPresentWindowsGroup() { QFETCH(QList, windows); KWindowEffects::presentWindows(m_window->winId(), windows); performWindowsOnPropertyTest(m_presentWindowsGroup, windows); } void KWindowEffectsTest::testHighlightWindows_data() { QTest::addColumn >("windows"); QTest::newRow("one") << (QList() << m_window->winId()); QTest::newRow("two") << (QList() << m_window->winId() << m_widget->effectiveWinId()); } void KWindowEffectsTest::testHighlightWindows() { QFETCH(QList, windows); KWindowEffects::highlightWindows(m_window->winId(), windows); performWindowsOnPropertyTest(m_highlightWindows, windows); } void KWindowEffectsTest::testHighlightWindowsEmpty() { // ensure it's empty KWindowEffects::highlightWindows(m_window->winId(), QList()); performAtomIsRemoveTest(m_window->winId(), m_highlightWindows); // install some windows on the atom QList windows; windows.append(m_window->winId()); windows.append(m_widget->effectiveWinId()); KWindowEffects::highlightWindows(m_window->winId(), windows); performWindowsOnPropertyTest(m_highlightWindows, windows); // and remove it again KWindowEffects::highlightWindows(m_window->winId(), QList()); performAtomIsRemoveTest(m_window->winId(), m_highlightWindows); } void KWindowEffectsTest::performWindowsOnPropertyTest(xcb_atom_t atom, const QList< WId > &windows) { xcb_connection_t *c = QX11Info::connection(); xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(c, false, m_window->winId(), atom, atom, 0, 100); QScopedPointer reply(xcb_get_property_reply(c, cookie, nullptr)); QVERIFY(!reply.isNull()); QCOMPARE(reply->type, atom); QCOMPARE(reply->format, uint8_t(32)); QCOMPARE(reply->value_len, uint32_t(windows.size())); int32_t *data = static_cast(xcb_get_property_value(reply.data())); for (int i = 0; i < windows.size(); ++i) { QCOMPARE(data[i], int32_t(windows.at(i))); } } void KWindowEffectsTest::testBlur_data() { QTest::addColumn("blur"); QRegion region(0, 0, 10, 10); QTest::newRow("one rect") << region; region = region.united(QRect(20, 20, 5, 5)); QTest::newRow("two rects") << region; region = region.united(QRect(100, 100, 20, 20)); QTest::newRow("three rects") << region; QTest::newRow("empty") << QRegion(); } void KWindowEffectsTest::testBlur() { QFETCH(QRegion, blur); KWindowEffects::enableBlurBehind(m_window->winId(), true, blur); xcb_connection_t *c = QX11Info::connection(); xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(c, false, m_window->winId(), m_blur, XCB_ATOM_CARDINAL, 0, 100); QScopedPointer reply(xcb_get_property_reply(c, cookie, nullptr)); QVERIFY(!reply.isNull()); QCOMPARE(reply->type, xcb_atom_t(XCB_ATOM_CARDINAL)); QCOMPARE(reply->format, uint8_t(32)); QCOMPARE(reply->value_len, uint32_t(blur.rectCount() * 4)); uint32_t *data = static_cast(xcb_get_property_value(reply.data())); - QVector rects = blur.rects(); - for (int i = 0; i < rects.count(); ++i) { - int counter = i * 4; - const QRect &rect = rects.at(i); - QCOMPARE(data[counter++], uint32_t(rect.x())); - QCOMPARE(data[counter++], uint32_t(rect.y())); - QCOMPARE(data[counter++], uint32_t(rect.width())); - QCOMPARE(data[counter++], uint32_t(rect.height())); + int dataOffset = 0; + for (const QRect& rect : blur) { + QCOMPARE(data[dataOffset++], uint32_t(rect.x())); + QCOMPARE(data[dataOffset++], uint32_t(rect.y())); + QCOMPARE(data[dataOffset++], uint32_t(rect.width())); + QCOMPARE(data[dataOffset++], uint32_t(rect.height())); } } void KWindowEffectsTest::testBlurDisable() { KWindowEffects::enableBlurBehind(m_window->winId(), false); performAtomIsRemoveTest(m_window->winId(), m_blur); KWindowEffects::enableBlurBehind(m_window->winId(), true); //verify that it got added xcb_connection_t *c = QX11Info::connection(); xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(c, false, m_window->winId(), m_blur, XCB_ATOM_CARDINAL, 0, 100); QScopedPointer reply(xcb_get_property_reply(c, cookie, nullptr)); QVERIFY(!reply.isNull()); QCOMPARE(reply->type, xcb_atom_t(XCB_ATOM_CARDINAL)); // and disable KWindowEffects::enableBlurBehind(m_window->winId(), false); performAtomIsRemoveTest(m_window->winId(), m_blur); } void KWindowEffectsTest::testMarkAsDashboard() { const QByteArray className = QByteArrayLiteral("dashboard"); // should not yet be set xcb_connection_t *c = QX11Info::connection(); xcb_get_property_cookie_t cookie = xcb_get_property_unchecked(c, false, m_window->winId(), XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 0, 100); QScopedPointer reply(xcb_get_property_reply(c, cookie, nullptr)); QVERIFY(!reply.isNull()); QCOMPARE(reply->type, xcb_atom_t(XCB_ATOM_STRING)); QCOMPARE(reply->format, uint8_t(8)); char *data = static_cast(xcb_get_property_value(reply.data())); QVERIFY(QByteArray(data) != className); // now mark as dashboard KWindowEffects::markAsDashboard(m_window->winId()); cookie = xcb_get_property_unchecked(c, false, m_window->winId(), XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 0, 100); reply.reset(xcb_get_property_reply(c, cookie, nullptr)); QVERIFY(!reply.isNull()); QCOMPARE(reply->type, xcb_atom_t(XCB_ATOM_STRING)); QCOMPARE(reply->format, uint8_t(8)); QCOMPARE(reply->value_len, uint32_t(19)); data = static_cast(xcb_get_property_value(reply.data())); QCOMPARE(QByteArray(data), className); data = data + 10; QCOMPARE(QByteArray(data), className); } void KWindowEffectsTest::testEffectAvailable_data() { QTest::addColumn("effect"); QTest::addColumn("propertyName"); QTest::newRow("slide") << KWindowEffects::Slide << QByteArrayLiteral("_KDE_SLIDE"); QTest::newRow("PresentWindows") << KWindowEffects::PresentWindows << QByteArrayLiteral("_KDE_PRESENT_WINDOWS_DESKTOP"); QTest::newRow("PresentWindowsGroup") << KWindowEffects::PresentWindowsGroup << QByteArrayLiteral("_KDE_PRESENT_WINDOWS_GROUP"); QTest::newRow("HighlightWindows") << KWindowEffects::HighlightWindows << QByteArrayLiteral("_KDE_WINDOW_HIGHLIGHT"); QTest::newRow("BlurBehind") << KWindowEffects::BlurBehind << QByteArrayLiteral("_KDE_NET_WM_BLUR_BEHIND_REGION"); QTest::newRow("Dashboard") << KWindowEffects::Dashboard << QByteArrayLiteral("_WM_EFFECT_KDE_DASHBOARD"); QTest::newRow("BackgroundContrast") << KWindowEffects::BackgroundContrast << QByteArrayLiteral("_KDE_NET_WM_BACKGROUND_CONTRAST_REGION"); } void KWindowEffectsTest::testEffectAvailable() { NETRootInfo rootInfo(QX11Info::connection(), NET::Supported | NET::SupportingWMCheck); if (qstrcmp(rootInfo.wmName(), "KWin") == 0) { QSKIP("KWin running, we don't want to interact with the running system"); } // this test verifies whether an effect is available QFETCH(KWindowEffects::Effect, effect); // without a compositing manager it's not available // try-verify as there still might be the selection claimed from previous data run QTRY_VERIFY(!KWindowSystem::compositingActive()); QVERIFY(!KWindowEffects::isEffectAvailable(effect)); // fake the compositor QSignalSpy compositingChangedSpy(KWindowSystem::self(), &KWindowSystem::compositingChanged); QVERIFY(compositingChangedSpy.isValid()); KSelectionOwner compositorSelection("_NET_WM_CM_S0"); QSignalSpy claimedSpy(&compositorSelection, &KSelectionOwner::claimedOwnership); QVERIFY(claimedSpy.isValid()); compositorSelection.claim(true); QVERIFY(claimedSpy.wait()); QCOMPARE(compositingChangedSpy.count(), 1); QCOMPARE(compositingChangedSpy.first().first().toBool(), true); QVERIFY(KWindowSystem::compositingActive()); // but not yet available QVERIFY(!KWindowEffects::isEffectAvailable(effect)); // set the atom QFETCH(QByteArray, propertyName); xcb_connection_t *c = QX11Info::connection(); xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(c, false, propertyName.length(), propertyName.constData()); QScopedPointer atom(xcb_intern_atom_reply(c, atomCookie, nullptr)); QVERIFY(!atom.isNull()); unsigned char dummy = 0; xcb_change_property(c, XCB_PROP_MODE_REPLACE, QX11Info::appRootWindow(), atom->atom, atom->atom, 8, 1, &dummy); xcb_flush(c); // now the effect should be available QVERIFY(KWindowEffects::isEffectAvailable(effect)); // delete the property again xcb_delete_property(c, QX11Info::appRootWindow(), atom->atom); xcb_flush(c); // which means it's no longer available QVERIFY(!KWindowEffects::isEffectAvailable(effect)); // remove compositing selection compositorSelection.release(); QVERIFY(compositingChangedSpy.wait()); QCOMPARE(compositingChangedSpy.count(), 2); QCOMPARE(compositingChangedSpy.last().first().toBool(), false); QVERIFY(!KWindowSystem::compositingActive()); } QTEST_MAIN(KWindowEffectsTest) #include "kwindoweffectstest.moc" diff --git a/src/platforms/xcb/kwindoweffects.cpp b/src/platforms/xcb/kwindoweffects.cpp index 0b647b5..43428aa 100644 --- a/src/platforms/xcb/kwindoweffects.cpp +++ b/src/platforms/xcb/kwindoweffects.cpp @@ -1,345 +1,343 @@ /* * Copyright 2009 Marco Martin * Copyright 2014 Martin Gräßlin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "kwindoweffects_x11.h" #include #include #include "kwindowsystem.h" #include #include #include #include static const char DASHBOARD_WIN_CLASS[] = "dashboard\0dashboard"; using namespace KWindowEffects; KWindowEffectsPrivateX11::KWindowEffectsPrivateX11() { } KWindowEffectsPrivateX11::~KWindowEffectsPrivateX11() { } bool KWindowEffectsPrivateX11::isEffectAvailable(Effect effect) { if (!KWindowSystem::self()->compositingActive()) { return false; } QByteArray effectName; switch (effect) { case Slide: effectName = QByteArrayLiteral("_KDE_SLIDE"); break; case PresentWindows: effectName = QByteArrayLiteral("_KDE_PRESENT_WINDOWS_DESKTOP"); break; case PresentWindowsGroup: effectName = QByteArrayLiteral("_KDE_PRESENT_WINDOWS_GROUP"); break; case HighlightWindows: effectName = QByteArrayLiteral("_KDE_WINDOW_HIGHLIGHT"); break; case BlurBehind: effectName = QByteArrayLiteral("_KDE_NET_WM_BLUR_BEHIND_REGION"); break; case Dashboard: // TODO: Better namespacing for atoms effectName = QByteArrayLiteral("_WM_EFFECT_KDE_DASHBOARD"); break; case BackgroundContrast: effectName = QByteArrayLiteral("_KDE_NET_WM_BACKGROUND_CONTRAST_REGION"); break; default: return false; } // hackish way to find out if KWin has the effect enabled, // TODO provide proper support xcb_connection_t *c = QX11Info::connection(); xcb_list_properties_cookie_t propsCookie = xcb_list_properties_unchecked(c, QX11Info::appRootWindow()); xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(c, false, effectName.length(), effectName.constData()); QScopedPointer props(xcb_list_properties_reply(c, propsCookie, nullptr)); QScopedPointer atom(xcb_intern_atom_reply(c, atomCookie, nullptr)); if (!atom || !props) { return false; } xcb_atom_t *atoms = xcb_list_properties_atoms(props.data()); for (int i = 0; i < props->atoms_len; ++i) { if (atoms[i] == atom->atom) { return true; } } return false; } void KWindowEffectsPrivateX11::slideWindow(WId id, SlideFromLocation location, int offset) { xcb_connection_t *c = QX11Info::connection(); if (!c) { return; } const QByteArray effectName = QByteArrayLiteral("_KDE_SLIDE"); xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(c, false, effectName.length(), effectName.constData()); const int size = 2; int32_t data[size]; data[0] = offset; switch (location) { case LeftEdge: data[1] = 0; break; case TopEdge: data[1] = 1; break; case RightEdge: data[1] = 2; break; case BottomEdge: data[1] = 3; default: break; } QScopedPointer atom(xcb_intern_atom_reply(c, atomCookie, nullptr)); if (!atom) { return; } if (location == NoEdge) { xcb_delete_property(c, id, atom->atom); } else { xcb_change_property(c, XCB_PROP_MODE_REPLACE, id, atom->atom, atom->atom, 32, size, data); } } QList KWindowEffectsPrivateX11::windowSizes(const QList &ids) { QList windowSizes; Q_FOREACH (WId id, ids) { if (id > 0) { KWindowInfo info(id, NET::WMGeometry | NET::WMFrameExtents); windowSizes.append(info.frameGeometry().size()); } else { windowSizes.append(QSize()); } } return windowSizes; } void KWindowEffectsPrivateX11::presentWindows(WId controller, const QList &ids) { xcb_connection_t *c = QX11Info::connection(); if (!c) { return; } const int numWindows = ids.count(); QVarLengthArray data(numWindows); int actualCount = 0; for (int i = 0; i < numWindows; ++i) { data[i] = ids.at(i); ++actualCount; } if (actualCount != numWindows) { data.resize(actualCount); } if (data.isEmpty()) { return; } const QByteArray effectName = QByteArrayLiteral("_KDE_PRESENT_WINDOWS_GROUP"); xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(c, false, effectName.length(), effectName.constData()); QScopedPointer atom(xcb_intern_atom_reply(c, atomCookie, nullptr)); if (!atom) { return; } xcb_change_property(c, XCB_PROP_MODE_REPLACE, controller, atom->atom, atom->atom, 32, data.size(), data.constData()); } void KWindowEffectsPrivateX11::presentWindows(WId controller, int desktop) { xcb_connection_t *c = QX11Info::connection(); if (!c) { return; } const QByteArray effectName = QByteArrayLiteral("_KDE_PRESENT_WINDOWS_DESKTOP"); xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(c, false, effectName.length(), effectName.constData()); QScopedPointer atom(xcb_intern_atom_reply(c, atomCookie, nullptr)); if (!atom) { return; } int32_t data = desktop; xcb_change_property(c, XCB_PROP_MODE_REPLACE, controller, atom->atom, atom->atom, 32, 1, &data); } void KWindowEffectsPrivateX11::highlightWindows(WId controller, const QList &ids) { xcb_connection_t *c = QX11Info::connection(); if (!c) { return; } const QByteArray effectName = QByteArrayLiteral("_KDE_WINDOW_HIGHLIGHT"); xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(c, false, effectName.length(), effectName.constData()); QScopedPointer atom(xcb_intern_atom_reply(c, atomCookie, nullptr)); if (!atom) { return; } const int numWindows = ids.count(); if (numWindows == 0) { xcb_delete_property(c, controller, atom->atom); return; } QVarLengthArray data(numWindows); int actualCount = 0; for (int i = 0; i < numWindows; ++i) { data[i] = ids.at(i); ++actualCount; } if (actualCount != numWindows) { data.resize(actualCount); } if (data.isEmpty()) { return; } xcb_change_property(c, XCB_PROP_MODE_REPLACE, controller, atom->atom, atom->atom, 32, data.size(), data.constData()); } void KWindowEffectsPrivateX11::enableBlurBehind(WId window, bool enable, const QRegion ®ion) { xcb_connection_t *c = QX11Info::connection(); if (!c) { return; } const QByteArray effectName = QByteArrayLiteral("_KDE_NET_WM_BLUR_BEHIND_REGION"); xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(c, false, effectName.length(), effectName.constData()); QScopedPointer atom(xcb_intern_atom_reply(c, atomCookie, nullptr)); if (!atom) { return; } if (enable) { - QVector rects = region.rects(); QVector data; - data.reserve(rects.count() * 4); - Q_FOREACH (const QRect &r, rects) { + data.reserve(region.rectCount() * 4); + for (const QRect& r : region) { // kwin on X uses device pixels, convert from logical auto dpr = qApp->devicePixelRatio(); data << r.x() * dpr << r.y() * dpr << r.width() * dpr << r.height() * dpr; } xcb_change_property(c, XCB_PROP_MODE_REPLACE, window, atom->atom, XCB_ATOM_CARDINAL, 32, data.size(), data.constData()); } else { xcb_delete_property(c, window, atom->atom); } } void KWindowEffectsPrivateX11::enableBackgroundContrast(WId window, bool enable, qreal contrast, qreal intensity, qreal saturation, const QRegion ®ion) { xcb_connection_t *c = QX11Info::connection(); const QByteArray effectName = QByteArrayLiteral("_KDE_NET_WM_BACKGROUND_CONTRAST_REGION"); xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(c, false, effectName.length(), effectName.constData()); QScopedPointer atom(xcb_intern_atom_reply(c, atomCookie, nullptr)); if (!atom) { return; } if (enable) { - QVector rects = region.rects(); QVector data; - data.reserve(rects.count() * 4 + 16); - Q_FOREACH (const QRect &r, rects) { + data.reserve(region.rectCount() * 4 + 16); + for (const QRect& r : region) { auto dpr = qApp->devicePixelRatio(); data << r.x() * dpr << r.y() * dpr << r.width() * dpr << r.height() * dpr; } QMatrix4x4 satMatrix; //saturation QMatrix4x4 intMatrix; //intensity QMatrix4x4 contMatrix; //contrast //Saturation matrix if (!qFuzzyCompare(saturation, 1.0)) { const qreal rval = (1.0 - saturation) * .2126; const qreal gval = (1.0 - saturation) * .7152; const qreal bval = (1.0 - saturation) * .0722; satMatrix = QMatrix4x4(rval + saturation, rval, rval, 0.0, gval, gval + saturation, gval, 0.0, bval, bval, bval + saturation, 0.0, 0, 0, 0, 1.0); } //IntensityMatrix if (!qFuzzyCompare(intensity, 1.0)) { intMatrix.scale(intensity, intensity, intensity); } //Contrast Matrix if (!qFuzzyCompare(contrast, 1.0)) { const float transl = (1.0 - contrast) / 2.0; contMatrix = QMatrix4x4(contrast, 0, 0, 0.0, 0, contrast, 0, 0.0, 0, 0, contrast, 0.0, transl, transl, transl, 1.0); } QMatrix4x4 colorMatrix = contMatrix * satMatrix * intMatrix; colorMatrix = colorMatrix.transposed(); uint32_t *rawData = reinterpret_cast(colorMatrix.data()); for (int i = 0; i < 16; ++i) { data << rawData[i]; } xcb_change_property(c, XCB_PROP_MODE_REPLACE, window, atom->atom, atom->atom, 32, data.size(), data.constData()); } else { xcb_delete_property(c, window, atom->atom); } } void KWindowEffectsPrivateX11::markAsDashboard(WId window) { xcb_connection_t *c = QX11Info::connection(); if (!c) { return; } xcb_change_property(c, XCB_PROP_MODE_REPLACE, window, XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 8, 19, DASHBOARD_WIN_CLASS); }