| name | kde-plasmoid |
| description | Build KDE Plasma 6 widgets with Python backend and QML UI, including metadata, deployment, and KDE Store distribution |
| metadata | {"author":"mte90","version":"1.0.0","tags":["kde","plasma","plasmoid","widget","qml","qt","desktop"]} |
KDE Plasmoid Development with Python
Complete guide for developing Plasma widgets (Plasmoids) using Python backend with QML UI layer.
Overview
Important: Native Python Plasmoids (PyKDE4/PyKDE5) are deprecated in Plasma 6. Modern Plasmoids must use:
- UI Layer: QML with Kirigami components
- Backend Logic: Python (PySide6 or PyQt6) via QObject subclasses
Architecture
┌─────────────────────────────────────┐
│ QML UI Layer │
│ (PlasmoidItem + Kirigami) │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Python Backend Logic │
│ (QObject-derived classes) │
└─────────────────────────────────────┘
Version Requirements
| Component | Version |
|---|
| Plasma | 6.x |
| Qt | 6.x |
| Python | 3.8+ |
| PySide6/PyQt6 | 6.x |
Dependencies
System Packages
sudo pacman -S python-pyqt6 pyside6 kirigami plasma-framework plasma-sdk
sudo dnf install python3-pyqt6 python3-pyside6 kf6-kirigami-devel plasma-framework plasma-sdk
sudo apt install python3-pyqt6 python3-pyside6 kirigami-devel plasma-framework plasma-sdk
sudo zypper install python3-qt6 python3-pyside6 kf6-kirigami-devel plasma-framework
Python Packages
pip install psutil requests pydbus
Plasmoid Structure
my-plasmoid/
├── package/
│ ├── contents/
│ │ ├── config/
│ │ │ ├── config.qml
│ │ │ └── main.xml
│ │ ├── ui/
│ │ │ ├── main.qml
│ │ │ └── configGeneral.qml
│ │ └── main.xml
│ └── metadata.json
├── src/
│ ├── __init__.py
│ └── backend.py
├── README.md
└── LICENSE
Configuration Files
metadata.json
{
"KPlugin": {
"Authors": [
{
"Email": "your.email@example.com",
"Name": "Your Name"
}
],
"Category": "System Information",
"Description": "A Python-powered Plasma widget with system monitoring capabilities",
"Icon": "utilities-system-monitor",
"Id": "com.example.my-plasmoid",
"License": "LGPL-2.1-or-later",
"Name": "My Plasmoid",
"Version": "1.0.0",
"Website": "https://github.com/youruser/my-plasmoid",
"Keywords": [
"system",
"monitor",
"cpu",
"memory",
"disk"
],
"X-KDE-PluginInfo-Name": "com.example.my-plasmoid"
},
"X-Plasma-API-Minimum-Version": "6.0",
"X-Plasma-API-Extensions-Required": [],
"X-Plasma-Check-Compatibility": "true",
"KPackageStructure": "Plasma/Applet"
}
Critical Fields:
KPlugin.Category: Required widget category (see below)
KPlugin.License: Must be valid SPDX identifier (e.g., "LGPL-2.1-or-later", "MIT", "GPL-2.0-or-later")
X-Plasma-API-Minimum-Version: Must be "6.0" for Plasma 6
X-Plasma-Check-Compatibility: Set to "true" to enable compatibility checking
KPackageStructure: Must be "Plasma/Applet"
Id: Unique identifier, must match folder name exactly
Categories
| Category | Description |
|---|
System Information | System monitors, stats, sensors |
Utility | General tools and helpers |
Date and Time | Clocks, calendars, timers |
Environment and Weather | Weather widgets, climate data |
Miscellaneous | Other widgets not fitting other categories |
Application Launchers | App menus, launchers, shortcuts |
Windows and Tasks | Task managers, window controls |
Python Backend
Basic Backend Class
"""Python backend for Plasma widget"""
from PySide6.QtCore import QObject, Signal, Slot, Property
class WidgetBackend(QObject):
"""Backend logic exposed to QML"""
dataUpdated = Signal()
def __init__(self, parent=None):
super().__init__(parent)
self._data = "Initial Value"
self._count = 0
@Property(str, notify=dataUpdated)
def data(self):
return self._data
@data.setter
def data(self, value):
if self._data != value:
self._data = value
self.dataUpdated.emit()
@Property(int, notify=dataUpdated)
def count(self):
return self._count
@Slot(result=str)
def getData(self):
return self._data
@Slot(str)
def setData(self, value):
self.data = value
@Slot(str, result=str)
def processData(self, inputText):
"""Process input and return result"""
return f"Processed: {inputText}"
@Slot()
def refresh(self):
"""Refresh data"""
self._count += 1
self._data = f"Updated #{self._count}"
self.dataUpdated.emit()
@Slot(str, result=str)
def getSystemInfo(self, category):
"""Get system information"""
import psutil
if category == "cpu":
return f"{psutil.cpu_percent():.1f}%"
elif category == "memory":
mem = psutil.virtual_memory()
return f"{mem.percent:.1f}%"
elif category == "disk":
disk = psutil.disk_usage('/')
return f"{disk.percent:.1f}%"
return "Unknown"
PySide6 vs PyQt6
| Feature | PySide6 | PyQt6 |
|---|
| Signal | Signal | pyqtSignal |
| Slot | Slot | pyqtSlot |
| Property | Property | pyqtProperty |
| License | LGPL | GPL |
| QML Registration | @QmlElement decorator | qmlRegisterType() |
PySide6 Registration:
from PySide6.QtQml import QmlElement
QML_IMPORT_NAME = "com.example.widget"
QML_IMPORT_MAJOR_VERSION = 1
@QmlElement
class WidgetBackend(QObject):
pass
PyQt6 Registration:
from PyQt6.QtQml import qmlRegisterType
qmlRegisterType(WidgetBackend, "com.example.widget", 1, 0, "WidgetBackend")
QML UI
main.qml
import QtQuick
import QtQuick.Layouts
import org.kde.plasma.plasmoid
import org.kde.plasma.components 3.0 as PlasmaComponents3
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.kirigami 2.0 as Kirigami
import com.example.widget 1.0
PlasmoidItem {
id: root
// Backend instance
WidgetBackend {
id: backend
}
// Full representation (expanded widget)
Plasmoid.fullRepresentation: Kirigami.Card {
implicitWidth: Kirigami.Units.gridUnit * 20
implicitHeight: Kirigami.Units.gridUnit * 15
ColumnLayout {
anchors.fill: parent
anchors.margins: Kirigami.Units.smallSpacing
spacing: Kirigami.Units.smallSpacing
// Title
PlasmaComponents3.Label {
text: Plasmoid.configuration.customLabel || "My Widget"
font.bold: true
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 1.2
Layout.fillWidth: true
}
// Data display
PlasmaComponents3.Label {
text: backend.data
Layout.fillWidth: true
wrapMode: Text.WordWrap
}
// System info
RowLayout {
Layout.fillWidth: true
PlasmaComponents3.Label {
text: "CPU: " + backend.getSystemInfo("cpu")
}
PlasmaComponents3.Label {
text: "RAM: " + backend.getSystemInfo("memory")
}
}
// Input field
PlasmaComponents3.TextField {
id: inputField
placeholderText: "Enter text..."
Layout.fillWidth: true
}
// Buttons
RowLayout {
Layout.fillWidth: true
PlasmaComponents3.Button {
text: "Process"
onClicked: backend.processData(inputField.text)
}
PlasmaComponents3.Button {
text: "Refresh"
icon.name: "view-refresh"
onClicked: backend.refresh()
}
}
}
}
// Compact representation (panel icon)
Plasmoid.compactRepresentation: PlasmaCore.IconItem {
source: Plasmoid.icon
anchors.centerIn: parent
implicitWidth: {
if (Plasmoid.location === PlasmaCore.Types.HorizontalPanel ||
Plasmoid.location === PlasmaCore.Types.VerticalPanel) {
return Kirigami.Units.iconSizes.medium
}
return Kirigami.Units.iconSizes.large
}
implicitHeight: implicitWidth
MouseArea {
anchors.fill: parent
onClicked: Plasmoid.expanded = !Plasmoid.expanded
}
}
// Tooltip
Plasmoid.toolTipMainText: "My Widget"
Plasmoid.toolTipSubText: backend.data
// Icon
Plasmoid.icon: "utilities-system-monitor"
}
Plasma 6 QML Imports
// Correct Plasma 6 imports (no version numbers for most)
import QtQuick
import QtQuick.Layouts
import org.kde.plasma.plasmoid
import org.kde.plasma.components 3.0 as PlasmaComponents3
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.kirigami 2.0 as Kirigami
Configuration System
contents/config/main.xml
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
<kcfgfile name=""/>
<group name="General">
<entry name="enabled" type="Bool">
<default>true</default>
<label>Enable widget</label>
</entry>
<entry name="refreshInterval" type="Int">
<default>60</default>
<min>5</min>
<max>3600</max>
<label>Refresh interval in seconds</label>
</entry>
<entry name="customLabel" type="String">
<default>My Widget</default>
<label>Custom label</label>
</entry>
<entry name="showNotifications" type="Bool">
<default>false</default>
<label>Show notifications</label>
</entry>
</group>
</kcfg>
contents/config/config.qml
import QtQuick 2.0
import org.kde.plasma.configuration 2.0
ConfigModel {
ConfigCategory {
name: i18n("General")
icon: "configure"
source: "configGeneral.qml"
}
}
contents/ui/configGeneral.qml
import QtQuick 2.0
import QtQuick.Controls 2.5 as QQC2
import org.kde.kirigami 2.4 as Kirigami
Kirigami.FormLayout {
id: page
// Property aliases MUST use cfg_ prefix
property alias cfg_enabled: enabledCheck.checked
property alias cfg_refreshInterval: intervalSpin.value
property alias cfg_customLabel: labelField.text
property alias cfg_showNotifications: notifyCheck.checked
QQC2.CheckBox {
id: enabledCheck
text: i18n("Enable widget")
Kirigami.FormData.label: i18n("Status:")
}
QQC2.SpinBox {
id: intervalSpin
from: 5
to: 3600
editable: true
Kirigami.FormData.label: i18n("Refresh interval (seconds):")
}
QQC2.TextField {
id: labelField
placeholderText: i18n("Enter custom label")
Kirigami.FormData.label: i18n("Label:")
}
QQC2.CheckBox {
id: notifyCheck
text: i18n("Show notifications")
}
}
Accessing Configuration in QML
// Read configuration
text: plasmoid.configuration.customLabel || "Default"
checked: plasmoid.configuration.enabled
// Write configuration
plasmoid.configuration.customLabel = "New Label"
Installation & Testing
Development Commands
cd my-plasmoid/package
zip -r ../my-plasmoid.plasmoid .
plasmapkg2 -i my-plasmoid.plasmoid
plasmapkg2 -l com.example.my-plasmoid
plasmoidtest com.example.my-plasmoid
plasmoidtest /path/to/my-plasmoid/package
plasmapkg2 -r com.example.my-plasmoid
plasmapkg2 -u my-plasmoid.plasmoid
plasmapkg2 -t Plasma/Applet --list
Reload Plasma Shell
kquitapp6 plasmashell && kstart6 plasmashell
kquitapp5 plasmashell && kstart5 plasmashell
Testing with plasmoidtest
The plasmoidtest command is the recommended testing tool for Plasma 6. It provides:
- Interactive widget preview in a resizable window
- Real-time configuration testing
- Console output for debugging
plasmoidtest com.example.my-plasmoid
plasmapkg2 -l com.example.my-plasmoid
plasmoidtest --debug com.example.my-plasmoid
plasmoidtest /path/to/my-plasmoid/package
Debugging
journalctl -f | grep -i plasma
plasmoidtest com.example.my-plasmoid 2>&1 | tee debug.log
export QT_LOGGING_RULES="*.debug=true"
export QML_DEBUGGING_ENABLED=1
plasmoidtest com.example.my-plasmoid 2>&1 | grep -i "qml\|error"
plasmoidtest --validate com.example.my-plasmoid
Packaging & Distribution
Create Release Package
cd my-plasmoid
rm -f ../my-plasmoid.plasmoid
cd package && zip -r ../../my-plasmoid-1.0.0.plasmoid . && cd ..
unzip -l my-plasmoid-1.0.0.plasmoid
Build .plasmoid with plasmapkg2
cd my-plasmoid/package
plasmapkg2 -c my-plasmoid.plasmoid
plasmapkg2 -t Plasma/Applet --list
plasmapkg2 -c -o my-plasmoid-compressed.plasmoid package/
Install/Update/Remove
plasmapkg2 -i my-plasmoid.plasmoid
plasmapkg2 -i package/
plasmapkg2 -u my-plasmoid.plasmoid
plasmapkg2 -r com.example.my-plasmoid
plasmapkg2 -t Plasma/Applet --list
plasmapkg2 -t Plasma/Applet --list --verbose
KDE Store Submission
-
Prepare files:
my-plasmoid-1.0.0.plasmoid
- Screenshots (PNG, 1920x1080 recommended)
- README.md with description
- LICENSE file (compatible with specified license)
-
KDE Store requirements:
- Minimum plasma version compatibility declared
- Complete metadata in metadata.json
- Valid SPDX license identifier
- At least 3 screenshots showing widget in use
-
Upload to KDE Store:
- Visit https://store.kde.org/
- Create account
- Submit to "Plasma Desktop Applets" category
- Fill description, screenshots, changelog
- Undergo review process (typically 1-2 weeks)
-
KDE Store policy compliance:
- No promotional content
- No aggressive marketing in description
- Open-source license only (no proprietary components)
- Privacy policy for widgets accessing user data
GitHub Release
tar -czf my-plasmoid-1.0.0.tar.gz my-plasmoid/
cat > install.sh << 'EOF'
plasmapkg2 -i my-plasmoid-1.0.0.plasmoid
echo "Widget installed. Reload plasma shell: kquitapp6 plasmashell && kstart6 plasmashell"
EOF
chmod +x install.sh
./install.sh
plasmapkg2 -t Plasma/Applet --list | grep my-plasmoid
Deployment/Publishing
Local Deployment
plasmapkg2 -i my-plasmoid-1.0.0.plasmoid
find ~/.local/share/plasma-appletsrc -name "*my-plasmoid*" 2>/dev/null || \
find ~/.local/share/plasma-appletsrc -name "*com.example.my-plasmoid*" 2>/dev/null
plasmapkg2 -t Plasma/Applet --list
cat ~/.local/share/plasma-appletsrc/com.example.kde.desktop-appletsrc
System-Wide Deployment (requires root)
sudo cp my-plasmoid-1.0.0.plasmoid /usr/share/plasma/plasmoids/com.example.my-plasmoid/
sudo mkdir -p /usr/share/plasma/plasmoids/com.example.my-plasmoid
sudo cp -r my-plasmoid/package/* /usr/share/plasma/plasmoids/com.example.my-plasmoid/
kquitapp6 plasmashell && kstart6 plasmashell
sudo plasmapkg2 -l com.example.my-plasmoid
KDE Store Distribution
Step 1: Prepare package
cd my-plasmoid
VERSION="1.0.0"
plasmapkg2 -c -o my-plasmoid-${VERSION}.plasmoid package/
unzip -l my-plasmoid-${VERSION}.plasmoid
unzip -p my-plasmoid-${VERSION}.plasmoid metadata.json | jq .
Step 2: Prepare screenshots
Screenshots should:
- Be high-resolution (1920x1080 minimum)
- Show widget in actual Plasma session
- Include at least 3 variations:
- Widget in desktop mode
- Widget in panel (if applicable)
- Configuration dialog
mkdir -p screenshots
plasmoidtest com.example.my-plasmoid
Step 3: Submit to KDE Store
-
Account setup:
-
New submission:
- Click "Submit New Applet"
- Fill metadata form:
- Name, description, category
- License (must match metadata.json)
- Screenshots (upload PNG files)
- GitHub repository URL (optional but recommended)
-
Review process:
- KDE maintainers review (typically 1-2 weeks)
- Common rejection reasons:
- Missing required metadata fields
- Non-compliant license
- Promotional/proprietary content
- Broken QML syntax
- Missing plasma compatibility declaration
-
Approved applet:
- Appears in Plasma Add-Widgets panel
- Visible to all KDE users
- Automated updates available
Publishing Timeline
| Stage | Duration | Notes |
|---|
| Development | Variable | Depends on feature complexity |
| Testing | 1-2 days | Manual testing, regression checks |
| Package creation | 30 minutes | Build .plasmoid package |
| KDE Store review | 1-2 weeks | Varies by workload |
| User availability | Immediate | Once approved |
Troubleshooting
plasmapkg2 Exit Codes
| Exit Code | Meaning | Solution |
|---|
0 | Success | Package created/installed correctly |
1 | Invalid source | Check folder structure, verify contents/ exists |
2 | Missing metadata.json | Add metadata.json to package root |
3 | Invalid KPackageStructure | Set to "Plasma/Applet" in metadata.json |
4 | QML compilation error | Fix QML syntax errors in main.qml |
5 | Python backend error | Check backend.py for syntax/runtime errors |
6 | Permission denied | Run with sudo or check file permissions |
7 | Invalid KPluginMetaData | Verify all required fields in metadata.json |
8 | Config file error | Check main.xml and config.qml syntax |
9 | Package too large | Remove unused files, compress properly |
plasmapkg2 Non-Zero Exit Codes
ls my-plasmoid/package/contents/
ls my-plasmoid/package/metadata.json
plasmapkg2 -c -v my-plasmoid.plasmoid 2>&1 | grep -i "qml\|error"
jq '.KPlugin' metadata.json
Missing KPluginMetaData Errors
Error: Missing required KPluginMetaData field
Solutions:
- Missing Category:
{
"KPlugin": {
"Category": "System Information",
"Name": "My Widget",
"Id": "com.example.my-widget"
}
}
- Missing License:
{
"KPlugin": {
"License": "LGPL-2.1-or-later",
"Name": "My Widget",
"Id": "com.example.my-widget"
}
}
- Missing Version:
{
"KPlugin": {
"Version": "1.0.0",
"Name": "My Widget",
"Id": "com.example.my-widget"
}
}
QML Compilation Errors
// Error: "Object 'backend' not found"
// Solution: Ensure backend is instantiated before reference
WidgetBackend {
id: backend
}
PlasmaComponents3.Label {
text: backend.data // ← Only valid after backend initialization
}
Common QML Issues:
- Import errors:
// Error: "Import 'org.kde.plasma.plasmoid 2.0' is not allowed"
// Solution: Use Plasma 6 import (no version number)
import org.kde.plasma.plasmoid // ← No version
- Property binding errors:
// Error: "Cannot assign to const property"
// Solution: Use cfg_ prefix for config properties
property alias cfg_customLabel: label.text // ← Correct
- Undefined signals:
// Error: "Signal 'dataChanged' is not defined"
// Solution: Ensure backend has matching signal
class WidgetBackend(QObject):
dataChanged = Signal() // ← Must match QML
KPackageStructure Errors
Error: KPackageStructure must be "Plasma/Applet"
Fix in metadata.json:
{
"KPackageStructure": "Plasma/Applet",
"X-Plasma-API-Minimum-Version": "6.0"
}
Widget Not Appearing
| Issue | Solution |
|---|
Missing X-Plasma-API-Minimum-Version | Add "X-Plasma-API-Minimum-Version": "6.0" to metadata.json |
Wrong KPackageStructure | Set to "Plasma/Applet" |
| Missing main.qml | Ensure contents/ui/main.qml exists |
| Wrong Id format | Use reverse domain: com.example.widget |
| Permission denied | Check file permissions on widget directory |
| Category not found | Verify category matches predefined list |
Python Backend Not Loading
plasmapkg2 -l com.example.my-plasmoid 2>&1 | grep -i python
python3 -c "from src.backend import WidgetBackend"
python3 -c "from PySide6 import QtCore; print(QtCore.__version__)"
Common Backend Issues:
- Import errors:
from PySide6.QtQml import qmlRegisterType
qmlRegisterType(WidgetBackend, "com.example.widget", 1, 0, "WidgetBackend")
- Signal/slot mismatch:
dataUpdated = Signal()
- Attribute errors:
def __init__(self, parent=None):
super().__init__(parent)
self._data = "Initial"
Configuration Not Saving
- Check
main.xml uses correct types
- Property aliases use
cfg_ prefix
- Config file:
~/.config/plasma-org.kde.plasma.desktop-appletsrc
Debug config saving:
cat ~/.config/plasma-org.kde.plasma.desktop-appletsrc
kquitapp6 plasmashell && kstart6 plasmashell
plasmapkg2 -l com.example.my-plasmoid
Script Installation
systemd service (optional, for testing):
[Unit]
Description=Plasmoid Test Service
After=plasma-org.kde.plasma.desktop-appletsrc.service
[Service]
Type=simple
ExecStart=/usr/bin/plasmoidtest com.example.my-plasmoid
Restart=always
[Install]
WantedBy=multi-user.target
Advanced Debugging
export QT_LOGGING_RULES="*.debug=true"
export KWIN_DEBUG_LOGGING=1
plasmapkg2 -l com.example.my-plasmoid 2>&1 | tee widget-debug.log
journalctl -u plasma-org.kde.plasma.desktop-appletsrc -f | grep -i error
unzip -p my-plasmoid.plasmoid metadata.json | jq .KPlugin
qmlcppcheck main.qml
Best Practices
Python Backend
class Backend(QObject):
dataChanged = Signal()
def updateData(self):
self._data = compute()
self.dataChanged.emit()
@Slot(result=str)
def expensiveData(self):
if not hasattr(self, '_cached'):
self._cached = self._computeExpensive()
return self._cached
@Slot(result=str)
def slowOperation(self):
time.sleep(5)
QML UI
// ✅ GOOD: Use Kirigami units for scaling
width: Kirigami.Units.gridUnit * 10
spacing: Kirigami.Units.smallSpacing
// ✅ GOOD: Handle configuration defaults
text: plasmoid.configuration.label || i18n("Default")
// ❌ BAD: Hardcoded values
width: 320 // Won't scale on HiDPI
Performance
from PySide6.QtCore import QTimer
class Backend(QObject):
def __init__(self):
self._timer = QTimer()
self._timer.timeout.connect(self.refresh)
self._timer.start(60000)
Testing/Debugging
Unit Testing Backend
"""Unit tests for WidgetBackend"""
import unittest
from src.backend import WidgetBackend
class TestWidgetBackend(unittest.TestCase):
def setUp(self):
self.backend = WidgetBackend()
def test_initial_data(self):
self.assertEqual(self.backend.getData(), "Initial Value")
def test_set_data(self):
self.backend.setData("New Value")
self.assertEqual(self.backend.getData(), "New Value")
def test_process_data(self):
result = self.backend.processData("test")
self.assertEqual(result, "Processed: test")
def test_refresh(self):
self.backend.refresh()
self.assertIn("Updated", self.backend.getData())
if __name__ == "__main__":
unittest.main()
Runtime Testing
plasmoidtest com.example.my-plasmoid
krun "plasma-shell --test"
journalctl -u plasma-org.kde.plasma.desktop-appletsrc -f
Automated Testing
"""Integration tests for complete plasmoid"""
import subprocess
import sys
import tempfile
import os
def test_plasmoid_package():
"""Test plasmoid package creation"""
with tempfile.TemporaryDirectory() as tmpdir:
result = subprocess.run(
["plasmapkg2", "-c", "-o", "test.plasmoid", "package/"],
capture_output=True,
text=True
)
assert result.returncode == 0, f"Packages failed: {result.stderr}"
result = subprocess.run(
["unzip", "-l", "test.plasmoid"],
capture_output=True,
text=True
)
assert "metadata.json" in result.stdout, "Missing metadata.json"
assert "main.qml" in result.stdout, "Missing main.qml"
if __name__ == "__main__":
test_plasmoid_package()
print("All tests passed!")
Manual Testing Checklist
Debug Tools
export QT_LOGGING_RULES="*.debug=true"
export KWIN_DEBUG_LOGGING=1
plasmapkg2 -l com.example.my-plasmoid 2>&1 | tee widget-debug.log
journalctl -u plasma-org.kde.plasma.desktop-appletsrc -f | grep -i error
unzip -p my-plasmoid.plasmoid metadata.json | jq .KPlugin
qmlcppcheck main.qml
References