fix(copyright): 补充copyright,删除无用文件(任务#194959)
This commit is contained in:
parent
6d032170e6
commit
da273270da
|
@ -1,96 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(taskmanager LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
#find QT modules
|
||||
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Gui Quick Widgets DBus X11Extras REQUIRED)
|
||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui Quick Widgets DBus X11Extras REQUIRED)
|
||||
|
||||
#find kde modules
|
||||
find_package(Qt5Xdg REQUIRED)
|
||||
find_package(KF5Wayland)
|
||||
find_package(KF5I18n)
|
||||
find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
|
||||
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
|
||||
include(FindQtWaylandScanner)
|
||||
include(ECMQtDeclareLoggingCategory)
|
||||
|
||||
#find other modules
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(GLIB2 REQUIRED glib-2.0)
|
||||
pkg_check_modules(GIO2 REQUIRED gio-2.0)
|
||||
pkg_check_modules(Gsetting REQUIRED gsettings-qt)
|
||||
pkg_check_modules(PipeWire REQUIRED libpipewire-0.3)
|
||||
include_directories(${GLIB2_INCLUDE_DIRS})
|
||||
include_directories(${GIO2_INCLUDE_DIRS})
|
||||
include_directories(${Gsetting_INCLUDE_DIRS})
|
||||
include_directories(${PipeWire_INCLUDE_DIRS})
|
||||
|
||||
#generate libtaskmanager.so
|
||||
set (PLUGIN_SRCS
|
||||
screencastingrequest.cpp screencastingrequest.h
|
||||
screencasting.cpp screencasting.h
|
||||
pipewirecore.cpp pipewirecore.h
|
||||
pipewiresourcestream.cpp pipewiresourcestream.h
|
||||
pipewiresourceitem.cpp pipewiresourceitem.h
|
||||
taskmanagerplugin.cpp taskmanagerplugin.h
|
||||
)
|
||||
|
||||
add_library(${PROJECT_NAME} SHARED ${PLUGIN_SRCS})
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE PLUGIN_IMPORT_URI="${PLUGIN_IMPORT_URI}")
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
Qt5::Core
|
||||
Qt5::Gui
|
||||
Qt5::Gui_EGL
|
||||
Qt::GuiPrivate
|
||||
Qt5::Quick
|
||||
Qt5::Widgets
|
||||
Qt5::DBus
|
||||
Qt5::X11Extras
|
||||
Qt5Xdg
|
||||
${GLIB2_LIBRARIES}
|
||||
${GIO2_LIBRARIES}
|
||||
${Gsetting_LIBRARIES}
|
||||
${PipeWire_LIBRARIES}
|
||||
KF5::WaylandClient
|
||||
KF5::I18n
|
||||
)
|
||||
|
||||
#generate log files
|
||||
ecm_qt_declare_logging_category(SRCS
|
||||
HEADER logging.h
|
||||
IDENTIFIER PIPEWIRE_LOGGING
|
||||
CATEGORY_NAME plasma_workspace_pipewire_logging
|
||||
DESCRIPTION "PipeWire components for window thumbnails"
|
||||
EXPORT PlasmaWorkspacePipeWire)
|
||||
ecm_qt_install_logging_categories(
|
||||
EXPORT PlasmaWorkspacePipeWire
|
||||
FILE myproject.categories
|
||||
DESTINATION "./"
|
||||
)
|
||||
|
||||
#generate wayland protocol files
|
||||
set(PLASMA_WAYLAND_PROTOCOLS_DIR /usr/share/plasma-wayland-protocols)
|
||||
ecm_add_qtwayland_client_protocol(SRCS
|
||||
PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/screencast.xml
|
||||
BASENAME zkde-screencast-unstable-v1
|
||||
)
|
||||
|
||||
target_sources(${PROJECT_NAME} PUBLIC pipewirecore.cpp pipewiresourceitem.cpp pipewiresourcestream.cpp
|
||||
screencasting.cpp screencastingrequest.cpp ${SRCS})
|
||||
|
||||
set(PLUGIN_IMPORT_URI "org.ukui.panel.taskmanager")
|
||||
set(PLUGIN_INSTALL_PATH "/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/qt5/qml/org/ukui/panel/taskmanager")
|
||||
set(taskmanager_LIB_DIR /usr/share/ukui/ukui-panel/libtaskmanager)
|
||||
install(FILES qmldir DESTINATION ${PLUGIN_INSTALL_PATH})
|
||||
install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${PLUGIN_INSTALL_PATH})
|
||||
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
#include "pipewirecore.h"
|
||||
#include "logging.h"
|
||||
#include <KLocalizedString>
|
||||
#include <QSocketNotifier>
|
||||
#include <spa/utils/result.h>
|
||||
|
||||
PipeWireCore::PipeWireCore()
|
||||
{
|
||||
pw_init(nullptr, nullptr);
|
||||
pwCoreEvents.version = PW_VERSION_CORE_EVENTS;
|
||||
pwCoreEvents.error = &PipeWireCore::onCoreError;
|
||||
}
|
||||
|
||||
void PipeWireCore::onCoreError(void *data, uint32_t id, int seq, int res, const char *message)
|
||||
{
|
||||
Q_UNUSED(seq)
|
||||
|
||||
qCWarning(PIPEWIRE_LOGGING) << "PipeWire remote error: " << message;
|
||||
if (id == PW_ID_CORE && res == -EPIPE) {
|
||||
PipeWireCore *pw = static_cast<PipeWireCore *>(data);
|
||||
Q_EMIT pw->pipewireFailed(QString::fromUtf8(message));
|
||||
}
|
||||
}
|
||||
|
||||
PipeWireCore::~PipeWireCore()
|
||||
{
|
||||
if (pwMainLoop) {
|
||||
pw_loop_leave(pwMainLoop);
|
||||
}
|
||||
|
||||
if (pwCore) {
|
||||
pw_core_disconnect(pwCore);
|
||||
}
|
||||
|
||||
if (pwContext) {
|
||||
pw_context_destroy(pwContext);
|
||||
}
|
||||
|
||||
if (pwMainLoop) {
|
||||
pw_loop_destroy(pwMainLoop);
|
||||
}
|
||||
}
|
||||
|
||||
bool PipeWireCore::init()
|
||||
{
|
||||
pwMainLoop = pw_loop_new(nullptr);
|
||||
pw_loop_enter(pwMainLoop);
|
||||
|
||||
QSocketNotifier *notifier = new QSocketNotifier(pw_loop_get_fd(pwMainLoop), QSocketNotifier::Read, this);
|
||||
connect(notifier, &QSocketNotifier::activated, this, [this] {
|
||||
int result = pw_loop_iterate(pwMainLoop, 0);
|
||||
if (result < 0)
|
||||
qCWarning(PIPEWIRE_LOGGING) << "pipewire_loop_iterate failed: " << spa_strerror(result);
|
||||
});
|
||||
|
||||
pwContext = pw_context_new(pwMainLoop, nullptr, 0);
|
||||
if (!pwContext) {
|
||||
qCWarning(PIPEWIRE_LOGGING) << "Failed to create PipeWire context";
|
||||
m_error = i18n("Failed to create PipeWire context");
|
||||
return false;
|
||||
}
|
||||
|
||||
pwCore = pw_context_connect(pwContext, nullptr, 0);
|
||||
if (!pwCore) {
|
||||
qCWarning(PIPEWIRE_LOGGING) << "Failed to connect PipeWire context";
|
||||
m_error = i18n("Failed to connect PipeWire context");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pw_loop_iterate(pwMainLoop, 0) < 0) {
|
||||
qCWarning(PIPEWIRE_LOGGING) << "Failed to start main PipeWire loop";
|
||||
m_error = i18n("Failed to start main PipeWire loop");
|
||||
return false;
|
||||
}
|
||||
|
||||
pw_core_add_listener(pwCore, &coreListener, &pwCoreEvents, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
QSharedPointer<PipeWireCore> PipeWireCore::self()
|
||||
{
|
||||
static QWeakPointer<PipeWireCore> global;
|
||||
QSharedPointer<PipeWireCore> ret;
|
||||
if (global) {
|
||||
ret = global.toStrongRef();
|
||||
} else {
|
||||
ret.reset(new PipeWireCore);
|
||||
if (ret->init()) {
|
||||
global = ret;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
#ifndef PIPEWIRECORE_H
|
||||
#define PIPEWIRECORE_H
|
||||
|
||||
|
||||
#include <QObject>
|
||||
#include <pipewire/pipewire.h>
|
||||
|
||||
class PipeWireCore : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PipeWireCore();
|
||||
|
||||
static void onCoreError(void *data, uint32_t id, int seq, int res, const char *message);
|
||||
|
||||
~PipeWireCore();
|
||||
|
||||
bool init();
|
||||
|
||||
static QSharedPointer<PipeWireCore> self();
|
||||
|
||||
struct pw_core *pwCore = nullptr;
|
||||
struct pw_context *pwContext = nullptr;
|
||||
struct pw_loop *pwMainLoop = nullptr;
|
||||
spa_hook coreListener;
|
||||
QString m_error;
|
||||
|
||||
pw_core_events pwCoreEvents = {};
|
||||
|
||||
Q_SIGNALS:
|
||||
void pipewireFailed(const QString &message);
|
||||
};
|
||||
|
||||
#endif // PIPEWIRECORE_H
|
|
@ -1,284 +0,0 @@
|
|||
#include "pipewiresourceitem.h"
|
||||
#include "pipewiresourcestream.h"
|
||||
#include <QGuiApplication>
|
||||
#include <QOpenGLContext>
|
||||
#include <QOpenGLTexture>
|
||||
#include <QQuickWindow>
|
||||
#include <QRunnable>
|
||||
#include <QSGImageNode>
|
||||
#include <QSocketNotifier>
|
||||
#include <QThread>
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#include <libdrm/drm_fourcc.h>
|
||||
|
||||
#include <QtPlatformHeaders/QEGLNativeContext>
|
||||
|
||||
static void pwInit()
|
||||
{
|
||||
pw_init(nullptr, nullptr);
|
||||
}
|
||||
Q_COREAPP_STARTUP_FUNCTION(pwInit);
|
||||
|
||||
class DiscardEglPixmapRunnable : public QRunnable
|
||||
{
|
||||
public:
|
||||
DiscardEglPixmapRunnable(EGLImageKHR image, QOpenGLTexture *texture)
|
||||
: m_image(image)
|
||||
, m_texture(texture)
|
||||
{
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
if (m_image != EGL_NO_IMAGE_KHR) {
|
||||
static auto eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress("eglDestroyImageKHR");
|
||||
eglDestroyImageKHR(eglGetCurrentDisplay(), m_image);
|
||||
}
|
||||
|
||||
delete m_texture;
|
||||
}
|
||||
|
||||
private:
|
||||
const EGLImageKHR m_image;
|
||||
QOpenGLTexture *m_texture;
|
||||
};
|
||||
|
||||
PipeWireSourceItem::PipeWireSourceItem(QQuickItem *parent)
|
||||
: QQuickItem(parent)
|
||||
{
|
||||
setFlag(ItemHasContents, true);
|
||||
|
||||
connect(this, &QQuickItem::visibleChanged, this, [this]() {
|
||||
if (m_stream)
|
||||
m_stream->setActive(isVisible());
|
||||
});
|
||||
}
|
||||
|
||||
PipeWireSourceItem::~PipeWireSourceItem()
|
||||
{
|
||||
}
|
||||
|
||||
void PipeWireSourceItem::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
|
||||
{
|
||||
switch (change) {
|
||||
case ItemVisibleHasChanged:
|
||||
if (m_stream)
|
||||
m_stream->setActive(isVisible() && data.boolValue && isComponentComplete());
|
||||
break;
|
||||
case ItemSceneChange:
|
||||
m_needsRecreateTexture = true;
|
||||
releaseResources();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PipeWireSourceItem::releaseResources()
|
||||
{
|
||||
if (window()) {
|
||||
window()->scheduleRenderJob(new DiscardEglPixmapRunnable(m_image, m_texture.take()), QQuickWindow::NoStage);
|
||||
m_image = EGL_NO_IMAGE_KHR;
|
||||
}
|
||||
}
|
||||
|
||||
void PipeWireSourceItem::setNodeId(uint nodeId)
|
||||
{
|
||||
if (nodeId == m_nodeId)
|
||||
return;
|
||||
|
||||
m_nodeId = nodeId;
|
||||
|
||||
if (m_nodeId == 0) {
|
||||
m_stream.reset(nullptr);
|
||||
m_createNextTexture = [] {
|
||||
return nullptr;
|
||||
};
|
||||
} else {
|
||||
m_stream.reset(new PipeWireSourceStream(this));
|
||||
m_stream->createStream(m_nodeId);
|
||||
if (!m_stream->error().isEmpty()) {
|
||||
m_stream.reset(nullptr);
|
||||
m_nodeId = 0;
|
||||
return;
|
||||
}
|
||||
m_stream->setActive(isVisible() && isComponentComplete());
|
||||
|
||||
connect(m_stream.data(), &PipeWireSourceStream::dmabufTextureReceived, this, &PipeWireSourceItem::updateTextureDmaBuf);
|
||||
connect(m_stream.data(), &PipeWireSourceStream::imageTextureReceived, this, &PipeWireSourceItem::updateTextureImage);
|
||||
}
|
||||
|
||||
Q_EMIT nodeIdChanged(nodeId);
|
||||
}
|
||||
|
||||
QSGNode *PipeWireSourceItem::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *)
|
||||
{
|
||||
if (Q_UNLIKELY(!m_createNextTexture)) {
|
||||
return node;
|
||||
}
|
||||
|
||||
auto texture = m_createNextTexture();
|
||||
if (!texture) {
|
||||
delete node;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (m_needsRecreateTexture) {
|
||||
delete node;
|
||||
node = nullptr;
|
||||
m_needsRecreateTexture = false;
|
||||
}
|
||||
|
||||
QSGImageNode *textureNode = static_cast<QSGImageNode *>(node);
|
||||
if (!textureNode) {
|
||||
textureNode = window()->createImageNode();
|
||||
textureNode->setOwnsTexture(true);
|
||||
}
|
||||
textureNode->setTexture(texture);
|
||||
|
||||
const auto br = boundingRect().toRect();
|
||||
QRect rect({0, 0}, texture->textureSize().scaled(br.size(), Qt::KeepAspectRatio));
|
||||
rect.moveCenter(br.center());
|
||||
textureNode->setRect(rect);
|
||||
|
||||
return textureNode;
|
||||
}
|
||||
|
||||
QString PipeWireSourceItem::error() const
|
||||
{
|
||||
return m_stream->error();
|
||||
}
|
||||
|
||||
static EGLImage createImage(EGLDisplay display, const QVector<DmaBufPlane> &planes, uint32_t format, const QSize &size)
|
||||
{
|
||||
const bool hasModifiers = planes[0].modifier != DRM_FORMAT_MOD_INVALID;
|
||||
|
||||
QVector<EGLint> attribs;
|
||||
attribs << EGL_WIDTH << size.width() << EGL_HEIGHT << size.height() << EGL_LINUX_DRM_FOURCC_EXT << EGLint(format)
|
||||
|
||||
<< EGL_DMA_BUF_PLANE0_FD_EXT << planes[0].fd << EGL_DMA_BUF_PLANE0_OFFSET_EXT << EGLint(planes[0].offset) << EGL_DMA_BUF_PLANE0_PITCH_EXT
|
||||
<< EGLint(planes[0].stride);
|
||||
|
||||
if (hasModifiers) {
|
||||
attribs << EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT << EGLint(planes[0].modifier & 0xffffffff) << EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT
|
||||
<< EGLint(planes[0].modifier >> 32);
|
||||
}
|
||||
|
||||
if (planes.count() > 1) {
|
||||
attribs << EGL_DMA_BUF_PLANE1_FD_EXT << planes[1].fd << EGL_DMA_BUF_PLANE1_OFFSET_EXT << EGLint(planes[1].offset) << EGL_DMA_BUF_PLANE1_PITCH_EXT
|
||||
<< EGLint(planes[1].stride);
|
||||
|
||||
if (hasModifiers) {
|
||||
attribs << EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT << EGLint(planes[1].modifier & 0xffffffff) << EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT
|
||||
<< EGLint(planes[1].modifier >> 32);
|
||||
}
|
||||
}
|
||||
|
||||
if (planes.count() > 2) {
|
||||
attribs << EGL_DMA_BUF_PLANE2_FD_EXT << planes[2].fd << EGL_DMA_BUF_PLANE2_OFFSET_EXT << EGLint(planes[2].offset) << EGL_DMA_BUF_PLANE2_PITCH_EXT
|
||||
<< EGLint(planes[2].stride);
|
||||
|
||||
if (hasModifiers) {
|
||||
attribs << EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT << EGLint(planes[2].modifier & 0xffffffff) << EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT
|
||||
<< EGLint(planes[2].modifier >> 32);
|
||||
}
|
||||
}
|
||||
|
||||
if (planes.count() > 3) {
|
||||
attribs << EGL_DMA_BUF_PLANE3_FD_EXT << planes[3].fd << EGL_DMA_BUF_PLANE3_OFFSET_EXT << EGLint(planes[3].offset) << EGL_DMA_BUF_PLANE3_PITCH_EXT
|
||||
<< EGLint(planes[3].stride);
|
||||
|
||||
if (hasModifiers) {
|
||||
attribs << EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT << EGLint(planes[3].modifier & 0xffffffff) << EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT
|
||||
<< EGLint(planes[3].modifier >> 32);
|
||||
}
|
||||
}
|
||||
|
||||
attribs << EGL_NONE;
|
||||
|
||||
static auto eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress("eglCreateImageKHR");
|
||||
Q_ASSERT(eglCreateImageKHR);
|
||||
|
||||
EGLImage ret = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, (EGLClientBuffer) nullptr, attribs.data());
|
||||
if (ret == EGL_NO_IMAGE_KHR) {
|
||||
qWarning() << "invalid image" << glGetError();
|
||||
}
|
||||
// Q_ASSERT(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PipeWireSourceItem::updateTextureDmaBuf(const QVector<DmaBufPlane> &planes, uint32_t format)
|
||||
{
|
||||
static auto s_glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES");
|
||||
if (!s_glEGLImageTargetTexture2DOES) {
|
||||
qWarning() << "glEGLImageTargetTexture2DOES is not available" << window();
|
||||
return;
|
||||
}
|
||||
if (!window() || !window()->openglContext() || !m_stream) {
|
||||
qWarning() << "need a window and a context" << window();
|
||||
return;
|
||||
}
|
||||
|
||||
const EGLDisplay display = static_cast<EGLDisplay>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("egldisplay"));
|
||||
if (m_image) {
|
||||
static auto eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress("eglDestroyImageKHR");
|
||||
eglDestroyImageKHR(display, m_image);
|
||||
}
|
||||
|
||||
const auto size = m_stream->size();
|
||||
m_image = createImage(display, planes, format, size);
|
||||
if (m_image == EGL_NO_IMAGE_KHR) {
|
||||
QImage img(200, 200, QImage::Format_ARGB32_Premultiplied);
|
||||
img.fill(Qt::blue);
|
||||
updateTextureImage(img);
|
||||
return;
|
||||
}
|
||||
|
||||
m_createNextTexture = [this, size, format] {
|
||||
if (!m_texture) {
|
||||
m_texture.reset(new QOpenGLTexture(QOpenGLTexture::Target2D));
|
||||
bool created = m_texture->create();
|
||||
Q_ASSERT(created);
|
||||
}
|
||||
|
||||
m_texture->bind();
|
||||
|
||||
s_glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)m_image);
|
||||
|
||||
m_texture->setWrapMode(QOpenGLTexture::ClampToEdge);
|
||||
m_texture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear);
|
||||
m_texture->release();
|
||||
m_texture->setSize(size.width(), size.height());
|
||||
|
||||
int textureId = m_texture->textureId();
|
||||
QQuickWindow::CreateTextureOption textureOption = format == DRM_FORMAT_ARGB8888 ? QQuickWindow::TextureHasAlphaChannel : QQuickWindow::TextureIsOpaque;
|
||||
return window()->createTextureFromNativeObject(QQuickWindow::NativeObjectTexture, &textureId, 0 /*a vulkan thing?*/, size, textureOption);
|
||||
};
|
||||
if (window()->isVisible()) {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void PipeWireSourceItem::updateTextureImage(const QImage &image)
|
||||
{
|
||||
if (!window()) {
|
||||
qWarning() << "pass";
|
||||
return;
|
||||
}
|
||||
|
||||
m_createNextTexture = [this, image] {
|
||||
return window()->createTextureFromImage(image, QQuickWindow::TextureIsOpaque);
|
||||
};
|
||||
if (window()->isVisible())
|
||||
update();
|
||||
}
|
||||
|
||||
void PipeWireSourceItem::componentComplete()
|
||||
{
|
||||
if (m_stream)
|
||||
m_stream->setActive(isVisible());
|
||||
QQuickItem::componentComplete();
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
#ifndef PIPEWIRESOURCEITEM_H
|
||||
#define PIPEWIRESOURCEITEM_H
|
||||
|
||||
#include <QQuickItem>
|
||||
#include <functional>
|
||||
|
||||
#include <pipewire/pipewire.h>
|
||||
#include <spa/param/format-utils.h>
|
||||
#include <spa/param/props.h>
|
||||
#include <spa/param/video/format-utils.h>
|
||||
|
||||
struct DmaBufPlane;
|
||||
class PipeWireSourceStream;
|
||||
class QSGTexture;
|
||||
class QOpenGLTexture;
|
||||
typedef void *EGLImage;
|
||||
|
||||
class PipeWireSourceItem : public QQuickItem
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(uint nodeId READ nodeId WRITE setNodeId NOTIFY nodeIdChanged)
|
||||
|
||||
public:
|
||||
PipeWireSourceItem(QQuickItem *parent = nullptr);
|
||||
~PipeWireSourceItem() override;
|
||||
|
||||
QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *data) override;
|
||||
Q_SCRIPTABLE QString error() const;
|
||||
|
||||
void setNodeId(uint nodeId);
|
||||
uint nodeId() const
|
||||
{
|
||||
return m_nodeId;
|
||||
}
|
||||
|
||||
void componentComplete() override;
|
||||
void releaseResources() override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void nodeIdChanged(uint nodeId);
|
||||
|
||||
private:
|
||||
void itemChange(ItemChange change, const ItemChangeData &data) override;
|
||||
void updateTextureDmaBuf(const QVector<DmaBufPlane> &plane, uint32_t format);
|
||||
void updateTextureImage(const QImage &image);
|
||||
|
||||
uint m_nodeId = 0;
|
||||
std::function<QSGTexture *()> m_createNextTexture;
|
||||
QScopedPointer<PipeWireSourceStream> m_stream;
|
||||
QScopedPointer<QOpenGLTexture> m_texture;
|
||||
|
||||
EGLImage m_image = nullptr;
|
||||
bool m_needsRecreateTexture = false;
|
||||
};
|
||||
|
||||
#endif // PIPEWIRESOURCEITEM_H
|
|
@ -1,364 +0,0 @@
|
|||
#include "pipewiresourcestream.h"
|
||||
|
||||
#include "logging.h"
|
||||
#include "pipewirecore.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <libdrm/drm_fourcc.h>
|
||||
#include <spa/utils/result.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QLoggingCategory>
|
||||
#include <QOpenGLTexture>
|
||||
#include <QSocketNotifier>
|
||||
#include <QVersionNumber>
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
#include <QtPlatformHeaders/QEGLNativeContext>
|
||||
#undef Status
|
||||
|
||||
#if !PW_CHECK_VERSION(0, 3, 29)
|
||||
#define SPA_POD_PROP_FLAG_MANDATORY (1u << 3)
|
||||
#endif
|
||||
#if !PW_CHECK_VERSION(0, 3, 33)
|
||||
#define SPA_POD_PROP_FLAG_DONT_FIXATE (1u << 4)
|
||||
#endif
|
||||
|
||||
static uint32_t SpaPixelFormatToDrmFormat(uint32_t spa_format)
|
||||
{
|
||||
switch (spa_format) {
|
||||
case SPA_VIDEO_FORMAT_RGBA:
|
||||
return DRM_FORMAT_ABGR8888;
|
||||
case SPA_VIDEO_FORMAT_RGBx:
|
||||
return DRM_FORMAT_XBGR8888;
|
||||
case SPA_VIDEO_FORMAT_BGRA:
|
||||
return DRM_FORMAT_ARGB8888;
|
||||
case SPA_VIDEO_FORMAT_BGRx:
|
||||
return DRM_FORMAT_XRGB8888;
|
||||
default:
|
||||
return DRM_FORMAT_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<uint64_t> queryDmaBufModifiers(EGLDisplay display, uint32_t format)
|
||||
{
|
||||
static auto eglQueryDmaBufModifiersEXT = (PFNEGLQUERYDMABUFMODIFIERSEXTPROC)eglGetProcAddress("eglQueryDmaBufModifiersEXT");
|
||||
static auto eglQueryDmaBufFormatsEXT = (PFNEGLQUERYDMABUFFORMATSEXTPROC)eglGetProcAddress("eglQueryDmaBufFormatsEXT");
|
||||
if (!eglQueryDmaBufFormatsEXT || !eglQueryDmaBufModifiersEXT) {
|
||||
return {};
|
||||
}
|
||||
|
||||
uint32_t drm_format = SpaPixelFormatToDrmFormat(format);
|
||||
if (drm_format == DRM_FORMAT_INVALID) {
|
||||
qCDebug(PIPEWIRE_LOGGING) << "Failed to find matching DRM format." << format;
|
||||
return {};
|
||||
}
|
||||
|
||||
EGLint count = 0;
|
||||
EGLBoolean success = eglQueryDmaBufFormatsEXT(display, 0, nullptr, &count);
|
||||
|
||||
if (!success || count == 0) {
|
||||
qCWarning(PIPEWIRE_LOGGING) << "Failed to query DMA-BUF format count.";
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint32_t> formats(count);
|
||||
if (!eglQueryDmaBufFormatsEXT(display, count, reinterpret_cast<EGLint *>(formats.data()), &count)) {
|
||||
if (!success)
|
||||
qCWarning(PIPEWIRE_LOGGING) << "Failed to query DMA-BUF formats.";
|
||||
return {};
|
||||
}
|
||||
|
||||
if (std::find(formats.begin(), formats.end(), drm_format) == formats.end()) {
|
||||
qCDebug(PIPEWIRE_LOGGING) << "Format " << drm_format << " not supported for modifiers.";
|
||||
return {DRM_FORMAT_MOD_INVALID};
|
||||
}
|
||||
|
||||
success = eglQueryDmaBufModifiersEXT(display, drm_format, 0, nullptr, nullptr, &count);
|
||||
if (!success) {
|
||||
qCWarning(PIPEWIRE_LOGGING) << "Failed to query DMA-BUF modifier count.";
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint64_t> modifiers(count);
|
||||
if (count > 0) {
|
||||
if (!eglQueryDmaBufModifiersEXT(display, drm_format, count, modifiers.data(), nullptr, &count)) {
|
||||
qCWarning(PIPEWIRE_LOGGING) << "Failed to query DMA-BUF modifiers.";
|
||||
}
|
||||
}
|
||||
|
||||
// Support modifier-less buffers
|
||||
modifiers.push_back(DRM_FORMAT_MOD_INVALID);
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
void PipeWireSourceStream::onStreamStateChanged(void *data, pw_stream_state old, pw_stream_state state, const char *error_message)
|
||||
{
|
||||
PipeWireSourceStream *pw = static_cast<PipeWireSourceStream *>(data);
|
||||
qCDebug(PIPEWIRE_LOGGING) << "state changed" << pw_stream_state_as_string(old) << "->" << pw_stream_state_as_string(state) << error_message;
|
||||
|
||||
switch (state) {
|
||||
case PW_STREAM_STATE_ERROR:
|
||||
qCWarning(PIPEWIRE_LOGGING) << "Stream error: " << error_message;
|
||||
break;
|
||||
case PW_STREAM_STATE_PAUSED:
|
||||
Q_EMIT pw->streamReady();
|
||||
break;
|
||||
case PW_STREAM_STATE_STREAMING:
|
||||
Q_EMIT pw->startStreaming();
|
||||
break;
|
||||
case PW_STREAM_STATE_CONNECTING:
|
||||
break;
|
||||
case PW_STREAM_STATE_UNCONNECTED:
|
||||
if (!pw->m_stopped) {
|
||||
Q_EMIT pw->stopStreaming();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static spa_pod *buildFormat(spa_pod_builder *builder, spa_video_format format, const std::vector<uint64_t> &modifiers = {})
|
||||
{
|
||||
spa_pod_frame f[2];
|
||||
const spa_rectangle pw_min_screen_bounds{1, 1};
|
||||
const spa_rectangle pw_max_screen_bounds{UINT32_MAX, UINT32_MAX};
|
||||
|
||||
spa_pod_builder_push_object(builder, &f[0], SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
|
||||
spa_pod_builder_add(builder, SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), 0);
|
||||
spa_pod_builder_add(builder, SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), 0);
|
||||
spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_format, SPA_POD_Id(format), 0);
|
||||
|
||||
if (modifiers.size()) {
|
||||
auto pw_version = QVersionNumber::fromString(pw_get_library_version());
|
||||
|
||||
// SPA_POD_PROP_FLAG_DONT_FIXATE can be used with PipeWire >= 0.3.33
|
||||
if (pw_version >= QVersionNumber(0, 3, 33)) {
|
||||
spa_pod_builder_prop(builder, SPA_FORMAT_VIDEO_modifier, SPA_POD_PROP_FLAG_MANDATORY | SPA_POD_PROP_FLAG_DONT_FIXATE);
|
||||
} else {
|
||||
spa_pod_builder_prop(builder, SPA_FORMAT_VIDEO_modifier, SPA_POD_PROP_FLAG_MANDATORY);
|
||||
}
|
||||
spa_pod_builder_push_choice(builder, &f[1], SPA_CHOICE_Enum, 0);
|
||||
// mofifiers from the array
|
||||
for (auto it = modifiers.begin(); it != modifiers.end(); it++) {
|
||||
spa_pod_builder_long(builder, *it);
|
||||
if (it == modifiers.begin()) {
|
||||
spa_pod_builder_long(builder, *it);
|
||||
}
|
||||
}
|
||||
spa_pod_builder_pop(builder, &f[1]);
|
||||
}
|
||||
|
||||
spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_size, SPA_POD_CHOICE_RANGE_Rectangle(&pw_min_screen_bounds, &pw_min_screen_bounds, &pw_max_screen_bounds), 0);
|
||||
|
||||
return static_cast<spa_pod *>(spa_pod_builder_pop(builder, &f[0]));
|
||||
}
|
||||
|
||||
void PipeWireSourceStream::onStreamParamChanged(void *data, uint32_t id, const struct spa_pod *format)
|
||||
{
|
||||
if (!format || id != SPA_PARAM_Format) {
|
||||
return;
|
||||
}
|
||||
|
||||
PipeWireSourceStream *pw = static_cast<PipeWireSourceStream *>(data);
|
||||
spa_format_video_raw_parse(format, &pw->videoFormat);
|
||||
|
||||
const int32_t width = pw->videoFormat.size.width;
|
||||
const int32_t height = pw->videoFormat.size.height;
|
||||
const int bpp = pw->videoFormat.format == SPA_VIDEO_FORMAT_RGB || pw->videoFormat.format == SPA_VIDEO_FORMAT_BGR ? 3 : 4;
|
||||
const quint32 stride = SPA_ROUND_UP_N(width * bpp, 4);
|
||||
qCDebug(PIPEWIRE_LOGGING) << "Stream format changed";
|
||||
const int32_t size = height * stride;
|
||||
|
||||
uint8_t paramsBuffer[1024];
|
||||
spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(paramsBuffer, sizeof(paramsBuffer));
|
||||
|
||||
const auto bufferTypes = pw->m_allowDmaBuf && spa_pod_find_prop(format, nullptr, SPA_FORMAT_VIDEO_modifier)
|
||||
? (1 << SPA_DATA_DmaBuf) | (1 << SPA_DATA_MemFd) | (1 << SPA_DATA_MemPtr)
|
||||
: (1 << SPA_DATA_MemFd) | (1 << SPA_DATA_MemPtr);
|
||||
|
||||
const spa_pod *param = (spa_pod *)spa_pod_builder_add_object(&pod_builder,
|
||||
SPA_TYPE_OBJECT_ParamBuffers,
|
||||
SPA_PARAM_Buffers,
|
||||
SPA_PARAM_BUFFERS_buffers,
|
||||
SPA_POD_CHOICE_RANGE_Int(16, 2, 16),
|
||||
SPA_PARAM_BUFFERS_blocks,
|
||||
SPA_POD_Int(1),
|
||||
SPA_PARAM_BUFFERS_size,
|
||||
SPA_POD_Int(size),
|
||||
SPA_PARAM_BUFFERS_stride,
|
||||
SPA_POD_CHOICE_RANGE_Int(stride, stride, INT32_MAX),
|
||||
SPA_PARAM_BUFFERS_align,
|
||||
SPA_POD_Int(16),
|
||||
SPA_PARAM_BUFFERS_dataType,
|
||||
SPA_POD_CHOICE_FLAGS_Int(bufferTypes));
|
||||
pw_stream_update_params(pw->pwStream, ¶m, 1);
|
||||
}
|
||||
|
||||
static void onProcess(void *data)
|
||||
{
|
||||
PipeWireSourceStream *stream = static_cast<PipeWireSourceStream *>(data);
|
||||
stream->process();
|
||||
}
|
||||
|
||||
PipeWireSourceStream::PipeWireSourceStream(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
pwStreamEvents.version = PW_VERSION_STREAM_EVENTS;
|
||||
pwStreamEvents.process = &onProcess;
|
||||
pwStreamEvents.state_changed = &PipeWireSourceStream::onStreamStateChanged;
|
||||
pwStreamEvents.param_changed = &PipeWireSourceStream::onStreamParamChanged;
|
||||
}
|
||||
|
||||
PipeWireSourceStream::~PipeWireSourceStream()
|
||||
{
|
||||
m_stopped = true;
|
||||
if (pwStream) {
|
||||
pw_stream_destroy(pwStream);
|
||||
}
|
||||
}
|
||||
|
||||
uint PipeWireSourceStream::framerate()
|
||||
{
|
||||
if (pwStream) {
|
||||
return videoFormat.max_framerate.num / videoFormat.max_framerate.denom;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint PipeWireSourceStream::nodeId()
|
||||
{
|
||||
return pwNodeId;
|
||||
}
|
||||
|
||||
bool PipeWireSourceStream::createStream(uint nodeid)
|
||||
{
|
||||
pwCore = PipeWireCore::self();
|
||||
if (!pwCore->m_error.isEmpty()) {
|
||||
m_error = pwCore->m_error;
|
||||
return false;
|
||||
}
|
||||
|
||||
connect(pwCore.data(), &PipeWireCore::pipewireFailed, this, &PipeWireSourceStream::coreFailed);
|
||||
|
||||
pwStream = pw_stream_new(pwCore->pwCore, "plasma-screencast", nullptr);
|
||||
pwNodeId = nodeid;
|
||||
pw_stream_add_listener(pwStream, &streamListener, &pwStreamEvents, this);
|
||||
|
||||
uint8_t buffer[4096];
|
||||
spa_pod_builder podBuilder = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
|
||||
|
||||
const QVector<spa_video_format> formats =
|
||||
{SPA_VIDEO_FORMAT_RGBx, SPA_VIDEO_FORMAT_RGBA, SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_BGRA, SPA_VIDEO_FORMAT_RGB, SPA_VIDEO_FORMAT_BGR};
|
||||
QVector<const spa_pod *> params;
|
||||
params.reserve(formats.size() * 2);
|
||||
const EGLDisplay display = static_cast<EGLDisplay>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("egldisplay"));
|
||||
for (spa_video_format format : formats) {
|
||||
if (m_allowDmaBuf) {
|
||||
if (auto modifiers = queryDmaBufModifiers(display, format); modifiers.size() > 0) {
|
||||
params += buildFormat(&podBuilder, format, modifiers);
|
||||
}
|
||||
}
|
||||
|
||||
params += buildFormat(&podBuilder, format, {});
|
||||
}
|
||||
|
||||
pw_stream_flags s = (pw_stream_flags)(PW_STREAM_FLAG_DONT_RECONNECT | PW_STREAM_FLAG_AUTOCONNECT);
|
||||
if (pw_stream_connect(pwStream, PW_DIRECTION_INPUT, pwNodeId, s, params.data(), params.size()) != 0) {
|
||||
qCWarning(PIPEWIRE_LOGGING) << "Could not connect to stream";
|
||||
pw_stream_destroy(pwStream);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PipeWireSourceStream::handleFrame(struct pw_buffer *buffer)
|
||||
{
|
||||
spa_buffer *spaBuffer = buffer->buffer;
|
||||
|
||||
if (spaBuffer->datas->chunk->size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (spaBuffer->datas->type == SPA_DATA_MemFd) {
|
||||
uint8_t *map =
|
||||
static_cast<uint8_t *>(mmap(nullptr, spaBuffer->datas->maxsize + spaBuffer->datas->mapoffset, PROT_READ, MAP_PRIVATE, spaBuffer->datas->fd, 0));
|
||||
|
||||
if (map == MAP_FAILED) {
|
||||
qCWarning(PIPEWIRE_LOGGING) << "Failed to mmap the memory: " << strerror(errno);
|
||||
return;
|
||||
}
|
||||
const QImage::Format format = spaBuffer->datas->chunk->stride / videoFormat.size.width == 3 ? QImage::Format_RGB888 : QImage::Format_ARGB32;
|
||||
|
||||
QImage img(map, videoFormat.size.width, videoFormat.size.height, spaBuffer->datas->chunk->stride, format);
|
||||
Q_EMIT imageTextureReceived(img.copy());
|
||||
|
||||
munmap(map, spaBuffer->datas->maxsize + spaBuffer->datas->mapoffset);
|
||||
} else if (spaBuffer->datas->type == SPA_DATA_DmaBuf) {
|
||||
QVector<DmaBufPlane> planes;
|
||||
planes.reserve(spaBuffer->n_datas);
|
||||
for (uint i = 0; i < spaBuffer->n_datas; ++i) {
|
||||
const auto &data = spaBuffer->datas[i];
|
||||
|
||||
DmaBufPlane plane;
|
||||
plane.fd = data.fd;
|
||||
plane.stride = data.chunk->stride;
|
||||
plane.offset = data.chunk->offset;
|
||||
plane.modifier = DRM_FORMAT_MOD_INVALID;
|
||||
planes += plane;
|
||||
}
|
||||
Q_EMIT dmabufTextureReceived(planes, DRM_FORMAT_ARGB8888);
|
||||
} else if (spaBuffer->datas->type == SPA_DATA_MemPtr) {
|
||||
QImage img(static_cast<uint8_t *>(spaBuffer->datas->data),
|
||||
videoFormat.size.width,
|
||||
videoFormat.size.height,
|
||||
spaBuffer->datas->chunk->stride,
|
||||
QImage::Format_ARGB32);
|
||||
Q_EMIT imageTextureReceived(img);
|
||||
} else {
|
||||
qWarning() << "unsupported buffer type" << spaBuffer->datas->type;
|
||||
QImage errorImage(200, 200, QImage::Format_ARGB32_Premultiplied);
|
||||
errorImage.fill(Qt::red);
|
||||
Q_EMIT imageTextureReceived(errorImage);
|
||||
}
|
||||
}
|
||||
|
||||
void PipeWireSourceStream::coreFailed(const QString &errorMessage)
|
||||
{
|
||||
m_error = errorMessage;
|
||||
Q_EMIT stopStreaming();
|
||||
}
|
||||
|
||||
void PipeWireSourceStream::process()
|
||||
{
|
||||
pw_buffer *buf = pw_stream_dequeue_buffer(pwStream);
|
||||
if (!buf) {
|
||||
return;
|
||||
}
|
||||
|
||||
handleFrame(buf);
|
||||
|
||||
pw_stream_queue_buffer(pwStream, buf);
|
||||
}
|
||||
|
||||
void PipeWireSourceStream::stop()
|
||||
{
|
||||
if (!m_stopped)
|
||||
pw_stream_set_active(pwStream, false);
|
||||
m_stopped = true;
|
||||
delete this;
|
||||
}
|
||||
|
||||
void PipeWireSourceStream::setActive(bool active)
|
||||
{
|
||||
Q_ASSERT(pwStream);
|
||||
pw_stream_set_active(pwStream, active);
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
#ifndef PIPEWIRESOURCESTREAM_H
|
||||
#define PIPEWIRESOURCESTREAM_H
|
||||
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
#include <QSize>
|
||||
|
||||
#include <pipewire/pipewire.h>
|
||||
#include <spa/param/format-utils.h>
|
||||
#include <spa/param/props.h>
|
||||
#include <spa/param/video/format-utils.h>
|
||||
|
||||
#undef Status
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
class AbstractEglBackend;
|
||||
class GLTexture;
|
||||
}
|
||||
class PipeWireCore;
|
||||
|
||||
typedef void *EGLDisplay;
|
||||
|
||||
struct DmaBufPlane {
|
||||
int fd; /// The dmabuf file descriptor
|
||||
uint32_t offset; /// The offset from the start of buffer
|
||||
uint32_t stride; /// The distance from the start of a row to the next row in bytes
|
||||
uint64_t modifier = 0; /// The layout modifier
|
||||
};
|
||||
|
||||
class PipeWireSourceStream : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PipeWireSourceStream(QObject *parent);
|
||||
~PipeWireSourceStream();
|
||||
|
||||
static void onStreamParamChanged(void *data, uint32_t id, const struct spa_pod *format);
|
||||
static void onStreamStateChanged(void *data, pw_stream_state old, pw_stream_state state, const char *error_message);
|
||||
|
||||
uint framerate();
|
||||
uint nodeId();
|
||||
QString error() const
|
||||
{
|
||||
return m_error;
|
||||
}
|
||||
|
||||
QSize size() const
|
||||
{
|
||||
return QSize(videoFormat.size.width, videoFormat.size.height);
|
||||
}
|
||||
bool createStream(uint nodeid);
|
||||
void stop();
|
||||
void setActive(bool active);
|
||||
|
||||
void handleFrame(struct pw_buffer *buffer);
|
||||
void process();
|
||||
|
||||
bool setAllowDmaBuf(bool allowed);
|
||||
|
||||
Q_SIGNALS:
|
||||
void streamReady();
|
||||
void startStreaming();
|
||||
void stopStreaming();
|
||||
void dmabufTextureReceived(const QVector<DmaBufPlane> &planes, uint32_t format);
|
||||
void imageTextureReceived(const QImage &image);
|
||||
|
||||
private:
|
||||
void coreFailed(const QString &errorMessage);
|
||||
|
||||
QSharedPointer<PipeWireCore> pwCore;
|
||||
pw_stream *pwStream = nullptr;
|
||||
spa_hook streamListener;
|
||||
pw_stream_events pwStreamEvents = {};
|
||||
|
||||
uint32_t pwNodeId = 0;
|
||||
|
||||
bool m_stopped = false;
|
||||
|
||||
spa_video_info_raw videoFormat;
|
||||
QString m_error;
|
||||
bool m_allowDmaBuf = true;
|
||||
};
|
||||
|
||||
#endif // PIPEWIRESOURCESTREAM_H
|
|
@ -1,2 +0,0 @@
|
|||
module org.ukui.panel.taskmanager
|
||||
plugin taskmanager
|
|
@ -1,109 +0,0 @@
|
|||
#include "screencasting.h"
|
||||
#include "qwayland-zkde-screencast-unstable-v1.h"
|
||||
#include <KWayland/Client/output.h>
|
||||
#include <KWayland/Client/plasmawindowmanagement.h>
|
||||
#include <KWayland/Client/registry.h>
|
||||
#include <QDebug>
|
||||
#include <QRect>
|
||||
|
||||
|
||||
using namespace KWayland::Client;
|
||||
|
||||
class ScreencastingStreamPrivate : public QtWayland::zkde_screencast_stream_unstable_v1
|
||||
{
|
||||
public:
|
||||
ScreencastingStreamPrivate(ScreencastingStream *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
~ScreencastingStreamPrivate()
|
||||
{
|
||||
close();
|
||||
q->deleteLater();
|
||||
}
|
||||
|
||||
void zkde_screencast_stream_unstable_v1_created(uint32_t node) override
|
||||
{
|
||||
m_nodeId = node;
|
||||
Q_EMIT q->created(node);
|
||||
}
|
||||
|
||||
void zkde_screencast_stream_unstable_v1_closed() override
|
||||
{
|
||||
Q_EMIT q->closed();
|
||||
}
|
||||
|
||||
void zkde_screencast_stream_unstable_v1_failed(const QString &error) override
|
||||
{
|
||||
Q_EMIT q->failed(error);
|
||||
}
|
||||
|
||||
uint m_nodeId = 0;
|
||||
QPointer<ScreencastingStream> q;
|
||||
};
|
||||
|
||||
ScreencastingStream::ScreencastingStream(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new ScreencastingStreamPrivate(this))
|
||||
{
|
||||
}
|
||||
|
||||
ScreencastingStream::~ScreencastingStream() = default;
|
||||
|
||||
quint32 ScreencastingStream::nodeId() const
|
||||
{
|
||||
return d->m_nodeId;
|
||||
}
|
||||
|
||||
class ScreencastingPrivate : public QtWayland::zkde_screencast_unstable_v1
|
||||
{
|
||||
public:
|
||||
ScreencastingPrivate(Registry *registry, int id, int version, Screencasting *q)
|
||||
: QtWayland::zkde_screencast_unstable_v1(*registry, id, version)
|
||||
, q(q)
|
||||
{
|
||||
}
|
||||
|
||||
ScreencastingPrivate(::zkde_screencast_unstable_v1 *screencasting, Screencasting *q)
|
||||
: QtWayland::zkde_screencast_unstable_v1(screencasting)
|
||||
, q(q)
|
||||
{
|
||||
}
|
||||
|
||||
~ScreencastingPrivate()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
Screencasting *const q;
|
||||
};
|
||||
|
||||
Screencasting::Screencasting(QObject *parent)
|
||||
:QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
Screencasting::Screencasting(Registry *registry, int id, int version, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new ScreencastingPrivate(registry, id, version, this))
|
||||
{
|
||||
}
|
||||
|
||||
Screencasting::~Screencasting() = default;
|
||||
|
||||
ScreencastingStream *Screencasting::createWindowStream(const QString &uuid, CursorMode mode)
|
||||
{
|
||||
auto stream = new ScreencastingStream(this);
|
||||
stream->d->init(d->stream_window(uuid, mode));
|
||||
return stream;
|
||||
}
|
||||
|
||||
void Screencasting::setup(::zkde_screencast_unstable_v1 *screencasting)
|
||||
{
|
||||
d.reset(new ScreencastingPrivate(screencasting, this));
|
||||
}
|
||||
|
||||
void Screencasting::destroy()
|
||||
{
|
||||
d.reset(nullptr);
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
#ifndef SCREENCASTING_H
|
||||
#define SCREENCASTING_H
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
#include <QVector>
|
||||
#include <optional>
|
||||
|
||||
struct zkde_screencast_unstable_v1;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class PlasmaWindow;
|
||||
class Registry;
|
||||
class Output;
|
||||
}
|
||||
}
|
||||
|
||||
class ScreencastingPrivate;
|
||||
class ScreencastingStreamPrivate;
|
||||
class ScreencastingStream : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ScreencastingStream(QObject *parent);
|
||||
~ScreencastingStream() override;
|
||||
|
||||
quint32 nodeId() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void created(quint32 nodeid);
|
||||
void failed(const QString &error);
|
||||
void closed();
|
||||
|
||||
private:
|
||||
friend class Screencasting;
|
||||
QScopedPointer<ScreencastingStreamPrivate> d;
|
||||
};
|
||||
|
||||
class Screencasting : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Screencasting(QObject *parent = nullptr);
|
||||
explicit Screencasting(KWayland::Client::Registry *registry, int id, int version, QObject *parent = nullptr);
|
||||
~Screencasting() override;
|
||||
|
||||
enum CursorMode {
|
||||
Hidden = 1,
|
||||
Embedded = 2,
|
||||
Metadata = 4,
|
||||
};
|
||||
Q_ENUM(CursorMode);
|
||||
|
||||
|
||||
ScreencastingStream *createWindowStream(const QString &uuid, CursorMode mode);
|
||||
|
||||
void setup(zkde_screencast_unstable_v1 *screencasting);
|
||||
void destroy();
|
||||
|
||||
private:
|
||||
QScopedPointer<ScreencastingPrivate> d;
|
||||
|
||||
};
|
||||
|
||||
#endif // SCREENCASTING_H
|
|
@ -1,128 +0,0 @@
|
|||
#include "screencastingrequest.h"
|
||||
#include <KWayland/Client/connection_thread.h>
|
||||
#include <KWayland/Client/registry.h>
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
#include <QPointer>
|
||||
#include <functional>
|
||||
|
||||
class ScreencastingSingleton : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ScreencastingSingleton(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
KWayland::Client::ConnectionThread *connection = KWayland::Client::ConnectionThread::fromApplication(this);
|
||||
if (!connection) {
|
||||
return;
|
||||
}
|
||||
|
||||
KWayland::Client::Registry *registry = new KWayland::Client::Registry(this);
|
||||
|
||||
connect(registry,
|
||||
&KWayland::Client::Registry::interfaceAnnounced,
|
||||
this,
|
||||
[this, registry](const QByteArray &interfaceName, quint32 name, quint32 version) {
|
||||
if (interfaceName != "zkde_screencast_unstable_v1")
|
||||
return;
|
||||
|
||||
m_screencasting = new Screencasting(registry, name, version, this);
|
||||
Q_EMIT created(m_screencasting);
|
||||
});
|
||||
|
||||
registry->create(connection);
|
||||
registry->setup();
|
||||
}
|
||||
|
||||
static ScreencastingSingleton *self()
|
||||
{
|
||||
static QPointer<ScreencastingSingleton> s_self;
|
||||
if (!s_self && QCoreApplication::instance())
|
||||
s_self = new ScreencastingSingleton(QCoreApplication::instance());
|
||||
return s_self;
|
||||
}
|
||||
|
||||
void requestInterface(ScreencastingRequest *item)
|
||||
{
|
||||
if (!m_screencasting) {
|
||||
connect(this, &ScreencastingSingleton::created, item, &ScreencastingRequest::create, Qt::UniqueConnection);
|
||||
} else {
|
||||
item->create(m_screencasting);
|
||||
}
|
||||
}
|
||||
|
||||
Q_SIGNALS:
|
||||
void created(Screencasting *screencasting);
|
||||
|
||||
private:
|
||||
Screencasting *m_screencasting = nullptr;
|
||||
};
|
||||
|
||||
|
||||
ScreencastingRequest::ScreencastingRequest(QObject *parent)
|
||||
:QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
ScreencastingRequest::~ScreencastingRequest() = default;
|
||||
|
||||
quint32 ScreencastingRequest::nodeId() const
|
||||
{
|
||||
return m_nodeId;
|
||||
}
|
||||
|
||||
void ScreencastingRequest::setNodeid(uint nodeId)
|
||||
{
|
||||
if (nodeId == m_nodeId) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_nodeId = nodeId;
|
||||
Q_EMIT nodeIdChanged(nodeId);
|
||||
}
|
||||
|
||||
QString ScreencastingRequest::uuid() const
|
||||
{
|
||||
return m_uuid;
|
||||
}
|
||||
|
||||
void ScreencastingRequest::setUuid(const QString &uuid)
|
||||
{
|
||||
if (m_uuid == uuid) {
|
||||
return;
|
||||
}
|
||||
|
||||
Q_EMIT closeRunningStreams();
|
||||
setNodeid(0);
|
||||
|
||||
m_uuid = uuid;
|
||||
if (!m_uuid.isEmpty()) {
|
||||
ScreencastingSingleton::self()->requestInterface(this);
|
||||
}
|
||||
|
||||
Q_EMIT uuidChanged(uuid);
|
||||
}
|
||||
|
||||
void ScreencastingRequest::create(Screencasting *screencasting)
|
||||
{
|
||||
auto stream = screencasting->createWindowStream(m_uuid, Screencasting::CursorMode::Hidden);
|
||||
stream->setObjectName(m_uuid);
|
||||
|
||||
connect(stream, &ScreencastingStream::created, this, [stream, this](int nodeId) {
|
||||
if (stream->objectName() == m_uuid) {
|
||||
setNodeid(nodeId);
|
||||
}
|
||||
});
|
||||
connect(stream, &ScreencastingStream::failed, this, [](const QString &error) {
|
||||
qWarning() << "error creating screencast" << error;
|
||||
});
|
||||
connect(stream, &ScreencastingStream::closed, this, [this, stream] {
|
||||
if (stream->nodeId() == m_nodeId) {
|
||||
setNodeid(0);
|
||||
}
|
||||
});
|
||||
connect(this, &ScreencastingRequest::closeRunningStreams, stream, &QObject::deleteLater);
|
||||
}
|
||||
|
||||
#include "screencastingrequest.moc"
|
|
@ -1,39 +0,0 @@
|
|||
#ifndef SCREENCASTINGREQUEST_H
|
||||
#define SCREENCASTINGREQUEST_H
|
||||
|
||||
#include "screencasting.h"
|
||||
#include <QObject>
|
||||
|
||||
class ScreencastingStream;
|
||||
|
||||
class ScreencastingRequest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString uuid READ uuid WRITE setUuid NOTIFY uuidChanged)
|
||||
Q_PROPERTY(quint32 nodeId READ nodeId NOTIFY nodeIdChanged)
|
||||
|
||||
public:
|
||||
ScreencastingRequest(QObject *parent = nullptr);
|
||||
~ScreencastingRequest();
|
||||
|
||||
void setUuid(const QString &uuid);
|
||||
QString uuid() const;
|
||||
quint32 nodeId() const;
|
||||
|
||||
void create(Screencasting *screencasting);
|
||||
Q_SIGNALS:
|
||||
void nodeIdChanged(quint32 nodeId);
|
||||
void uuidChanged(const QString &uuid);
|
||||
void closeRunningStreams();
|
||||
void cursorModeChanged(Screencasting::CursorMode cursorMode);
|
||||
|
||||
private:
|
||||
void setNodeid(uint nodeId);
|
||||
|
||||
ScreencastingStream *m_stream = nullptr;
|
||||
QString m_uuid;
|
||||
KWayland::Client::Output *m_output = nullptr;
|
||||
quint32 m_nodeId = 0;
|
||||
};
|
||||
|
||||
#endif // SCREENCASTINGREQUEST_H
|
|
@ -1,18 +0,0 @@
|
|||
#include "taskmanagerplugin.h"
|
||||
#include "pipewiresourceitem.h"
|
||||
#include "screencasting.h"
|
||||
#include "screencastingrequest.h"
|
||||
|
||||
|
||||
namespace TaskManager
|
||||
{
|
||||
void TaskManagerPlugin::registerTypes(const char *uri)
|
||||
{
|
||||
Q_ASSERT(QLatin1String(uri) == QLatin1String("org.ukui.panel.taskmanager"));
|
||||
|
||||
qmlRegisterType<PipeWireSourceItem>(uri, 0, 1, "PipeWireSourceItem");
|
||||
qmlRegisterType<ScreencastingRequest>(uri, 0, 1, "ScreencastingRequest");
|
||||
qmlRegisterUncreatableType<Screencasting>(uri, 0, 1, "Screencasting", "Use ScreencastingItem");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
#ifndef TASKMANAGERPLUGIN_H
|
||||
#define TASKMANAGERPLUGIN_H
|
||||
|
||||
#include <QQmlEngine>
|
||||
#include <QQmlExtensionPlugin>
|
||||
|
||||
namespace TaskManager
|
||||
{
|
||||
class TaskManagerPlugin : public QQmlExtensionPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
|
||||
|
||||
public:
|
||||
void registerTypes(const char *uri) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // TASKMANAGERPLUGIN_H
|
|
@ -1,3 +1,23 @@
|
|||
/*
|
||||
* Copyright (C) 2022, KylinSoft Co., Ltd.
|
||||
*
|
||||
* 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 3 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Nicole <buxiaoqing@kylinos.cn>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "contextmenu.h"
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
|
|
|
@ -1,3 +1,23 @@
|
|||
/*
|
||||
* Copyright (C) 2022, KylinSoft Co., Ltd.
|
||||
*
|
||||
* 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 3 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Nicole <buxiaoqing@kylinos.cn>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CONTEXTMENU_H
|
||||
#define CONTEXTMENU_H
|
||||
|
||||
|
|
|
@ -1,3 +1,23 @@
|
|||
/*
|
||||
* Copyright (C) 2022, KylinSoft Co., Ltd.
|
||||
*
|
||||
* 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 3 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Nicole <buxiaoqing@kylinos.cn>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "statusnotifierbuttonabstract.h"
|
||||
|
||||
StatusNotifierButtonAbstract::StatusNotifierButtonAbstract(QWidget *parent):
|
||||
|
|
|
@ -1,3 +1,23 @@
|
|||
/*
|
||||
* Copyright (C) 2022, KylinSoft Co., Ltd.
|
||||
*
|
||||
* 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 3 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Nicole <buxiaoqing@kylinos.cn>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STATUSNOTIFIERBUTTONABSTRACT_H
|
||||
#define STATUSNOTIFIERBUTTONABSTRACT_H
|
||||
#include <QToolButton>
|
||||
|
|
|
@ -1,3 +1,23 @@
|
|||
/*
|
||||
* Copyright (C) 2022, KylinSoft Co., Ltd.
|
||||
*
|
||||
* 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 3 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Nicole <buxiaoqing@kylinos.cn>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kbadge.h"
|
||||
#include <QPainter>
|
||||
#include <QRect>
|
||||
|
|
|
@ -1,3 +1,23 @@
|
|||
/*
|
||||
* Copyright (C) 2022, KylinSoft Co., Ltd.
|
||||
*
|
||||
* 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 3 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Nicole <buxiaoqing@kylinos.cn>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef KBADGE_H
|
||||
#define KBADGE_H
|
||||
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
//
|
||||
// Created by hxf on 9/21/23.
|
||||
//
|
||||
#include "signalforwarding.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusError>
|
||||
#include <QApplication>
|
||||
|
||||
#define SERVICE_NAME "org.ukui.panel.signalforwarding"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
QApplication app(argc, argv);
|
||||
SignalForwarding sf(&app);
|
||||
QDBusConnection::sessionBus().registerObject("/", &app);
|
||||
if (!QDBusConnection::sessionBus().registerService(SERVICE_NAME)) {
|
||||
fprintf(stderr, "%s\n",
|
||||
qPrintable(QDBusConnection::sessionBus().lastError().message()));
|
||||
exit(1);
|
||||
}
|
||||
return app.exec();
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
project(SignalListener)
|
||||
|
||||
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core DBus REQUIRED)
|
||||
|
||||
set(SignalListener_SRC SignalListener.cpp)
|
||||
|
||||
add_executable(signallistener ${SignalListener_SRC})
|
||||
|
||||
target_link_libraries(signallistener PRIVATE
|
||||
Qt5::Core
|
||||
Qt5::DBus)
|
|
@ -1,62 +0,0 @@
|
|||
//
|
||||
// Created by hxf on 9/25/23.
|
||||
//
|
||||
|
||||
#include "SignalListener.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDBusError>
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusServiceWatcher>
|
||||
#include <QDebug>
|
||||
#include <QProcess>
|
||||
#include <QDir>
|
||||
|
||||
void SignalListener::printMsg(QDBusVariant winId) {
|
||||
qDebug() << winId.variant();
|
||||
}
|
||||
|
||||
void SignalListener::start(const QVariant &) {
|
||||
iface = new QDBusInterface(SERVICE_NAME, "/", "org.ukui.panel.signalforwarding",
|
||||
QDBusConnection::sessionBus(), this);
|
||||
if (!iface->isValid()) {
|
||||
fprintf(stderr, "%s\n",
|
||||
qPrintable(QDBusConnection::sessionBus().lastError().message()));
|
||||
QCoreApplication::instance()->quit();
|
||||
}
|
||||
|
||||
QMetaObject::Connection con = connect(iface, SIGNAL(titleChanged(QDBusVariant)), this, SLOT(printMsg(QDBusVariant)));
|
||||
connect(iface, SIGNAL(windowAdded(QDBusVariant)), this, SLOT(printMsg(QDBusVariant)));
|
||||
connect(iface, SIGNAL(windowRemoved(QDBusVariant)), this, SLOT(printMsg(QDBusVariant)));
|
||||
|
||||
if (con) {
|
||||
qDebug() << con;
|
||||
} else {
|
||||
qDebug() << "gg";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
|
||||
if (!QDBusConnection::sessionBus().isConnected()) {
|
||||
fprintf(stderr, "Cannot connect to the D-Bus session bus.\n"
|
||||
"To start it, run:\n"
|
||||
"\teval `dbus-launch --auto-syntax`\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
QDBusServiceWatcher serviceWatcher(SERVICE_NAME, QDBusConnection::sessionBus(),
|
||||
QDBusServiceWatcher::WatchForRegistration);
|
||||
|
||||
SignalListener ping;
|
||||
QObject::connect(&serviceWatcher, &QDBusServiceWatcher::serviceRegistered,
|
||||
&ping, &SignalListener::start);
|
||||
|
||||
QProcess signalforwarding;
|
||||
signalforwarding.start("signalforwarding");
|
||||
|
||||
app.exec();
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
//
|
||||
// Created by hxf on 9/25/23.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QDBusInterface>
|
||||
|
||||
#define SERVICE_NAME "org.ukui.panel.signalforwarding"
|
||||
|
||||
class SignalListener : public QObject {
|
||||
Q_OBJECT
|
||||
public slots:
|
||||
void start(const QVariant &);
|
||||
void printMsg(QDBusVariant winId);
|
||||
public:
|
||||
QDBusInterface *iface = nullptr;
|
||||
};
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
//
|
||||
// Created by hxf on 9/21/23.
|
||||
//
|
||||
#include "signalforwarding.h"
|
||||
|
||||
#include <QVariant>
|
||||
#include "windowmanager/windowmanager.h"
|
||||
|
||||
#ifdef EXPAND_MACRO
|
||||
#undef EXPAND_MACRO
|
||||
#endif
|
||||
#define EXPAND_MACRO(signalName) connect(kdk::WindowManager::self(), &kdk::WindowManager::signalName, this, &SignalForwarding::signalName##TypeConvert);
|
||||
|
||||
SignalForwarding::SignalForwarding(QObject *parent) : QDBusAbstractAdaptor(parent) {
|
||||
ARGS(windowAdded, windowRemoved, titleChanged, iconChanged, onAllDesktopsChanged, demandsAttentionChanged, skipTaskbarChanged)
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
//
|
||||
// Created by hxf on 9/21/23.
|
||||
//
|
||||
#pragma once
|
||||
#include <QtCore/QObject>
|
||||
#include <QtDBus/QDBusAbstractAdaptor>
|
||||
#include <QtDBus/QDBusVariant>
|
||||
|
||||
#define SYMBOL_CATENATE(arg1, arg2) arg1 ## arg2
|
||||
#define SYMBOL_CATENATE_WITH_MACRO(arg1, arg2) SYMBOL_CATENATE(arg1, arg2)
|
||||
|
||||
#define ATTR(args) args
|
||||
#define ARG_1(arg) EXPAND_MACRO(arg)
|
||||
#define ARG_2(arg, ...) ARG_1(arg) ATTR(ARG_1(__VA_ARGS__))
|
||||
#define ARG_3(arg, ...) ARG_1(arg) ATTR(ARG_2(__VA_ARGS__))
|
||||
#define ARG_4(arg, ...) ARG_1(arg) ATTR(ARG_3(__VA_ARGS__))
|
||||
#define ARG_5(arg, ...) ARG_1(arg) ATTR(ARG_4(__VA_ARGS__))
|
||||
#define ARG_6(arg, ...) ARG_1(arg) ATTR(ARG_5(__VA_ARGS__))
|
||||
#define ARG_7(arg, ...) ARG_1(arg) ATTR(ARG_6(__VA_ARGS__))
|
||||
#define ARG_8(arg, ...) ARG_1(arg) ATTR(ARG_7(__VA_ARGS__))
|
||||
#define ARG_9(arg, ...) ARG_1(arg) ATTR(ARG_8(__VA_ARGS__))
|
||||
#define ARG_10(arg, ...) ARG_1(arg) ATTR(ARG_9(__VA_ARGS__))
|
||||
#define ARG_11(arg, ...) ARG_1(arg) ATTR(ARG_10(__VA_ARGS__))
|
||||
#define ARG_12(arg, ...) ARG_1(arg) ATTR(ARG_11(__VA_ARGS__))
|
||||
#define ARG_13(arg, ...) ARG_1(arg) ATTR(ARG_12(__VA_ARGS__))
|
||||
#define ARG_14(arg, ...) ARG_1(arg) ATTR(ARG_13(__VA_ARGS__))
|
||||
#define ARG_15(arg, ...) ARG_1(arg) ATTR(ARG_14(__VA_ARGS__))
|
||||
#define ARG_16(arg, ...) ARG_1(arg) ATTR(ARG_15(__VA_ARGS__))
|
||||
|
||||
#define COUNT_PARMS_IMP(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, NUM, ...) NUM
|
||||
#define COUNT_PARMS(...) \
|
||||
ATTR(COUNT_PARMS_IMP(__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
|
||||
|
||||
#define ARGS(...) \
|
||||
ATTR(SYMBOL_CATENATE_WITH_MACRO(ARG_, ATTR(COUNT_PARMS(__VA_ARGS__)))(__VA_ARGS__))
|
||||
|
||||
class SignalForwarding : public QDBusAbstractAdaptor {
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "org.ukui.panel.signalforwarding")
|
||||
public:
|
||||
SignalForwarding(QObject *parent = nullptr);
|
||||
|
||||
#ifdef EXPAND_MACRO
|
||||
#undef EXPAND_MACRO
|
||||
#endif
|
||||
#define EXPAND_MACRO(signalName) Q_SIGNALS: \
|
||||
void signalName(QDBusVariant winId); \
|
||||
public Q_SLOTS: \
|
||||
void signalName##TypeConvert(const QVariant& winId) { \
|
||||
emit signalName(QDBusVariant(winId));}
|
||||
ARGS(windowAdded, windowRemoved, titleChanged, iconChanged, onAllDesktopsChanged, demandsAttentionChanged, skipTaskbarChanged)
|
||||
};
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* libkysdk-waylandhelper's Library
|
||||
*
|
||||
* Copyright (C) 2023, KylinSoft Co., Ltd.
|
||||
*
|
||||
* 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 3 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 General Public License
|
||||
* along with this library. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Zhen Sun <sunzhen1@kylinos.cn>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "waylandhelper.h"
|
||||
#include <KWindowSystem/kwindowsystem.h>
|
||||
#include <QDebug>
|
||||
|
||||
using namespace kdk;
|
||||
|
||||
static const char* server_flag = "XDG_SESSION_TYPE";
|
||||
static const char* client_flag = "QT_QPA_PLATFORM";
|
||||
|
||||
static WaylandHelper* g_instance = nullptr;
|
||||
bool WaylandHelper::isWaylandServer()
|
||||
{
|
||||
if (qgetenv(server_flag) == QString("wayland"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool WaylandHelper::isWaylandClient()
|
||||
{
|
||||
if (qgetenv(client_flag) == QString("wayland"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
WaylandHelper *WaylandHelper::self()
|
||||
{
|
||||
if (!g_instance)
|
||||
g_instance = new WaylandHelper();
|
||||
return g_instance;
|
||||
}
|
||||
|
||||
WaylandHelper::WaylandHelper(QObject *parent)
|
||||
:QObject(parent)
|
||||
{
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* libkysdk-waylandhelper's Library
|
||||
*
|
||||
* Copyright (C) 2023, KylinSoft Co., Ltd.
|
||||
*
|
||||
* 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 3 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 General Public License
|
||||
* along with this library. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Zhen Sun <sunzhen1@kylinos.cn>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WAYLANDHELPER_H
|
||||
#define WAYLANDHELPER_H
|
||||
|
||||
#include "kysdk-waylandhelper_global.h"
|
||||
#include <QObject>
|
||||
|
||||
namespace kdk
|
||||
{
|
||||
class WaylandHelper:public QObject
|
||||
{
|
||||
public:
|
||||
static bool isWaylandServer();
|
||||
static bool isWaylandClient();
|
||||
static WaylandHelper *self();
|
||||
|
||||
private:
|
||||
WaylandHelper(QObject* parent=nullptr);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif // WAYLANDHELPER_H
|
|
@ -1,3 +1,24 @@
|
|||
/*
|
||||
*
|
||||
* * Copyright (C) 2023, KylinSoft Co., Ltd.
|
||||
* *
|
||||
* * 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 3 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 <https://www.gnu.org/licenses/>.
|
||||
* *
|
||||
* * Authors: Nicole <buxiaoqing@kylinos.cn>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "alwaysdisplayonpanel.h"
|
||||
#include <QtDebug>
|
||||
|
||||
|
|
|
@ -1,3 +1,24 @@
|
|||
/*
|
||||
*
|
||||
* * Copyright (C) 2023, KylinSoft Co., Ltd.
|
||||
* *
|
||||
* * 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 3 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 <https://www.gnu.org/licenses/>.
|
||||
* *
|
||||
* * Authors: Nicole <buxiaoqing@kylinos.cn>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ALWAYSDISPLAYONPANEL_H
|
||||
#define ALWAYSDISPLAYONPANEL_H
|
||||
|
||||
|
|
|
@ -1,3 +1,24 @@
|
|||
/*
|
||||
*
|
||||
* * Copyright (C) 2023, KylinSoft Co., Ltd.
|
||||
* *
|
||||
* * 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 3 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 <https://www.gnu.org/licenses/>.
|
||||
* *
|
||||
* * Authors: Nicole <buxiaoqing@kylinos.cn>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "generalsettings.h"
|
||||
#include <QtDebug>
|
||||
GeneralSettings::GeneralSettings(QWidget *parent) : QFrame(parent)
|
||||
|
|
|
@ -1,3 +1,24 @@
|
|||
/*
|
||||
*
|
||||
* * Copyright (C) 2023, KylinSoft Co., Ltd.
|
||||
* *
|
||||
* * 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 3 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 <https://www.gnu.org/licenses/>.
|
||||
* *
|
||||
* * Authors: Nicole <buxiaoqing@kylinos.cn>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GENERALSETTINGS_H
|
||||
#define GENERALSETTINGS_H
|
||||
|
||||
|
|
|
@ -1,3 +1,24 @@
|
|||
/*
|
||||
*
|
||||
* * Copyright (C) 2023, KylinSoft Co., Ltd.
|
||||
* *
|
||||
* * 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 3 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 <https://www.gnu.org/licenses/>.
|
||||
* *
|
||||
* * Authors: Nicole <buxiaoqing@kylinos.cn>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ukccplugin.h"
|
||||
|
||||
#include <ukcc/widgets/switchbutton.h>
|
||||
|
|
|
@ -1,3 +1,24 @@
|
|||
/*
|
||||
*
|
||||
* * Copyright (C) 2023, KylinSoft Co., Ltd.
|
||||
* *
|
||||
* * 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 3 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 <https://www.gnu.org/licenses/>.
|
||||
* *
|
||||
* * Authors: Nicole <buxiaoqing@kylinos.cn>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UKCCPLUGIN_H
|
||||
#define UKCCPLUGIN_H
|
||||
|
||||
|
|
Loading…
Reference in New Issue