Support passing generic QIcon through PlasmaWindow interface
Summary: Especially for Xwayland windows the compositor might not have a themed icon name. Resulting in a task manager not having dedicated icons for Xwayland windows. This change deprecates the way how a compositor is supposed to set the window icon. Instead of passing the themed icon name, it is now supposed to pass the QIcon. In case it's a themed icon the existing way to pass to the client is used. Otherwise a new event is used to inform the client that there is an icon - no data is transmitted at this point. The client can then create a file descriptor and pass it to the compositor. The compositor serializes the icon into the file descriptor and the client can read from it. This all happens transparently on client side there is no api change at all. The writing and reading of the icon is done in a thread. Due to that Qt5::Concurrent is now a required dependency instead of an optional dependency. Reviewers: #plasma_on_wayland, hein Subscribers: plasma-devel Tags: #plasma_on_wayland Differential Revision: https://phabricator.kde.org/D3049
This commit is contained in:
parent
bd34a6d828
commit
d92592a291
6 changed files with 118 additions and 22 deletions
|
@ -145,6 +145,7 @@ target_link_libraries(KF5WaylandServer
|
|||
PRIVATE
|
||||
Wayland::Server
|
||||
EGL::EGL
|
||||
Qt5::Concurrent
|
||||
)
|
||||
|
||||
if(IS_ABSOLUTE "${KF5_INCLUDE_INSTALL_DIR}")
|
||||
|
|
|
@ -66,6 +66,7 @@ private Q_SLOTS:
|
|||
void testRequestShowingDesktop();
|
||||
void testParentWindow();
|
||||
void testGeometry();
|
||||
void testIcon();
|
||||
|
||||
void cleanup();
|
||||
|
||||
|
@ -545,5 +546,40 @@ void TestWindowManagement::testGeometry()
|
|||
QCOMPARE(window->geometry(), QRect(0, 0, 35, 45));
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(TestWindowManagement)
|
||||
void TestWindowManagement::testIcon()
|
||||
{
|
||||
using namespace KWayland::Client;
|
||||
QVERIFY(m_window);
|
||||
QSignalSpy iconChangedSpy(m_window, &PlasmaWindow::iconChanged);
|
||||
QVERIFY(iconChangedSpy.isValid());
|
||||
m_windowInterface->setIcon(QIcon());
|
||||
// first goes from themed name to empty
|
||||
QVERIFY(iconChangedSpy.wait());
|
||||
if (!QIcon::hasThemeIcon(QStringLiteral("wayland"))) {
|
||||
QEXPECT_FAIL("", "no icon", Continue);
|
||||
}
|
||||
QCOMPARE(m_window->icon().name(), QStringLiteral("wayland"));
|
||||
QVERIFY(iconChangedSpy.wait());
|
||||
if (!QIcon::hasThemeIcon(QStringLiteral("wayland"))) {
|
||||
QEXPECT_FAIL("", "no icon", Continue);
|
||||
}
|
||||
QCOMPARE(m_window->icon().name(), QStringLiteral("wayland"));
|
||||
|
||||
// create an icon with a pixmap
|
||||
QPixmap p(32, 32);
|
||||
p.fill(Qt::red);
|
||||
m_windowInterface->setIcon(p);
|
||||
QVERIFY(iconChangedSpy.wait());
|
||||
QCOMPARE(m_window->icon().pixmap(32, 32), p);
|
||||
|
||||
// let's set a themed icon
|
||||
m_windowInterface->setIcon(QIcon::fromTheme(QStringLiteral("xorg")));
|
||||
QVERIFY(iconChangedSpy.wait());
|
||||
if (!QIcon::hasThemeIcon(QStringLiteral("xorg"))) {
|
||||
QEXPECT_FAIL("", "no icon", Continue);
|
||||
}
|
||||
QCOMPARE(m_window->icon().name(), QStringLiteral("xorg"));
|
||||
}
|
||||
|
||||
QTEST_MAIN(TestWindowManagement)
|
||||
#include "test_wayland_windowmanagement.moc"
|
||||
|
|
|
@ -23,6 +23,9 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "display.h"
|
||||
#include "surface_interface.h"
|
||||
|
||||
#include <QtConcurrentRun>
|
||||
#include <QFile>
|
||||
#include <QIcon>
|
||||
#include <QList>
|
||||
#include <QVector>
|
||||
#include <QRect>
|
||||
|
@ -70,6 +73,7 @@ public:
|
|||
void setTitle(const QString &title);
|
||||
void setAppId(const QString &appId);
|
||||
void setThemedIconName(const QString &iconName);
|
||||
void setIcon(const QIcon &icon);
|
||||
void setVirtualDesktop(quint32 desktop);
|
||||
void unmap();
|
||||
void setState(org_kde_plasma_window_management_state flag, bool set);
|
||||
|
@ -97,6 +101,7 @@ private:
|
|||
static void setMinimizedGeometryCallback(wl_client *client, wl_resource *resource, wl_resource *panel, uint32_t x, uint32_t y, uint32_t width, uint32_t height);
|
||||
static void unsetMinimizedGeometryCallback(wl_client *client, wl_resource *resource, wl_resource *panel);
|
||||
static void destroyCallback(wl_client *client, wl_resource *resource);
|
||||
static void getIconCallback(wl_client *client, wl_resource *resource, int32_t fd);
|
||||
static Private *cast(wl_resource *resource) {
|
||||
return reinterpret_cast<Private*>(wl_resource_get_user_data(resource));
|
||||
}
|
||||
|
@ -105,13 +110,14 @@ private:
|
|||
QString m_title;
|
||||
QString m_appId;
|
||||
QString m_themedIconName;
|
||||
QIcon m_icon;
|
||||
quint32 m_virtualDesktop = 0;
|
||||
quint32 m_state = 0;
|
||||
wl_listener listener;
|
||||
static const struct org_kde_plasma_window_interface s_interface;
|
||||
};
|
||||
|
||||
const quint32 PlasmaWindowManagementInterface::Private::s_version = 6;
|
||||
const quint32 PlasmaWindowManagementInterface::Private::s_version = 7;
|
||||
|
||||
PlasmaWindowManagementInterface::Private::Private(PlasmaWindowManagementInterface *q, Display *d)
|
||||
: Global::Private(d, &org_kde_plasma_window_management_interface, s_version)
|
||||
|
@ -267,7 +273,8 @@ const struct org_kde_plasma_window_interface PlasmaWindowInterface::Private::s_i
|
|||
closeCallback,
|
||||
requestMoveCallback,
|
||||
requestResizeCallback,
|
||||
destroyCallback
|
||||
destroyCallback,
|
||||
getIconCallback
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -326,7 +333,13 @@ void PlasmaWindowInterface::Private::createResource(wl_resource *parent, uint32_
|
|||
org_kde_plasma_window_send_title_changed(resource, m_title.toUtf8().constData());
|
||||
}
|
||||
org_kde_plasma_window_send_state_changed(resource, m_state);
|
||||
org_kde_plasma_window_send_themed_icon_name_changed(resource, m_themedIconName.toUtf8().constData());
|
||||
if (!m_themedIconName.isEmpty()) {
|
||||
org_kde_plasma_window_send_themed_icon_name_changed(resource, m_themedIconName.toUtf8().constData());
|
||||
} else {
|
||||
if (wl_resource_get_version(resource) >= ORG_KDE_PLASMA_WINDOW_ICON_CHANGED_SINCE_VERSION) {
|
||||
org_kde_plasma_window_send_icon_changed(resource);
|
||||
}
|
||||
}
|
||||
|
||||
org_kde_plasma_window_send_parent_window(resource, resourceForParent(parentWindow, resource));
|
||||
|
||||
|
@ -368,6 +381,34 @@ void PlasmaWindowInterface::Private::setThemedIconName(const QString &iconName)
|
|||
}
|
||||
}
|
||||
|
||||
void PlasmaWindowInterface::Private::setIcon(const QIcon &icon)
|
||||
{
|
||||
m_icon = icon;
|
||||
setThemedIconName(m_icon.name());
|
||||
if (m_icon.name().isEmpty()) {
|
||||
for (auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
|
||||
if (wl_resource_get_version(*it) >= ORG_KDE_PLASMA_WINDOW_ICON_CHANGED_SINCE_VERSION) {
|
||||
org_kde_plasma_window_send_icon_changed(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlasmaWindowInterface::Private::getIconCallback(wl_client *client, wl_resource *resource, int32_t fd)
|
||||
{
|
||||
Q_UNUSED(client)
|
||||
Private *p = cast(resource);
|
||||
QtConcurrent::run(
|
||||
[fd] (const QIcon &icon) {
|
||||
QFile file;
|
||||
file.open(fd, QIODevice::WriteOnly, QFileDevice::AutoCloseHandle);
|
||||
QDataStream ds(&file);
|
||||
ds << icon;
|
||||
file.close();
|
||||
}, p->m_icon
|
||||
);
|
||||
}
|
||||
|
||||
void PlasmaWindowInterface::Private::setTitle(const QString &title)
|
||||
{
|
||||
if (m_title == title) {
|
||||
|
@ -699,10 +740,17 @@ void PlasmaWindowInterface::setSkipTaskbar(bool set)
|
|||
d->setState(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPTASKBAR, set);
|
||||
}
|
||||
|
||||
#ifndef KWAYLANDSERVER_NO_DEPRECATED
|
||||
void PlasmaWindowInterface::setThemedIconName(const QString &iconName)
|
||||
{
|
||||
d->setThemedIconName(iconName);
|
||||
}
|
||||
#endif
|
||||
|
||||
void PlasmaWindowInterface::setIcon(const QIcon &icon)
|
||||
{
|
||||
d->setIcon(icon);
|
||||
}
|
||||
|
||||
void PlasmaWindowInterface::setShadeable(bool set)
|
||||
{
|
||||
|
|
|
@ -101,7 +101,13 @@ public:
|
|||
void setMaximizeable(bool set);
|
||||
void setFullscreenable(bool set);
|
||||
void setSkipTaskbar(bool skip);
|
||||
void setThemedIconName(const QString &iconName);
|
||||
/**
|
||||
* @deprecated since 5.28 use setIcon
|
||||
* @see setIcon
|
||||
**/
|
||||
#ifndef KWAYLANDSERVER_NO_DEPRECATED
|
||||
void KWAYLANDSERVER_DEPRECATED setThemedIconName(const QString &iconName);
|
||||
#endif
|
||||
/**
|
||||
* @since 5.22
|
||||
*/
|
||||
|
@ -155,6 +161,19 @@ public:
|
|||
**/
|
||||
void setGeometry(const QRect &geometry);
|
||||
|
||||
/**
|
||||
* Set the icon of the PlasmaWindowInterface.
|
||||
*
|
||||
* In case the icon has a themed name, only the name is sent to the client.
|
||||
* Otherwise the client is only informed that there is an icon and the client
|
||||
* can request the icon in an asynchronous way by passing a file descriptor
|
||||
* into which the icon will be serialized.
|
||||
*
|
||||
* @param icon The new icon
|
||||
* @since 5.28
|
||||
**/
|
||||
void setIcon(const QIcon &icon);
|
||||
|
||||
Q_SIGNALS:
|
||||
void closeRequested();
|
||||
/**
|
||||
|
|
|
@ -10,8 +10,7 @@ target_link_libraries(testServer KF5::WaylandServer)
|
|||
ecm_mark_as_test(testServer)
|
||||
|
||||
find_package(Qt5Widgets ${QT_MIN_VERSION} CONFIG QUIET)
|
||||
find_package(Qt5Concurrent ${QT_MIN_VERSION} CONFIG QUIET)
|
||||
if (Qt5Widgets_FOUND AND Qt5Concurrent_FOUND)
|
||||
if (Qt5Widgets_FOUND)
|
||||
set(testRenderingServer_SRCS
|
||||
renderingservertest.cpp
|
||||
)
|
||||
|
@ -24,11 +23,9 @@ add_executable(copyClient copyclient.cpp)
|
|||
target_link_libraries(copyClient KF5::WaylandClient)
|
||||
ecm_mark_as_test(copyClient)
|
||||
|
||||
if (Qt5Concurrent_FOUND)
|
||||
add_executable(pasteClient pasteclient.cpp)
|
||||
target_link_libraries(pasteClient Qt5::Concurrent KF5::WaylandClient)
|
||||
ecm_mark_as_test(pasteClient)
|
||||
endif()
|
||||
add_executable(pasteClient pasteclient.cpp)
|
||||
target_link_libraries(pasteClient Qt5::Concurrent KF5::WaylandClient)
|
||||
ecm_mark_as_test(pasteClient)
|
||||
|
||||
if (HAVE_LINUX_INPUT_H)
|
||||
add_executable(touchClientTest touchclienttest.cpp)
|
||||
|
|
|
@ -2,14 +2,9 @@ add_subdirectory(testserver)
|
|||
|
||||
include(ECMMarkAsTest)
|
||||
|
||||
find_package(Qt5Concurrent ${QT_MIN_VERSION} CONFIG QUIET)
|
||||
set(scannerSRCS generator.cpp)
|
||||
|
||||
if (Qt5Concurrent_FOUND)
|
||||
set(scannerSRCS generator.cpp)
|
||||
|
||||
add_definitions(-DMAPPING_FILE="${CMAKE_CURRENT_SOURCE_DIR}/mapping.txt")
|
||||
add_executable(kwaylandScanner ${scannerSRCS})
|
||||
target_link_libraries(kwaylandScanner Qt5::Core Qt5::Concurrent)
|
||||
ecm_mark_as_test(kwaylandScanner)
|
||||
|
||||
endif()
|
||||
add_definitions(-DMAPPING_FILE="${CMAKE_CURRENT_SOURCE_DIR}/mapping.txt")
|
||||
add_executable(kwaylandScanner ${scannerSRCS})
|
||||
target_link_libraries(kwaylandScanner Qt5::Core Qt5::Concurrent)
|
||||
ecm_mark_as_test(kwaylandScanner)
|
||||
|
|
Loading…
Reference in a new issue