본문으로 건너뛰기
cccskills
무료GitHub에 공개

kde-plasmoid

Use when building KDE Plasma 6 widgets with a Python backend - plasmoid structure, metadata.json, QML UI, configuration system, plasmapkg2 packaging, KDE Store submission, or plasmoid testing and debugging

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(4)

  • SKILL.md10.6 KB
  • references/configuration.md4.6 KB
  • references/packaging-publishing.md4.9 KB
  • references/testing-debugging.md9.9 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

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

ComponentVersion
Plasma6.x
Qt6.x
Python3.8+
PySide6/PyQt66.x

Dependencies

System Packages

# Arch/Manjaro
sudo pacman -S python-pyqt6 pyside6 kirigami plasma-framework plasma-sdk

# Fedora
sudo dnf install python3-pyqt6 python3-pyside6 kf6-kirigami-devel plasma-framework plasma-sdk

# Debian/Ubuntu
sudo apt install python3-pyqt6 python3-pyside6 kirigami-devel plasma-framework plasma-sdk

# openSUSE
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

Python Backend

Basic Backend Class

#!/usr/bin/env python3
"""Python backend for Plasma widget"""

from PySide6.QtCore import QObject, Signal, Slot, Property
# OR PyQt6:
# from PyQt6.QtCore import QObject, pyqtSignal as Signal, pyqtSlot as Slot, pyqtProperty as Property

class WidgetBackend(QObject):
    """Backend logic exposed to QML"""
    
    # Signals
    dataUpdated = Signal()
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self._data = "Initial Value"
        self._count = 0
    
    # Properties (exposed to QML)
    @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
    
    # Slots (callable from QML)
    @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

FeaturePySide6PyQt6
SignalSignalpyqtSignal
SlotSlotpyqtSlot
PropertyPropertypyqtProperty
LicenseLGPLGPL
QML Registration@QmlElement decoratorqmlRegisterType()

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.Units.gridUnit * 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

Best Practices

Python Backend

# ✅ GOOD: Signal-based updates
class Backend(QObject):
    dataChanged = Signal()
    
    def updateData(self):
        self._data = compute()
        self.dataChanged.emit()

# ✅ GOOD: Lazy initialization
@Slot(result=str)
def expensiveData(self):
    if not hasattr(self, '_cached'):
        self._cached = self._computeExpensive()
    return self._cached

# ❌ BAD: Blocking main thread
@Slot(result=str)
def slowOperation(self):
    time.sleep(5)  # Blocks UI

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

# Use Timer for periodic updates
from PySide6.QtCore import QTimer

class Backend(QObject):
    def __init__(self):
        self._timer = QTimer()
        self._timer.timeout.connect(self.refresh)
        self._timer.start(60000)  # 60 seconds

Deep Dives

Refer to these on-demand reference files for detailed topics:

  • Configuration System — references/configuration.md: metadata.json schema, KCFG main.xml, config.qml, configGeneral.qml, property aliases with cfg_ prefix
  • Packaging & Publishing — references/packaging-publishing.md: plasmapkg2 CLI, .plasmoid package creation, local/system deployment, KDE Store submission workflow
  • Testing & Debugging — references/testing-debugging.md: plasmoidtest tool, exit codes, troubleshooting guide, unit/integration tests, debug logging

References

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

aiohttp

무료

Use when building Python async HTTP services or clients with aiohttp - web server routing, middleware, WebSocket, SSE, streaming, client sessions, pytest-aiohttp testing, or troubleshooting SSL and timeout issues

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

CodeAtCode/oss-ai-skills242026년 10월 9일 업데이트

ast-grep

무료

Use when doing structural code search and rewriting - ast-grep linting, refactoring, multi-language patterns

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

CodeAtCode/oss-ai-skills242026년 10월 9일 업데이트

Use when building GBA games with the BPCore Lua engine - entity, sprite and tilemap functions, SRAM save and load, link cable multiplayer protocol, camera and scrolling, or optimization patterns

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

CodeAtCode/oss-ai-skills242026년 10월 9일 업데이트

celery

무료

Use when running background tasks with Celery - worker and broker configuration (Redis, RabbitMQ), task routing by name vs queue, chains/groups/chords, retry patterns (autoretry_for, retry_backoff), acks_late semantics, failure detection, and monitoring with Flower

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

CodeAtCode/oss-ai-skills242026년 10월 9일 업데이트

django

무료

Use when building Django applications - security hardening, authentication and permissions, ORM optimization, PostgreSQL features, Django 6.0, migrations, testing, and ecosystem libraries

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

CodeAtCode/oss-ai-skills242026년 10월 9일 업데이트

Use when customizing Django Admin - save_formset, get_search_results, formsets, queryset optimization, db_index, custom URLs

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

CodeAtCode/oss-ai-skills242026년 10월 9일 업데이트

CodeAtCode의 스킬 모두 보기

이 스킬의 문제 신고