Porting Plasmoids to KF6
The Plasma API used to make desktop widgets (also known as "applets" or "plasmoids") is changing for the Plasma 6.0 release.
Changes Overview
Background Information
A plasmoid's base component is a C++ class called Applet, which is a QObject. Applets are contained in an Applet subclass called Containment, which manages the lifecycle of all of its applets. On Plasma Desktop, each screen has one containment which manages its desktop area, and another for each panel on that desktop.
The root of the QML part of a plasmoid is a C++ QQuickItem implementation called AppletInterface. If a plasmoid is also a Containment, then its base is a ContainmentInterface, which is a subclass of AppletInterface.
How it worked in Plasma 5
In Plasma 5, AppletInterface exposed and wrapped most of the Applet API, plus some QtQuick-related additions. The root QML object of each plasmoid could be any QML Item, and the AppletInterface was accessed in QML via the Plasmoid attached property or the plasmoid (lowercase) context property.
The Applet base instance was usually not accessible, unless the plasmoid offered a C++ Applet plugin, in which case it was accessible via the property Plasmoid.nativeInterface.
How it works in Plasma 6
In Plasma 6, AppletInterface and Applet have a more clear task separation. All the wrapper properties and methods from AppletInterface to Applet (and from ContainmentInterface to Containment) have been removed. AppletInterface and ContainmentInterface only offer QtQuick-specific API now.
The root QML object of a plasmoid is now required to be a PlasmoidItem which is the QML name for AppletInterface. If it is also a containment, it must be of type ContainmentItem, which is the QML name for ContainmentInterface. This approach is similar and consistent with the ApplicationWindow type for QML-based applications.
The attached Plasmoid object, as well the lowercase plasmoid context property are now instances of the underlying Applet (or Containment for panels and desktops), keeping most of the API present in the Plasma 5 version of the attached property.
The new PlasmoidItem root element--which is the QML frontend to the C++ AppletInterface class--maintains the following properties, which were already there in Plasma 5:
compactRepresentationfullRepresentationpreferredRepresentationswitchWidthswitchHeightactivationTogglesExpandedtoolTipMainTexttoolTipSubTexttoolTipTextFormattoolTipItemhideOnWindowDeactivate
In Plasma 6, a new plasmoid property has been added, which points to the Applet instance.
The new ContainmentItem root element--which is the QML frontend to the C++ ContainmentInterface class--maintains the following properties, which were already there in Plasma 5:
wallpaper
Methods already present in Plasma 5:
processMimeDatacontainmentAtmapFromAppletmapToAppletadjustToAvailableScreenRegionopenContextMenu
In Plasma 6, a new method AppletInterface *itemFor(Plasma::Applet *applet) has been added, which is used to get the AppletItem instance of a given Applet. NOTE: it may return null when invoked before componentComplete of the ContainmentItem is executed (FIXME).
Porting an existing plasmoid
The main thing to consider is adapting to the new subdivision of API between PlasmoidItem and Plasmoid. In general, you will need to take the following steps:
- Port the root 
Itemof the plasmoid toPlasmoidItem(orContainmentItem, if the plasmoid is a containment). If the root item wasn't anItembut rather something functional like aMouseArea, that item should be made a child of the new rootPlasmoidItemorContainmentItem. - All the properties and methods mentioned above will have to be ported from the 
Plasmoidattached property (orplasmoidcontext property) to be properties set on the rootPlasmoidItemorContainmentItemitem. Other properties, such asiconandtitlecan remain using thePlasmoidattached property. - for plasmoids that offer a C++ plugin as an 
Appletsubclass, the C++ part doesn't change. The QML part drops itsnativeInterfaceintermediary property, so change properties likePlasmoid.nativeInterface.myPropertytoPlasmoid.myProperty - Un-version your QML module imports. This is unnecessary in Qt6 and can cause bugs.
 
In addition, some changes to applets' metadata are needed. In Plasma 6, all plasmoids must use JSON metadata. You can convert your plasmoid's old-style .desktop file to the new-style .json file using the desktoptojson command line utility. Beyond the automatic desktop-to-json metadata conversion, a few manual tweaks are also needed:
- Set 
"X-Plasma-API-Minimum-Version": "6.0"so that the system sees the plasmoid. Plasmoids without this key are assumed to only work with Plasma 5 and will not be mad available in the UI. - Remove the 
X-Plasma-MainScriptentry. In Plasma 6,ui/main.qmlis always used as the entry point, so make sure that's the name of your "main" file. - Remove the 
X-Plasma-APIentry. 
If you automatically converted the metadata.json from a metadata.desktop, the KPlugin section may still contain the ServiceTypes key.
This needs to be replaced by a KPackageStructure entry in the json's top level.
For example, the following ServiceTypes section must be reworked:
{
    "ServiceTypes": [
        "Plasma/Applet"
    ]
}into this KPackageStructure definition:
{
    "KPackageStructure": "Plasma/Applet"
}Example porting of a minimal plasmoid
Qt5
import QtQuick 2.15
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.plasmoid 2.0
Item {
    id: root
    Plasmoid.toolTipMainText: i18n("This is %1", Plasmoid.title)
    Plasmoid.fullRepresentation: Item { ... }
    Plasmoid.compactRepresentation: Item { ... }
}Qt6
import QtQuick 2.15
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.plasmoid
PlasmoidItem {
    id: root
    // toolTipMainText is a direct property of root, title is a property of Plasmoid attached property
    toolTipMainText: i18n("This is %1", Plasmoid.title)
    fullRepresentation: Item { ... }
    compactRepresentation: Item { ... }
}Components to replace with others of same functionality
Things moved to Kirigami
The following things have been replaced by their Kirigami counterparts:
| Plasma 5 | Plasma 6 | 
|---|---|
| PlasmaCore.ColorScope.colorGroup | Kirigami.Theme.colorSet | 
| PlasmaCore.ColorScope.inherit | Kirigami.Theme.inherit | 
| PlasmaCore.Theme.smallestFont | Kirigami.Theme.smallFont | 
| PlasmaCore.Theme.NormalColorGroup | Kirigami.Theme.Window | 
| PlasmaCore.Theme.anything else | Kirigami.Theme.the same thing | 
| PlasmaCore.Theme.mSize(font).height | Kirigami.Units.gridUnit | 
| PlasmaCore.Units.largeSpacing | Kirigami.Units.gridUnit | 
| PlasmaCore.Units.devicePixelRatio | 1 | 
| PlasmaCore.Units.roundtoIconSize(font height) | Kirigami.Units.iconSizes.sizeForLabels | 
| PlasmaCore.Units.roundtoIconSize(value) | Kirigami.Units.iconSizes.roundedIconSize(value) | 
| PlasmaCore.Units.anything else | Kirigami.Units.the same thing | 
| PlasmaCore.IconItem | Kirigami.Icon | 
| PlasmaExtras.Heading | Kirigami.Heading | 
Note: remember to add import org.kde.kirigami as Kirigami in
files that don't have it yet
New KSvg framework
Everything regarding SVG theming has moved from Plasma Framework to a new framework called KSvg.
The API is compatible, with the exception of the colorGroup: property which
has been removed from KSvg because its functionality is now provided automatically.
The import needs to be changed to:
import org.kde.ksvg as KSvg
| Plasma 5 | Plasma 6 | 
|---|---|
| PlasmaCore.Svg | KSvg.Svg | 
| PlasmaCore.SvgItem | KSvg.SvgItem | 
| PlasmaCore.FrameSvgItem | KSvg.FrameSvgItem | 
Also, even if the old syntax is still compatible, it's recommended to change:
KSvg.SvgItem {
    svg: KSvg.Svg {
        imagePath: "widgets/background"
    }
}To the more compact form:
KSvg.SvgItem {
    imagePath: "widgets/background"
}New Plasma5Support library
Some parts of Plasma Framework have moved to Plasma5Support, such as types for the Data Engines system.
Their new import is:
import org.kde.plasma.plasma5support as Plasma5Support
| Plasma 5 | Plasma 6 | 
|---|---|
| PlasmaCore.DataSource | Plasma5Support.DataSource | 
| PlasmaCore.DataModel | Plasma5Support.DataModel | 
New Actions API
Plasmoids can add contextual actions, which appear in their headers (when used in the System Tray) and context menus.
In Plasma 5 these actions were defined using an imperative API in Component.onCompleted:, like so:
Component.onCompleted: {
    Plasmoid.clearActions()
    Plasmoid.setAction("previous", i18nc("Play previous track", "Previous Track"),
                        Qt.application.layoutDirection === Qt.RightToLeft ? "media-skip-forward" : "media-skip-backward");
    Plasmoid.action("previous").enabled = Qt.binding(() => root.canGoPrevious)
    Plasmoid.action("previous").visible = Qt.binding(() => root.canControl)
    Plasmoid.action("previous").priority = Plasmoid.LowPriorityAction
    ...
}
// Handling of actions then had to be done by adding "magic" functions:
function action_previous() {
  serviceOp(mpris2Source.current, "Previous");
}This has been replaced with a purely declarative API, in the form of a new QML type
called PlasmaCore.Action and a contextualActions: list property on the Plasmoid
item, where all the actions are declared with standard array syntax. The Plasma 6 version
of the above example can be rewritten as follows:
Plasmoid.contextualActions: [
    PlasmaCore.Action {
        text: i18nc("Play previous track", "Previous Track")
        icon.name: Qt.application.layoutDirection === Qt.RightToLeft ? "media-skip-forward" : "media-skip-backward"
        priority: Plasmoid.LowPriorityAction
        visible: root.canControl
        enabled: root.canGoPrevious
        onTriggered: serviceOp(mpris2Source.current, "Previous")
    },
    ...
]This way, both property bindings and the code to be executed when the action is
activated are all defined inline in a declarative way inside the PlasmaCore.Action
definition.
PlasmaCore.SortFilterModel to KItemModels.KSortFilterProxyModel
The item SortFilterModel from the import org.kde.plasma.core has been removed.
Any usages of it should be ported to the KSortFilterProxyModel component which offers
the same functionality. You can import it using org.kde.kitemmodels.
There are some key differences. While SortFilterModel has properties sortRole
and filterRole that take strings as role names, KSortFilterProxyModel
has the same two properties accepting only integers as the actual role values.
Usages of role names must be ported to the properties sortRoleName
and filterRoleName (sortRole and filterRole will automatically sync to the coresponding role number)
The filterRegExp property becomes filterRegularExpression which will have to be a RegExp()
type, such as filterRegularExpression: RegExp(".*foo.+").
Another change in usage is filterCallback which becomes filterRowCallback and filterColumnCallback
with a different API: the value parameter is gone, replaced by the parent index, from which the data of any role number can be extracted.
Example usage:
KItemModels.KSortFilterProxyModel {
    id: configDialogFilterModel
    sourceModel: ...
    filterRoleName: "name"
    filterRowCallback: (sourceRow, sourceParent) => {
        // filterRole will be the corresponding number for the role named the value set in filterRoleName
        let value = sourceModel.data(sourceModel.index(sourceRow, 0, sourceParent), filterRole);
        return value === "foo";
    }
}ExpandableListItem
- Rename property 
contextualActionsModeltocontextualActions. - Properties 
iconUsesPlasmaSVG,contextMenuandenabledActionsare gone. - Port 
isEnabledproperty to the standardenabledone. 
Configuration UI
If the plasmoid ships with a configuration UI this needs to be adjusted. The root item for a configuration page now must be one of the KCM components from the org.kde.kcmutils import.
Available are:
SimpleKCM: Use this for arbitrary content, e.g. a FormLayout or a column of controls. This will be the right thing for most applets.AbstractKCM: Similar to SimpleKCM, but does not contain a ScrollView. Use this when you need control over where and how to use a ScrollView in the UI.ScrollViewKCM: Use this when your configuration features a central ListView or similar view. Additional controls can be placed asheaderandfooterof the control.GridViewKCM: Use this when your configuration features a central GridView.
Example usage:
import QtQuick
import QtQuick.Controls
import org.kde.kirigami as Kirigami
import org.kde.kcmutils as KCM
KCM.SimpleKCM {
    property var cfg_myConfigKey
    Kirigami.FormLayout {
        Button {
            ...
        }
    }
}