From kde-commits Fri Sep 01 15:11:26 2017 From: =?utf-8?q?Martin_Fl=C3=B6ser?= Date: Fri, 01 Sep 2017 15:11:26 +0000 To: kde-commits Subject: [kwin] /: Add to Wayland captions if the caption is the same Message-Id: X-MARC-Message: https://marc.info/?l=kde-commits&m=150427870717112 Git commit 6685288d486925eeac5a2c14424812aa3c243902 by Martin Fl=C3=B6ser. Committed on 01/09/2017 at 15:02. Pushed by graesslin into branch 'master'. Add to Wayland captions if the caption is the same Summary: Bringing another caption feature from X11 to Wayland. If we have multiple windows with the same caption, starting from the second window a suffix is added. E.g. if we have three windows with caption "foo", the naming is: * foo * foo <2> * foo <3> The change tries to use as much shared code between the X11 and Wayland implementation. Unfortunately it's not possible to share completely as the X11 implementation does X11 specific things like editing the visible name. By sharing the code the numbering also works cross windowing system. That is if a window is called "foo" on X11, a new window on Wayland with caption "foo" will get adjusted to "foo <2>" and vice versa. The change also eliminates a duplicated signal for captionChanged in ShellClient (found by test case). By using the shared implementation on X11 side a bug gets fixed which got introduced with the support of "unresponsive", this is no longer considered and the numbering still works even if there is a window which is unresponsive. Test Plan: New test case and manual testing Reviewers: #kwin, #plasma Subscribers: plasma-devel, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D7425 M +8 -0 abstract_client.cpp M +23 -0 abstract_client.h M +48 -0 autotests/integration/shell_client_test.cpp M +2 -6 client.cpp M +6 -0 client.h M +18 -3 shell_client.cpp M +6 -0 shell_client.h https://commits.kde.org/kwin/6685288d486925eeac5a2c14424812aa3c243902 diff --git a/abstract_client.cpp b/abstract_client.cpp index 17e88ccdd..bd6262b42 100644 --- a/abstract_client.cpp +++ b/abstract_client.cpp @@ -1758,4 +1758,12 @@ QString AbstractClient::shortcutCaptionSuffix() const return QLatin1String(" {") + shortcut().toString() + QLatin1Char('}'); } = +AbstractClient *AbstractClient::findClientWithSameCaption() const +{ + auto fetchNameInternalPredicate =3D [this](const AbstractClient *cl) { + return (!cl->isSpecialWindow() || cl->isToolbar()) && cl !=3D this= && cl->captionNormal() =3D=3D captionNormal() && cl->captionSuffix() =3D= =3D captionSuffix(); + }; + return workspace()->findAbstractClient(fetchNameInternalPredicate); +} + } diff --git a/abstract_client.h b/abstract_client.h index a2fc9ad0d..d92c531ba 100644 --- a/abstract_client.h +++ b/abstract_client.h @@ -343,7 +343,24 @@ public: } = virtual void updateMouseGrab(); + /** + * @returns The caption consisting of @link{captionNormal} and @link{c= aptionSuffix} + * @see captionNormal + * @see captionSuffix + **/ virtual QString caption(bool full =3D true) const =3D 0; + /** + * @returns The caption as set by the AbstractClient without any suffi= x. + * @see caption + * @see captionSuffix + **/ + virtual QString captionNormal() const =3D 0; + /** + * @returns The suffix added to the caption (e.g. shortcut, machine na= me, etc.) + * @see caption + * @see captionNormal + **/ + virtual QString captionSuffix() const =3D 0; virtual bool isCloseable() const =3D 0; // TODO: remove boolean trap virtual bool isShown(bool shaded_is_shown) const =3D 0; @@ -986,6 +1003,12 @@ protected: QString shortcutCaptionSuffix() const; virtual void updateCaption() =3D 0; = + /** + * Looks for another AbstractClient with same @link{captionNormal} and= @link{captionSuffix}. + * If no such AbstractClient exists @c nullptr is returned. + **/ + AbstractClient *findClientWithSameCaption() const; + private: void handlePaletteChange(); QSharedPointer m_tabBoxClient; diff --git a/autotests/integration/shell_client_test.cpp b/autotests/integr= ation/shell_client_test.cpp index a0573537f..651e557ad 100644 --- a/autotests/integration/shell_client_test.cpp +++ b/autotests/integration/shell_client_test.cpp @@ -74,6 +74,7 @@ private Q_SLOTS: void testHidden(); void testDesktopFileName(); void testCaptionSimplified(); + void testCaptionMultipleWindows(); void testKillWindow_data(); void testKillWindow(); void testX11WindowId_data(); @@ -693,6 +694,53 @@ void TestShellClient::testCaptionSimplified() QCOMPARE(c->caption(), origTitle.simplified()); } = +void TestShellClient::testCaptionMultipleWindows() +{ + QScopedPointer surface(Test::createSurface()); + QScopedPointer shellSurface(qobject_cast(Test::createShellSurface(Test::ShellSurfaceType::XdgShellV5, surface.= data()))); + shellSurface->setTitle(QStringLiteral("foo")); + auto c =3D Test::renderAndWaitForShown(surface.data(), QSize(100, 50),= Qt::blue); + QVERIFY(c); + QCOMPARE(c->caption(), QStringLiteral("foo")); + QCOMPARE(c->captionNormal(), QStringLiteral("foo")); + QCOMPARE(c->captionSuffix(), QString()); + + QScopedPointer surface2(Test::createSurface()); + QScopedPointer shellSurface2(qobject_cast(Test::createShellSurface(Test::ShellSurfaceType::XdgShellV5, surface= 2.data()))); + shellSurface2->setTitle(QStringLiteral("foo")); + auto c2 =3D Test::renderAndWaitForShown(surface2.data(), QSize(100, 50= ), Qt::blue); + QVERIFY(c2); + QCOMPARE(c2->caption(), QStringLiteral("foo <2>")); + QCOMPARE(c2->captionNormal(), QStringLiteral("foo")); + QCOMPARE(c2->captionSuffix(), QStringLiteral(" <2>")); + + QScopedPointer surface3(Test::createSurface()); + QScopedPointer shellSurface3(qobject_cast(Test::createShellSurface(Test::ShellSurfaceType::XdgShellV5, surface= 3.data()))); + shellSurface3->setTitle(QStringLiteral("foo")); + auto c3 =3D Test::renderAndWaitForShown(surface3.data(), QSize(100, 50= ), Qt::blue); + QVERIFY(c3); + QCOMPARE(c3->caption(), QStringLiteral("foo <3>")); + QCOMPARE(c3->captionNormal(), QStringLiteral("foo")); + QCOMPARE(c3->captionSuffix(), QStringLiteral(" <3>")); + + QScopedPointer surface4(Test::createSurface()); + QScopedPointer shellSurface4(qobject_cast(Test::createShellSurface(Test::ShellSurfaceType::XdgShellV5, surface= 4.data()))); + shellSurface4->setTitle(QStringLiteral("bar")); + auto c4 =3D Test::renderAndWaitForShown(surface4.data(), QSize(100, 50= ), Qt::blue); + QVERIFY(c4); + QCOMPARE(c4->caption(), QStringLiteral("bar")); + QCOMPARE(c4->captionNormal(), QStringLiteral("bar")); + QCOMPARE(c4->captionSuffix(), QString()); + QSignalSpy captionChangedSpy(c4, &ShellClient::captionChanged); + QVERIFY(captionChangedSpy.isValid()); + shellSurface4->setTitle(QStringLiteral("foo")); + QVERIFY(captionChangedSpy.wait()); + QCOMPARE(captionChangedSpy.count(), 1); + QCOMPARE(c4->caption(), QStringLiteral("foo <4>")); + QCOMPARE(c4->captionNormal(), QStringLiteral("foo")); + QCOMPARE(c4->captionSuffix(), QStringLiteral(" <4>")); +} + void TestShellClient::testKillWindow_data() { QTest::addColumn("socketMode"); diff --git a/client.cpp b/client.cpp index b785fb085..ad8d48aee 100644 --- a/client.cpp +++ b/client.cpp @@ -1463,16 +1463,12 @@ void Client::setCaption(const QString& _s, bool for= ce) } QString shortcut_suffix =3D shortcutCaptionSuffix(); cap_suffix =3D machine_suffix + shortcut_suffix; - auto fetchNameInternalPredicate =3D [this](const Client *cl) { - return (!cl->isSpecialWindow() || cl->isToolbar()) && - cl !=3D this && cl->caption() =3D=3D caption(); - }; - if ((!isSpecialWindow() || isToolbar()) && workspace()->findClient(fet= chNameInternalPredicate)) { + if ((!isSpecialWindow() || isToolbar()) && findClientWithSameCaption()= ) { int i =3D 2; do { cap_suffix =3D machine_suffix + QLatin1String(" <") + QString:= :number(i) + QLatin1Char('>') + LRM; i++; - } while (workspace()->findClient(fetchNameInternalPredicate)); + } while (findClientWithSameCaption()); info->setVisibleName(caption().toUtf8().constData()); reset_name =3D false; } diff --git a/client.h b/client.h index b77c8cdf8..0e90a1be4 100644 --- a/client.h +++ b/client.h @@ -220,6 +220,12 @@ public: inline bool isBlockingCompositing() { return blocks_compositing; } = QString caption(bool full =3D true) const override; + QString captionNormal() const override { + return cap_normal; + } + QString captionSuffix() const override { + return cap_suffix; + } = using AbstractClient::keyPressEvent; void keyPressEvent(uint key_code, xcb_timestamp_t time); // FRAME ?? diff --git a/shell_client.cpp b/shell_client.cpp index 6f11b225d..381a11b85 100644 --- a/shell_client.cpp +++ b/shell_client.cpp @@ -104,12 +104,19 @@ template void ShellClient::initSurface(T *shellSurface) { m_caption =3D shellSurface->title().simplified(); - connect(shellSurface, &T::titleChanged, this, &ShellClient::captionCha= nged); + // delay till end of init + QTimer::singleShot(0, this, &ShellClient::updateCaption); connect(shellSurface, &T::destroyed, this, &ShellClient::destroyClient= ); connect(shellSurface, &T::titleChanged, this, [this] (const QString &s) { + const auto oldSuffix =3D m_captionSuffix; m_caption =3D s.simplified(); - emit captionChanged(); + updateCaption(); + if (m_captionSuffix =3D=3D oldSuffix) { + // don't emit caption change twice + // it already got emitted by the changing suffix + emit captionChanged(); + } } ); connect(shellSurface, &T::moveRequested, this, @@ -571,7 +578,15 @@ QString ShellClient::caption(bool full) const void ShellClient::updateCaption() { const QString oldSuffix =3D m_captionSuffix; - m_captionSuffix =3D shortcutCaptionSuffix(); + const auto shortcut =3D shortcutCaptionSuffix(); + m_captionSuffix =3D shortcut; + if ((!isSpecialWindow() || isToolbar()) && findClientWithSameCaption()= ) { + int i =3D 2; + do { + m_captionSuffix =3D shortcut + QLatin1String(" <") + QString::= number(i) + QLatin1Char('>'); + i++; + } while (findClientWithSameCaption()); + } if (m_captionSuffix !=3D oldSuffix) { emit captionChanged(); } diff --git a/shell_client.h b/shell_client.h index 401de11ae..a5ad7544e 100644 --- a/shell_client.h +++ b/shell_client.h @@ -64,6 +64,12 @@ public: = void blockActivityUpdates(bool b =3D true) override; QString caption(bool full =3D true) const override; + QString captionNormal() const override { + return m_caption; + } + QString captionSuffix() const override { + return m_captionSuffix; + } void closeWindow() override; AbstractClient *findModal(bool allow_itself =3D false) override; bool isCloseable() const override;