diff --git a/applets/systemtray/CMakeLists.txt b/applets/systemtray/CMakeLists.txt index 457461f36..cb0e11fe6 100644 --- a/applets/systemtray/CMakeLists.txt +++ b/applets/systemtray/CMakeLists.txt @@ -42,6 +42,7 @@ target_link_libraries(systemtraymodel_static KF5::ItemModels KF5::Plasma KF5::IconThemes + KF5::WindowSystem dbusmenuqt) kcoreaddons_add_plugin(org.kde.plasma.private.systemtray SOURCES systemtray.cpp INSTALL_NAMESPACE "plasma/applets") diff --git a/applets/systemtray/statusnotifieritemjob.cpp b/applets/systemtray/statusnotifieritemjob.cpp index 0b92832df..3cfacaf6b 100644 --- a/applets/systemtray/statusnotifieritemjob.cpp +++ b/applets/systemtray/statusnotifieritemjob.cpp @@ -18,7 +18,7 @@ */ #include "statusnotifieritemjob.h" -#include +#include StatusNotifierItemJob::StatusNotifierItemJob(StatusNotifierItemSource *source, const QString &operation, QMap ¶meters, QObject *parent) : ServiceJob(source->objectName(), operation, parameters, parent) @@ -34,6 +34,24 @@ StatusNotifierItemJob::~StatusNotifierItemJob() } void StatusNotifierItemJob::start() +{ + if (operationName() == QLatin1String("Scroll")) { + performJob(); + return; + } + + QWindow *window = nullptr; + const quint32 launchedSerial = KWindowSystem::lastInputSerial(window); + connect(KWindowSystem::self(), &KWindowSystem::xdgActivationTokenArrived, this, [this, launchedSerial](quint32 serial, const QString &token) { + if (serial == launchedSerial) { + m_source->provideXdgActivationToken(token); + performJob(); + } + }); + KWindowSystem::requestXdgActivationToken(window, launchedSerial, m_source->id()); +} + +void StatusNotifierItemJob::performJob() { if (operationName() == QString::fromLatin1("Activate")) { m_source->activate(parameters()[QStringLiteral("x")].toInt(), parameters()[QStringLiteral("y")].toInt()); diff --git a/applets/systemtray/statusnotifieritemjob.h b/applets/systemtray/statusnotifieritemjob.h index 5b7f88492..e60979df1 100644 --- a/applets/systemtray/statusnotifieritemjob.h +++ b/applets/systemtray/statusnotifieritemjob.h @@ -48,6 +48,7 @@ private Q_SLOTS: void contextMenuReady(QMenu *menu); private: + void performJob(); StatusNotifierItemSource *m_source; }; diff --git a/applets/systemtray/statusnotifieritemsource.cpp b/applets/systemtray/statusnotifieritemsource.cpp index b66d1aa5c..0f41aaba0 100644 --- a/applets/systemtray/statusnotifieritemsource.cpp +++ b/applets/systemtray/statusnotifieritemsource.cpp @@ -555,3 +555,10 @@ void StatusNotifierItemSource::contextMenu(int x, int y) } } } + +void StatusNotifierItemSource::provideXdgActivationToken(const QString &token) +{ + if (m_statusNotifierItemInterface && m_statusNotifierItemInterface->isValid()) { + m_statusNotifierItemInterface->ProvideXdgActivationToken(token); + } +} diff --git a/applets/systemtray/statusnotifieritemsource.h b/applets/systemtray/statusnotifieritemsource.h index c7a1da773..2e08a44b7 100644 --- a/applets/systemtray/statusnotifieritemsource.h +++ b/applets/systemtray/statusnotifieritemsource.h @@ -45,6 +45,7 @@ public: void secondaryActivate(int x, int y); void scroll(int delta, const QString &direction); void contextMenu(int x, int y); + void provideXdgActivationToken(const QString &token); QIcon attentionIcon() const; QString attentionIconName() const; diff --git a/dataengines/statusnotifieritem/CMakeLists.txt b/dataengines/statusnotifieritem/CMakeLists.txt index 4045f7613..2b77977e8 100644 --- a/dataengines/statusnotifieritem/CMakeLists.txt +++ b/dataengines/statusnotifieritem/CMakeLists.txt @@ -33,6 +33,7 @@ target_link_libraries(plasma_engine_statusnotifieritem KF5::Service KF5::Plasma KF5::IconThemes + KF5::WindowSystem dbusmenuqt ) diff --git a/dataengines/statusnotifieritem/statusnotifieritemjob.cpp b/dataengines/statusnotifieritem/statusnotifieritemjob.cpp index 0b92832df..cae49410e 100644 --- a/dataengines/statusnotifieritem/statusnotifieritemjob.cpp +++ b/dataengines/statusnotifieritem/statusnotifieritemjob.cpp @@ -18,7 +18,7 @@ */ #include "statusnotifieritemjob.h" -#include +#include StatusNotifierItemJob::StatusNotifierItemJob(StatusNotifierItemSource *source, const QString &operation, QMap ¶meters, QObject *parent) : ServiceJob(source->objectName(), operation, parameters, parent) @@ -34,6 +34,24 @@ StatusNotifierItemJob::~StatusNotifierItemJob() } void StatusNotifierItemJob::start() +{ + if (operationName() == QLatin1String("Scroll")) { + performJob(); + return; + } + + QWindow *window = nullptr; + const quint32 launchedSerial = KWindowSystem::lastInputSerial(window); + connect(KWindowSystem::self(), &KWindowSystem::xdgActivationTokenArrived, this, [this, launchedSerial](quint32 serial, const QString &token) { + if (serial == launchedSerial) { + m_source->provideXdgActivationToken(token); + performJob(); + } + }); + KWindowSystem::requestXdgActivationToken(window, launchedSerial, {}); +} + +void StatusNotifierItemJob::performJob() { if (operationName() == QString::fromLatin1("Activate")) { m_source->activate(parameters()[QStringLiteral("x")].toInt(), parameters()[QStringLiteral("y")].toInt()); diff --git a/dataengines/statusnotifieritem/statusnotifieritemjob.h b/dataengines/statusnotifieritem/statusnotifieritemjob.h index 5b7f88492..e60979df1 100644 --- a/dataengines/statusnotifieritem/statusnotifieritemjob.h +++ b/dataengines/statusnotifieritem/statusnotifieritemjob.h @@ -48,6 +48,7 @@ private Q_SLOTS: void contextMenuReady(QMenu *menu); private: + void performJob(); StatusNotifierItemSource *m_source; }; diff --git a/dataengines/statusnotifieritem/statusnotifieritemsource.cpp b/dataengines/statusnotifieritem/statusnotifieritemsource.cpp index 46719a000..61d232556 100644 --- a/dataengines/statusnotifieritem/statusnotifieritemsource.cpp +++ b/dataengines/statusnotifieritem/statusnotifieritemsource.cpp @@ -20,6 +20,7 @@ ***************************************************************************/ #include "statusnotifieritemsource.h" +#include "statusnotifieritem_interface.h" #include "statusnotifieritemservice.h" #include "systemtraytypes.h" @@ -540,3 +541,10 @@ void StatusNotifierItemSource::contextMenu(int x, int y) } } } + +void StatusNotifierItemSource::provideXdgActivationToken(const QString &token) +{ + if (m_statusNotifierItemInterface && m_statusNotifierItemInterface->isValid()) { + m_statusNotifierItemInterface->ProvideXdgActivationToken(token); + } +} diff --git a/dataengines/statusnotifieritem/statusnotifieritemsource.h b/dataengines/statusnotifieritem/statusnotifieritemsource.h index 4c9b279b3..fcab8ea94 100644 --- a/dataengines/statusnotifieritem/statusnotifieritemsource.h +++ b/dataengines/statusnotifieritem/statusnotifieritemsource.h @@ -46,6 +46,7 @@ public: void secondaryActivate(int x, int y); void scroll(int delta, const QString &direction); void contextMenu(int x, int y); + void provideXdgActivationToken(const QString &token); Q_SIGNALS: void contextMenuReady(QMenu *menu); diff --git a/libnotificationmanager/server.cpp b/libnotificationmanager/server.cpp index a40d588ed..83d8ea393 100644 --- a/libnotificationmanager/server.cpp +++ b/libnotificationmanager/server.cpp @@ -26,6 +26,7 @@ #include "debug.h" +#include #include using namespace NotificationManager; @@ -77,7 +78,18 @@ void Server::closeNotification(uint notificationId, CloseReason reason) void Server::invokeAction(uint notificationId, const QString &actionName) { - emit d->ActionInvoked(notificationId, actionName); + QWindow *window = nullptr; + const int launchedSerial = KWindowSystem::lastInputSerial(window); + connect(KWindowSystem::self(), + &KWindowSystem::xdgActivationTokenArrived, + this, + [this, launchedSerial, notificationId, actionName](int tokenSerial, const QString &token) { + if (tokenSerial == launchedSerial) { + emit d->ActivationToken(notificationId, token); + emit d->ActionInvoked(notificationId, actionName); + } + }); + KWindowSystem::requestXdgActivationToken(window, launchedSerial, {}); } void Server::reply(const QString &dbusService, uint notificationId, const QString &text) diff --git a/libnotificationmanager/server_p.h b/libnotificationmanager/server_p.h index 7b82d7828..099f50925 100644 --- a/libnotificationmanager/server_p.h +++ b/libnotificationmanager/server_p.h @@ -80,6 +80,7 @@ Q_SIGNALS: // DBus void NotificationClosed(uint id, uint reason); void ActionInvoked(uint id, const QString &actionKey); + void ActivationToken(uint id, const QString &activationToken); // non-standard // This is manually emitted as targeted signal in sendReplyText() void NotificationReplied(uint id, const QString &text); diff --git a/libtaskmanager/declarative/pipewiresourceitem.cpp b/libtaskmanager/declarative/pipewiresourceitem.cpp index 899a22468..a59c2a86b 100644 --- a/libtaskmanager/declarative/pipewiresourceitem.cpp +++ b/libtaskmanager/declarative/pipewiresourceitem.cpp @@ -119,7 +119,7 @@ void PipeWireSourceItem::setNodeId(uint nodeId) return nullptr; }; } else { - m_stream.reset(new PipeWireSourceStream(this)); + m_stream.reset(new PipeWireSourceStream(true, this)); m_stream->createStream(m_nodeId); if (!m_stream->error().isEmpty()) { m_stream.reset(nullptr); @@ -130,6 +130,7 @@ void PipeWireSourceItem::setNodeId(uint nodeId) connect(m_stream.data(), &PipeWireSourceStream::dmabufTextureReceived, this, &PipeWireSourceItem::updateTextureDmaBuf); connect(m_stream.data(), &PipeWireSourceStream::imageTextureReceived, this, &PipeWireSourceItem::updateTextureImage); + connect(m_stream.data(), &PipeWireSourceStream::streamChanged, this, &PipeWireSourceItem::streamChanged); } Q_EMIT nodeIdChanged(nodeId); @@ -303,3 +304,8 @@ void PipeWireSourceItem::componentComplete() m_stream->setActive(isVisible()); QQuickItem::componentComplete(); } + +QSize PipeWireSourceItem::sourceSize() const +{ + return m_stream ? m_stream->size() : QSize(); +} diff --git a/libtaskmanager/declarative/pipewiresourceitem.h b/libtaskmanager/declarative/pipewiresourceitem.h index dbd4b6bb9..5bb1db2b2 100644 --- a/libtaskmanager/declarative/pipewiresourceitem.h +++ b/libtaskmanager/declarative/pipewiresourceitem.h @@ -40,6 +40,9 @@ class PipeWireSourceItem : public QQuickItem Q_OBJECT /// Specify the pipewire node id that we want to play Q_PROPERTY(uint nodeId READ nodeId WRITE setNodeId NOTIFY nodeIdChanged) + + /// Reports the original size of the stream + Q_PROPERTY(QSize sourceSize READ sourceSize NOTIFY streamChanged) public: PipeWireSourceItem(QQuickItem *parent = nullptr); ~PipeWireSourceItem() override; @@ -52,18 +55,19 @@ public: { return m_nodeId; } + QSize sourceSize() const; void componentComplete() override; void releaseResources() override; Q_SIGNALS: + void streamChanged(); void nodeIdChanged(uint nodeId); private: void itemChange(ItemChange change, const ItemChangeData &data) override; void updateTextureDmaBuf(const QVector &plane, uint32_t format); void updateTextureImage(const QImage &image); - void setSize(const QSize &size); uint m_nodeId = 0; std::function m_createNextTexture; diff --git a/libtaskmanager/declarative/pipewiresourcestream.cpp b/libtaskmanager/declarative/pipewiresourcestream.cpp index 0118b1c2b..d9a56fb84 100644 --- a/libtaskmanager/declarative/pipewiresourcestream.cpp +++ b/libtaskmanager/declarative/pipewiresourcestream.cpp @@ -81,6 +81,10 @@ void PipeWireSourceStream::onStreamParamChanged(void *data, uint32_t id, const s uint8_t paramsBuffer[1024]; spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(paramsBuffer, sizeof(paramsBuffer)); + int extraTypes = 0; + if (pw->m_dmaBufSupported) { + extraTypes += 1 << SPA_DATA_DmaBuf; + } const spa_pod *param = (spa_pod *)spa_pod_builder_add_object(&pod_builder, SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers, @@ -95,8 +99,9 @@ void PipeWireSourceStream::onStreamParamChanged(void *data, uint32_t id, const s SPA_PARAM_BUFFERS_align, SPA_POD_Int(16), SPA_PARAM_BUFFERS_dataType, - SPA_POD_Int((1 << SPA_DATA_MemPtr) | (1 << SPA_DATA_MemFd) | (1 << SPA_DATA_DmaBuf))); + SPA_POD_Int((1 << SPA_DATA_MemPtr) | (1 << SPA_DATA_MemFd) | extraTypes)); pw_stream_update_params(pw->pwStream, ¶m, 1); + Q_EMIT pw->streamChanged(); } static void onProcess(void *data) @@ -105,8 +110,14 @@ static void onProcess(void *data) stream->process(); } -PipeWireSourceStream::PipeWireSourceStream(QObject *parent) +QSize PipeWireSourceStream::size() const +{ + return QSize(videoFormat.size.width, videoFormat.size.height); +} + +PipeWireSourceStream::PipeWireSourceStream(bool dmaBufSupported, QObject *parent) : QObject(parent) + , m_dmaBufSupported(dmaBufSupported) { pwStreamEvents.version = PW_VERSION_STREAM_EVENTS; pwStreamEvents.process = &onProcess; diff --git a/libtaskmanager/declarative/pipewiresourcestream.h b/libtaskmanager/declarative/pipewiresourcestream.h index 01a68c4f7..6e9e6edbd 100644 --- a/libtaskmanager/declarative/pipewiresourcestream.h +++ b/libtaskmanager/declarative/pipewiresourcestream.h @@ -54,7 +54,7 @@ class PipeWireSourceStream : public QObject { Q_OBJECT public: - explicit PipeWireSourceStream(QObject *parent); + explicit PipeWireSourceStream(bool dmaBufSupported, QObject *parent); ~PipeWireSourceStream(); static void onStreamParamChanged(void *data, uint32_t id, const struct spa_pod *format); @@ -67,10 +67,7 @@ public: return m_error; } - QSize size() const - { - return QSize(videoFormat.size.width, videoFormat.size.height); - } + QSize size() const; bool createStream(uint nodeid); void stop(); void setActive(bool active); @@ -82,6 +79,7 @@ Q_SIGNALS: void streamReady(); void startStreaming(); void stopStreaming(); + void streamChanged(); void dmabufTextureReceived(const QVector &planes, uint32_t format); void imageTextureReceived(const QImage &image); @@ -98,5 +96,6 @@ private: bool m_stopped = false; spa_video_info_raw videoFormat; + const bool m_dmaBufSupported = false; QString m_error; }; diff --git a/lookandfeel/contents/lockscreen/LockScreenUi.qml b/lookandfeel/contents/lockscreen/LockScreenUi.qml index bde069847..f31258c18 100644 --- a/lookandfeel/contents/lockscreen/LockScreenUi.qml +++ b/lookandfeel/contents/lockscreen/LockScreenUi.qml @@ -514,6 +514,7 @@ PlasmaCore.ColorScope { } PlasmaComponents3.ToolButton { + focusPolicy: Qt.TabFocus text: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Button to show/hide virtual keyboard", "Virtual Keyboard") icon.name: inputPanel.keyboardActive ? "input-keyboard-virtual-on" : "input-keyboard-virtual-off" onClicked: { @@ -527,6 +528,7 @@ PlasmaCore.ColorScope { } PlasmaComponents3.ToolButton { + focusPolicy: Qt.TabFocus Accessible.description: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Button to change keyboard layout", "Switch layout") icon.name: "input-keyboard"