C++ Plasmoid first steps

I discovered that KDevelop has built-in templates for C++ Plasmoids. I used the wizard to create a ‘Hello World’ project, and after building it, the output files are located in my build directory.

  󰈺  fisiu  …/ /kde/Hello  ♥ 16:04  pwd
/home/fisiu/Work/kde/Hello

  󰈺  fisiu  …/ /kde/Hello  ♥ 16:04  tree build/bin/
build/bin/
└── plasma
├── applet
│   └── org
│       └── kde
│           └── plasma
│               └── hello
│                   ├── main.qml
│                   ├── org.kde.plasma.hello.qmltypes
│                   ├── org.kde.plasma.hello_qml_module_dir_map.qrc
│                   ├── pairs.svg
│                   └── qmldir
└── applets
└── org.kde.plasma.hello.so

8 directories, 6 files

How can I test it? Shoudld I use plasmoidviewer or plasmawindowed?

Also, how do I ensure the Plasmoid finds the .so library during development without installing it to the system’s plugin directory (/usr/lib64/qt6/plugins/plasma/applets/)?

+1 on this question =)

actually, I was able to build and install the so.
I can copy the qml files manually to my ~/.local …
But I guess my CMakeLists.txt should be doing the install process.
right now it looks something like:

cmake_minimum_required(VERSION 3.16)

set(QT_MIN_VERSION "6.7.0")
set(KF6_MIN_VERSION "6.0.0")

find_package(ECM ${KF6_MIN_VERSION} REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})

include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings NO_POLICY_SCOPE)
include(FeatureSummary)

find_package(Qt6 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS
        Core
        Gui
        Qml
        Quick
)

find_package(KF6 ${KF6_MIN_VERSION} REQUIRED COMPONENTS
        I18n
        Config
        Package
)

find_package(Plasma REQUIRED)

add_definitions(-DTRANSLATION_DOMAIN=\"plasma_applet_org.kde.plasma.reunion\")

plasma_add_applet(org.kde.plasma.reunion
    QML_SOURCES
        qml/main.qml
    CPP_SOURCES
        helloworld.cpp
    RESOURCES
        qml/images/pairs.svg
    GENERATE_APPLET_CLASS
)

target_link_libraries(org.kde.plasma.reunion PRIVATE
    Qt6::Gui
    Plasma::Plasma
    KF6::I18n
)

I managed this. For now, my plasmoid structure is very simple.

.
├── CMakeLists.txt
├── package
│   ├── contents
│   │   ├── config
│   │   │   ├── config.qml
│   │   │   └── main.xml
│   │   └── ui
│   │       ├── config
│   │       │   ├── General.qml
│   │       │   └── Jobs.qml
│   │       └── main.qml
│   └── metadata.json
└── src
├── CMakeLists.txt
├── rsynkbackend.cpp
└── rsynkbackend.h

Top level CMakeLists.txt:

cmake_minimum_required(VERSION 3.16)

set(PROJECT_VERSION "1.0")
project(rsynk VERSION ${PROJECT_VERSION})
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# 1. Standard C++20 Settings
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(QT_MIN_VERSION "6.0.0")
set(KF6_MIN_VERSION "6.0.0")

# 2. Find KDE and Qt dependencies
find_package(ECM ${KF6_MIN_VERSION} REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})

include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings NO_POLICY_SCOPE)
include(ECMQtDeclareLoggingCategory)

include(ECMGenerateExportHeader)
include(ECMInstallIcons)
include(KDEPackageAppTemplates)
include(GenerateExportHeader)
include(CMakePackageConfigHelpers)
include(KDEClangFormat)
include(KDEGitCommitHooks)
include(ECMDeprecationSettings)
include(ECMQmlModule)
include(FeatureSummary)

find_package(Qt6 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS
    Core
    Quick
    Qml
)

find_package(KF6 ${KF6_MIN_VERSION} REQUIRED COMPONENTS
    Config
    CoreAddons
    # I18n
)

find_package(Plasma ${PROJECT_DEP_VERSION} REQUIRED)
find_package(PlasmaQuick ${PROJECT_DEP_VERSION} REQUIRED)


# 3. Tell CMake to go into the src folder
add_subdirectory(src)

# 4. Install the Plasma package (Metadata and QML)
plasma_install_package(package pl.fidano.rsynk)

feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)

src/CMakeLists.txt:

ecm_add_qml_module(rsynk URI "pl.fidano.rsynk" GENERATE_PLUGIN_SOURCE)

target_sources(rsynk PRIVATE
    rsynkbackend.cpp
    rsynkbackend.h
)

target_link_libraries(rsynk PRIVATE
    Qt::Gui
    Qt::Qml
)

ecm_finalize_qml_module(rsynk DESTINATION ${KDE_INSTALL_QMLDIR})

I also moved from kdevelop to vscode. I set in my project, .vscode/settings.json:

{
    "cmake.installPrefix": "${userHome}/.local"
}

And some custom tasks to streamline developer expirience, .vscode/tasks.json:

{
	"version": "2.0.0",
	"tasks": [
		{
			"type": "cmake",
			"label": "cleanRebuild",
			"command": "cleanRebuild",
			"targets": [
				"all"
			],
			"group": "build",
		},
		{
			"type": "cmake",
			"label": "install",
			"command": "install",
			"problemMatcher": [],
		},
		{
			"type": "shell",
			"label": "fire",
			"command": [
				"plasmoidviewer",
				"-s",
				"600x600",
				"-a",
				"pl.fidano.rsynk"
			],
			"dependsOn": [
				"cleanRebuild",
				"install"
			],
			"dependsOrder": "sequence",
			"group": "build"
		}
	]
}

So hitting Ctrl+Shift+B, selecting task fire builds c++ code and then it copies built lib alongside qml part to proper directory. With this setup I can easily create system package (archlinux package example) with standard settings:

build() {
 # Configure CMake with standard Plasma 6 flags
 cmake -B build -S "${_pkgname}" \
  -DCMAKE_INSTALL_PREFIX=/usr \
  -DCMAKE_BUILD_TYPE=Release \
  -DBUILD_TESTING=OFF \
  -DQT_MAJOR_VERSION=6

  # Build the C++ backend
  cmake --build build
}

package() {
 # Install to the package directory
 DESTDIR="$pkgdir" cmake --install build
}

Using a .local prefix, installed plasmoid lands in:

.local/share/plasma/plasmoids/pl.fidano.rsynk/
├── contents
│   ├── config
│   │   ├── config.qml
│   │   └── main.xml
│   └── ui
│       ├── config
│       │   ├── General.qml
│       │   └── Jobs.qml
│       └── main.qml
└── metadata.json

while the lib in:

.local/lib/qml/pl/fidano/rsynk/
├── kde-qmlmodule.version
├── librsynk.so
├── qmldir
└── rsynk.qmltypes

So to make it work I set QML_IMPORT_PATH=/home/fisiu/.local/lib/qml.

With system-wide install, all files land in proper dirs.