Step up your KDE Plasma rice game: A Beginner’s guide to KDE Frameworks and developing your own plasmoids and more

Learn how to code for KDE Plasma and develop a clock plasmoid.

Mukunda Adhikari
The Zerone
11 min readJan 5, 2023

--

This tutorial will walk you through the basics of programming you require to create your own plasmoid (desktop or taskbar widgets) for KDE Plasma, a Linux desktop environment popular for its versatile customizability.

So you got into Linux. Probably you got tired of a clean install of Windows taking 2.2 GB of your RAM while idle (which is half of the total RAM for some!) or you started being serious about your privacy or, like me, you got into it for the “hacking”. Trust me, many of us had that phase once. Then fiddling around and distro hopping from one to another, you stumbled upon KDE Plasma, and how seamless it was to customize it. You went all out with it; trying all of LinuxScoop’s customization videos to then trying out everything from KDE Store. Then you got lost, without anything else to add on to make your Plasma rice look good.

So this is the perfect place for you.

Because when you are done with this, you would have created a Plasmoid, and learned most of the basics you would need to start creating one from scratch yourself.

Prerequisites:

  • Experience with Linux distro having KDE Plasma
  • Decent bit of knowledge and experience with programming.

Setting up the development environment:

To develop for KDE Plasma, you need to install and configure a set of applications or tools that allows you to code, test, compile and build it into a form which your computer can run, and then make a deployable file. This set of tools collectively comprise a development environment. Your Linux Distro could possibly have some, if not all of this, installed. But I’d suggest going through all of these. We would be using the command line interface, Konsole in the case of KDE, but any terminal program would suffice.

Arch/Manjaro:

 sudo pacman -S git cmake dialog extra-cmake-modules

Fedora:

sudo dnf install git cmake dialog perl perl-IPC-Cmd perl-MD5 perl-FindBin

KDE Neon/Kubuntu/Ubuntu/Debian:

 sudo apt install git cmake dialog
The tools that I have used for modifying and developing plasmoids and tools for KDE Plasma.

Now we need to install KAppTemplate. KAppTemplate is an application to start development quickly using existing templates providing basic repeatedly written code and a proper structure. It saves time and makes it easier for beginners to code their first project. To install KAppTemplate: https://apps.kde.org/kapptemplate/

You would also need an IDE. You can use any IDE you are familiar with but for this tutorial, we will be using KDE’s official Advanced Text Editor, Kate.

With this, you are ready to develop your first KDE Plasma Project.

Building your first Plasmoid: Hello World

1. Start KAppTemplate. Click on the Application Launcher Icon. Type “KAppTemplate” in the search bar, or you could manually click on the Development Category and select it. It should greet you with this.

2. Select your preferred template. You will be presented with a big list of templates, ranging from empty file to wallpaper to QtQuick 2 Application. Our concern is with plasmoid, so select Plasma -> Plasmoid -> Plasma QML Applet with QML extension. Name the project as you desire. For this tutorial, I’ll be using “project2”.

3. Configure Project Properties. This includes stuff like version number, installation directory, author name and email. Installation directory determines where the template would be copied to, so choose the location that’s convenient for you. I’ll be leaving it as is for this tutorial.

Navigate to the location that you installed the template in.

The template that we exported contains these files. CMakeLists.txt is the important part here. It contains the libraries, packages, directories of where your codes are in, and other stuff required to properly build your project.

All the coding we do will be in main.qml which is inside package -> contents -> ui.

4. Using qmlscene to test the created qml file. Qmlscene allows you to run and test the qml file before you build and deploy it. Essentially, it makes prototyping easier. For this, you would have to comment out, which you can do by adding “//” at the start of the line of the code, the portion of the code which uses KDE libraries as qmlscene only supports the default Qt/QML libraries.

To load a qml file with qmlscene, open the folder in terminal and run “qmlscene [filename].qml”

Qmlscene output of our main.qml after commenting out blocks of code which used KDE Libraries.

5. Building and installing our plasmoid. Once we are done with coding, we have to build and install it. To do that, first Navigate back to the main directory of our project, project1.

a. Open the folder in the terminal or use the terminal that is present in Dolphin (which you can enable by pressing F4). Create a new folder called build by running “mkdir -p build”

b. Navigate to the folder by “cd build”

c. Then run the command “cmake -DCMAKE_INSTALL_PREFIX=/usr/ ..”. It will generate a native build environment that will compile source code, create libraries, generate wrappers and build executables in arbitrary combinations

d. Run “make”

e. Run “sudo make install”

And voila! Your first plasmoid is created, tested, built and installed to KDE. Logoff and Login to your computer. Right Click on Desktop, click on “Add Widget” and search “project1”

Aesthetic Clock

That’s the name of the plasmoid we are gonna create. It is available in Pling/KDE Store, or you could use the “Get New Widgets” feature in the “Add Widgets” menu to get it on your desktop.

A bit of background on its origin: The concept of this widget came to me while I was browsing through Dribbble, which is a design portfolio site. And this bit is important. You need to explore, to look around; the inspiration you find through this would be helpful for the applications and stuff you design. Dribbble, Behance, Pinterest: these would be good places to start from. You can save the images within the sites.

And once you collect tons of images to serve as an inspiration, you would need something to organize them for feasibility. That’s where PureRef, and other similar services like Beeref (which is available for Linux unlike Pureref), comes in. These applications essentially allow you to put all your reference images into a single window.

This is essentially how I approach creating a new widget or application from scratch. Now with that out of the way, let’s get to coding the Aesthetic Clock.

To start, repeat the same procedure that you did for HelloWorld Plasmoid till Step 4. It’s the barebones that we need for further coding.

Once you have commented out the blocks of code which required KDE Frameworks, let’s start this with the first thing in the widget, the rounded rectangle containing the gradient background, which we create inside the Item type present in the template.

Rectangle {
id: gradientrect
anchors.fill: parent
radius: 15
gradient: Gradient {
GradientStop { position: 1.0; color: "#FF512F" }
GradientStop { position: 0.0; color: "#F09819" }
}

Creating a rectangle in QML can be easily done with the Rectangle Item type. It is contained in “import QtQuick”. You can paint it with either a color or a gradient. If both are specified, gradient is used. The id is used to identify the rectangle, which is useful when you are adding other items inside it (we will touch on that later). The radius is for rounded edges. For gradient, you can either use predefined gradient inside Qt, which looks like:

gradient: Gradient.NightFade

Or you can also set start and end color, start color being defined by position: 0 and end by position:1 as we did in the above block of code.

Now the background image, which is the sharp mountains in our plasmoid. QML doesn’t have a property in the rectangle type for it, so we would have to add a separate Image Item.

Image {
source: "1.png"
anchors.fill: gradientrect
fillMode: Image.PreserveAspectCrop
anchors.bottom: gradientrect.bottom
opacity: 0.05
}

This is where the importance of assigning id that we talked about earlier comes in. We have set our “anchors.fill” to the rectangle we created before (which is now the parent object), which positions the Image type in such a way that its edges anchor to the edges of the parent. It essentially bounds the image to the rectangle. The other important thing here is fillMode.

These are the type of fillmodes available in QML Image Type. The one we are using, PreserveAspectCrop fills the parent object by cropping the image. The opacity used is 0.05, which is just a random number chosen by eyeballing it after testing it several times in qmlscene.

The bottom text showing the day and date is done by Label Type.

Label {
text: Qt.formatDate(timeSource.data["Local"]["DateTime"],"dddd" ) + ", " + Qt.formatDate(timeSource.data["Local"]["DateTime"], "MMMM dd" )
color: "#FFFFFF"
font.family: "Noto Sans"
font.pixelSize: 16
font.weight: Font.ExtraBold
Layout.alignment: Qt.AlignHCenter
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: 15
}

The color, font.family, font.pixelSize, font.weight, Layout.alignment are similar to what you would do in other programming languages or a word processor. The anchors are set to align it to the bottom of the rounded rectangle leaving a margin of 15. The horizontalCenter is set to parent object’s horizontalCenter which allows Layout.alignment to work.

The tricky part here is the text. It takes members of the array from the DataSource called timeSource (which in turns takes the data from the system), and formats it respectively. For this to work, you would have to initialize the datasource at the end of the file.

We then have the center text showing time in hours and minutes. It is again done by using Label. We are taking “hours” and “minutes” data and formatting it.

Label {
text: hours + ":" + ('0'+ minutes).slice(-2);
color: "#FFFFFF"
font { family: "Noto Sans"; pixelSize: 60}
Layout.alignment: Qt.AlignHCenter
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
} }

Next, we are going to animate the two small circles describing the time. To do this, we use the Canvas QML Type. It creates a 2d Canvas item enabling drawing via Javascript. It is similar to HTML5 Canvas. You can port your existing HTML5 Canvas application to QML with the help of this guide.

Before we start drawing with the canvas, we would have to initialize some variables needed for drawing with canvas.

property int hours
property int minutes
property int minute
function timeChanged() {
var date = new Date;
hours = date.getHours();
if (hours > 12) { hours = hours - 12 }
minutes = date.getMinutes();
minute = date.getMinutes();
}

We initialize hours, minutes and minute and get their data from Javascript’s Date object. We get the Minutes data twice because one would be modified for animating the circle while the other will be used for the Label that we did above.

With the above data, and a bit of High School Trigonometry, we animate the circles in the following way.

Canvas {
id:canvas
anchors.fill: gradientrect
onPaint: {
var ctx = getContext("2d");
ctx.reset();
var centreX = width / 2;
var centreY = height / 2;
ctx.beginPath();
ctx.arc(centreX, centreY, width / 3, -Math.PI/2, (3 * Math.PI)/2);
ctx.lineWidth = 10;
ctx.strokeStyle = "rgba(255,255,255,0.4)"
ctx.stroke();
ctx.beginPath();
ctx.arc((centreX + ((width / 3) * Math.cos((((hours*30)*(Math.PI/180)) - 1.57)))),( centreY + ((width / 3) * Math.sin((((hours*30)*(Math.PI/180)) - 1.57)))), 9, -Math.PI, Math.PI );
ctx.fillStyle = "white";
ctx.fill();
ctx.beginPath();
ctx.arc((centreX + ((width / 3) * Math.cos((((minute*6)*(Math.PI/180)) - 1.57)))),( centreY + ((width / 3) * Math.sin((((minute*6)*(Math.PI/180)) - 1.57)))), 9, -Math.PI, Math.PI );
ctx.fillStyle = "white";
ctx.fill();
}
}

First, we have id and anchors.fill. We want to make our canvas within the size of the gradient so we are going to set the latter to gradientrect. All the drawing/animating is done inside the onPaint event.

We need to initialize a Context2d object to render to the Canvas. We then clear the canvas, and define the center coordinates to draw the circle. Each drawing action is started by ctx.beginPath() and ends with specifying whether it’s a stroke() or a fill(). The first block of code above creates a circle at the center, with the radius width/3. The remaining two parameters are start angle and end angle, since we used the arc function to create the circle.

The second block and third block of codes draw a circle for the hour and minute position respectively. We use trigonometry to determine the center for the two circles. We use a smaller value for the radius and end the block with ctx.fill().

We then add this on top of the rectangle.

Layout.minimumWidth : plasmoid.formFactor == PlasmaCore.Types.Horizontal ? height : 350
Layout.minimumHeight : plasmoid.formFactor == PlasmaCore.Types.Vertical ? width : 380
Layout.preferredWidth: 350* units.devicePixelRatio
Layout.preferredHeight: 380 * units.devicePixelRatio
Plasmoid.backgroundHints: "NoBackground";

We added this block of code at the last because it uses KDE Frameworks. This wouldn’t have allowed qmlscene to work in case you were testing the result after each step. We set minimumWidth and minimumHeight as 350 and 380 respectively. This gives a nice aspect ratio to the plasmoid. We specified preferredWidth and preferredHeight to be multiple of those values to not have the aspect ratio ruined when the user tries to resize the plasmoid. Lastly we add NoBackground as backgroundHints because we have already used a gradient.

And with that, your overall code should look like this.

Once you have it, repeat the step 5 of the HelloWorld plasmoid. Reboot or sign out and sign in again, and Ta-da, you have your plasmoid ready.

What’s next?

First, give yourself a pat on the back. You have stuck to the end of this tutorial and have created a plasmoid for KDE yourself. Once you have done that, and you want to learn more, here are some pointers to help you get started.

  1. Official Qt/QML Documentation
  2. KDE Community Wiki
  3. Official KDE Documentation
  4. u/veggero’s KDE Plasma Theme Tutorial
  5. List of KDE Communities for Telegram

And this is it for this tutorial. Happy Coding!!!

--

--