📜 ⬆️ ⬇️

KDE4 Plasma Desktop. Simple plasmoid do it yourself

image Starting from version 4.x, KDesktop, Kicker and SuperKaramba in KDE have come to Plasma Desktop, which have been replaced with proven over the years but obsolete (of course, opinions can also be divided). This framework represents the desktop (at least its visible part) as a collection of widgets or plasmoids. Having acquired a certain amount of free time at one time, I decided to sort out a bit with the Plasma SDK, having implemented a function that I really didn’t have enough as part of my desktop at that time. And this function is an opportunity to send entries to LiveJournal without attracting additional applications. That is a sort of mini-client built right into the desktop. “It would be great,” I thought, and began to stir up the subject area of ​​interest.

In order to implement everything described below, the system itself must contain KDE4, as well as the following installed packages: kdesdk, kdebase-devel, kdelibs-devel, cmake. Depending on the distribution, the packages may have slightly different names (I give the names for Fedora Core), but the general meaning is clear, I think.

Let's start with the fact that plasmoids are binary and script. Without any hesitation, I decided to use the “pluses” close to my heart and create, respectively, a binary widget that is a .so (shared object) module, that is, a dynamically loaded library. The elemental framework should look something like this:
')
#ifndef __lj_plasmoid_h
#define __lj_plasmoid_h

#include <Plasma/Applet>

class QSizeF;
class LjPlasmoid : public Plasma::Applet
{
Q_OBJECT
public :

LjPlasmoid(QObject *parent, const QVariantList &args);
~LjPlasmoid();

void paintInterface(QPainter *painter, const QStyleOptionGraphicsItem *option, const QRect& contentsRect);
void init();

};

#endif


* This source code was highlighted with Source Code Highlighter .
#ifndef __lj_plasmoid_h
#define __lj_plasmoid_h

#include <Plasma/Applet>

class QSizeF;
class LjPlasmoid : public Plasma::Applet
{
Q_OBJECT
public :

LjPlasmoid(QObject *parent, const QVariantList &args);
~LjPlasmoid();

void paintInterface(QPainter *painter, const QStyleOptionGraphicsItem *option, const QRect& contentsRect);
void init();

};

#endif


* This source code was highlighted with Source Code Highlighter .
#ifndef __lj_plasmoid_h
#define __lj_plasmoid_h

#include <Plasma/Applet>

class QSizeF;
class LjPlasmoid : public Plasma::Applet
{
Q_OBJECT
public :

LjPlasmoid(QObject *parent, const QVariantList &args);
~LjPlasmoid();

void paintInterface(QPainter *painter, const QStyleOptionGraphicsItem *option, const QRect& contentsRect);
void init();

};

#endif


* This source code was highlighted with Source Code Highlighter .



Everything is quite obvious: the constructor, destructor, initialization and drawing of the interface. Nothing complicated. Almost empty implementation:

#include "lj_plasmoid.h"

#include <QPainter>
#include <QFontMetrics>
#include <QSizeF>

#include <plasma/svg.h>
#include <plasma/theme.h>

//
// .desktop

K_EXPORT_PLASMA_APPLET(ljplasmoid, LjPlasmoid)

LjPlasmoid::LjPlasmoid(QObject *parent, const QVariantList &args)
: Plasma::Applet(parent, args)
{
//
//

setBackgroundHints(DefaultBackground);
resize(400, 300);
}

LjPlasmoid::~LjPlasmoid()
{
}

void LjPlasmoid::init()
{
}

void LjPlasmoid::paintInterface(QPainter *p,
const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
{
//
}

* This source code was highlighted with Source Code Highlighter .
#include "lj_plasmoid.h"

#include <QPainter>
#include <QFontMetrics>
#include <QSizeF>

#include <plasma/svg.h>
#include <plasma/theme.h>

//
// .desktop

K_EXPORT_PLASMA_APPLET(ljplasmoid, LjPlasmoid)

LjPlasmoid::LjPlasmoid(QObject *parent, const QVariantList &args)
: Plasma::Applet(parent, args)
{
//
//

setBackgroundHints(DefaultBackground);
resize(400, 300);
}

LjPlasmoid::~LjPlasmoid()
{
}

void LjPlasmoid::init()
{
}

void LjPlasmoid::paintInterface(QPainter *p,
const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
{
//
}

* This source code was highlighted with Source Code Highlighter .
#include "lj_plasmoid.h"

#include <QPainter>
#include <QFontMetrics>
#include <QSizeF>

#include <plasma/svg.h>
#include <plasma/theme.h>

//
// .desktop

K_EXPORT_PLASMA_APPLET(ljplasmoid, LjPlasmoid)

LjPlasmoid::LjPlasmoid(QObject *parent, const QVariantList &args)
: Plasma::Applet(parent, args)
{
//
//

setBackgroundHints(DefaultBackground);
resize(400, 300);
}

LjPlasmoid::~LjPlasmoid()
{
}

void LjPlasmoid::init()
{
}

void LjPlasmoid::paintInterface(QPainter *p,
const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
{
//
}

* This source code was highlighted with Source Code Highlighter .



Having saved all this, I began to assemble my plasmoid to immediately make sure that my widget draws an empty area in a beautiful frame. For this, in addition to the module itself, a .desktop file is needed as follows:

[Desktop Entry]
Name=LjPlasmoid
Comment=LiveJournal Plasmoid
Type=Service
ServiceTypes=Plasma/Applet

X-KDE-Library=plasma_applet_ljplasmoid
X-KDE-PluginInfo-Author=Ivan Ivanov
X-KDE-PluginInfo-Email=ivan.ivanov@mail.ru
X-KDE-PluginInfo-Name=ljplasmoid
X-KDE-PluginInfo-Version=0.1
X-KDE-PluginInfo-Website=http://plasma.kde.org/
X-KDE-PluginInfo-Category=Examples
X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true


Attention here should be paid to the fact that the value of the X-KDE-PluginInfo-Name field must match the first parameter of the macro K_EXPORT_PLASMA_APPLE. Next, the module itself must be copied to the folder with the KDE4 libraries (for most cases it is '/ usr / lib / kde4', or in the case of x86_64 builds '/ usr / lib64 / kde4'), and the .desktop file should be sent to the address / usr / share / kde4 / services'. Well, the final touch, we need to force the plasma to re-read its data so that the newly created widget appears in the list of available. This is done by executing the funny command 'kbuildsycoca4'.

There are two ways to see the plasmoid in action: add it directly to the desktop, or use the 'plasmoidviewer' utility, which displays the widget in a single window. However, neither one nor the other helped me. Instead of my “brainchild”, I persistently looked at the error message, which claimed that an object with the name 'ljplasmoid' could not be created by any means.

Attempts to locate the problem have been long and painful. All means went to a course, up to the fine utility of 'strace' by means of which I tried to define, whether process 'plasma-desktop' addresses to my binary module. It turned out, yes, it’s appealing, but there was little sense in it - the error persisted in manifesting itself. At the very last turn, after a few hours of treading in the same place, I began to suspect that the problem probably lies in the assembly (I used IDE CodeBlocks to edit the source code and the assembly). Desperate to solve the problem in a different way, I decided to try using cmake-script offered on the KDE website for compilation. Here it is with minimal changes:

project(ljplasmoid)

set(CMAKE_VERBOSE_MAKEFILE ON)
find_package(KDE4 REQUIRED)
include(KDE4Defaults)

add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS})
include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES})

set(ljplasmoid_SRCS lj_plasmoid.cpp)
kde4_add_plugin(plasma_applet_ljplasmoid ${ljplasmoid_SRCS})
target_link_libraries(plasma_applet_ljplasmoid ${KDE4_PLASMA_LIBS} ${KDE4_KDEUI_LIBS})


To build using the 'cmake' utility, run the command 'cmake -G "Unix Makefiles" && make' in the folder where the CMakeLists.txt file is located (it contains the script itself). For reasons that are not quite clear to me, the change of the compilation method has borne fruit - the plasmoid has earned! A translucent empty rectangle that appeared on the desktop besides indescribable joy, caused a strong fit of enthusiasm in me, and I began to continue what I started. The only thing that overshadowed my pleasure with such a development model was the lack of a single IDE and, as a result, the need to constantly switch between the terminal and the editor. But here, the exit was found pretty quickly. KDevelop development environment and its built-in project template 'CMake-based project' quickly solved all my problems.

Next thing is the technique - to add elements of the user interface (I just need a field for input and a button "Send"). Plasma uses Qt, although in fact it is necessary to connect classes that are straps over Qt-shny. In total, we have several new include and announcements in the class:

...

#include <Plasma/PushButton>
#include <Plasma/TextEdit>

...

class LjPlasmoid : public Plasma::Applet
{
...

public slots:

void PostPressed();

public :

Plasma::PushButton m_post_button;
Plasma::TextEdit m_text_edit;
};


* This source code was highlighted with Source Code Highlighter .
...

#include <Plasma/PushButton>
#include <Plasma/TextEdit>

...

class LjPlasmoid : public Plasma::Applet
{
...

public slots:

void PostPressed();

public :

Plasma::PushButton m_post_button;
Plasma::TextEdit m_text_edit;
};


* This source code was highlighted with Source Code Highlighter .
...

#include <Plasma/PushButton>
#include <Plasma/TextEdit>

...

class LjPlasmoid : public Plasma::Applet
{
...

public slots:

void PostPressed();

public :

Plasma::PushButton m_post_button;
Plasma::TextEdit m_text_edit;
};


* This source code was highlighted with Source Code Highlighter .



Well, and, naturally, about the implementation becomes at the same time a little more meaningful:

LjPlasmoid::LjPlasmoid(QObject *parent, const QVariantList &args)
: Plasma::Applet(parent, args), m_post_button( this ), m_text_edit( this )
{
m_post_button.setText( "Post" );
m_text_edit.setText( "[ok: put your text here]" );

connect(&m_post_button, SIGNAL(clicked()), SLOT(PostPressed()));

setBackgroundHints(DefaultBackground);
resize(300, 200);
}

void LjPlasmoid::paintInterface(QPainter *p,
const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
{
p->setRenderHint(QPainter::SmoothPixmapTransform);
p->setRenderHint(QPainter::Antialiasing);

m_post_button.setGeometry(QRect(contentsRect.x() + contentsRect.width() - 75,
contentsRect.y() + contentsRect.height() - 30, 10, 30));
m_text_edit.setGeometry(QRect(contentsRect.x(), contentsRect.y(),
contentsRect.width(), contentsRect.height() - 35));
}


* This source code was highlighted with Source Code Highlighter .
LjPlasmoid::LjPlasmoid(QObject *parent, const QVariantList &args)
: Plasma::Applet(parent, args), m_post_button( this ), m_text_edit( this )
{
m_post_button.setText( "Post" );
m_text_edit.setText( "[ok: put your text here]" );

connect(&m_post_button, SIGNAL(clicked()), SLOT(PostPressed()));

setBackgroundHints(DefaultBackground);
resize(300, 200);
}

void LjPlasmoid::paintInterface(QPainter *p,
const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
{
p->setRenderHint(QPainter::SmoothPixmapTransform);
p->setRenderHint(QPainter::Antialiasing);

m_post_button.setGeometry(QRect(contentsRect.x() + contentsRect.width() - 75,
contentsRect.y() + contentsRect.height() - 30, 10, 30));
m_text_edit.setGeometry(QRect(contentsRect.x(), contentsRect.y(),
contentsRect.width(), contentsRect.height() - 35));
}


* This source code was highlighted with Source Code Highlighter .
LjPlasmoid::LjPlasmoid(QObject *parent, const QVariantList &args)
: Plasma::Applet(parent, args), m_post_button( this ), m_text_edit( this )
{
m_post_button.setText( "Post" );
m_text_edit.setText( "[ok: put your text here]" );

connect(&m_post_button, SIGNAL(clicked()), SLOT(PostPressed()));

setBackgroundHints(DefaultBackground);
resize(300, 200);
}

void LjPlasmoid::paintInterface(QPainter *p,
const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
{
p->setRenderHint(QPainter::SmoothPixmapTransform);
p->setRenderHint(QPainter::Antialiasing);

m_post_button.setGeometry(QRect(contentsRect.x() + contentsRect.width() - 75,
contentsRect.y() + contentsRect.height() - 30, 10, 30));
m_text_edit.setGeometry(QRect(contentsRect.x(), contentsRect.y(),
contentsRect.width(), contentsRect.height() - 35));
}


* This source code was highlighted with Source Code Highlighter .



So I got nothing but a widget that has a simple little face:

image

To work directly with LiveJournal, the API described on the official website was used, as well as a simple set of classes written by me for these purposes, using 'libcurl'. I will not publish the sources of this class, since they are beyond the topic topic, but those interested can download them here .

So, the last method remains to be realized - sending a message to the log:

void LjPlasmoid::PostPressed()
{
LjSession session;
LjRequest post(&session, recieve_responce, this );

post.AddData( "mode" , "postevent" );
post.AddData( "user" , "user_name" );
post.AddData( "password" , "user_password" );
post.AddData( "ver" , "1" );
post.AddData( "event" , m_text_edit.nativeWidget()->toPlainText().toAscii().data());
post.AddData( "lineendings" , "unix" );
post.AddData( "subject" , "[Posted via LjPlasmoid]" );
post.AddData( "security" , "public" );
post.AddData( "year" , "2009" );
post.AddData( "mon" , "11" );
post.AddData( "day" , "23" );
post.AddData( "hour" , "20" );
post.AddData( "min" , "00" );

printf( "text2send: %s\n" , m_text_edit.nativeWidget()->toPlainText().toAscii().data());

post.Post();
m_text_edit.setText( "[ok: put your text here]" );
}


* This source code was highlighted with Source Code Highlighter .
void LjPlasmoid::PostPressed()
{
LjSession session;
LjRequest post(&session, recieve_responce, this );

post.AddData( "mode" , "postevent" );
post.AddData( "user" , "user_name" );
post.AddData( "password" , "user_password" );
post.AddData( "ver" , "1" );
post.AddData( "event" , m_text_edit.nativeWidget()->toPlainText().toAscii().data());
post.AddData( "lineendings" , "unix" );
post.AddData( "subject" , "[Posted via LjPlasmoid]" );
post.AddData( "security" , "public" );
post.AddData( "year" , "2009" );
post.AddData( "mon" , "11" );
post.AddData( "day" , "23" );
post.AddData( "hour" , "20" );
post.AddData( "min" , "00" );

printf( "text2send: %s\n" , m_text_edit.nativeWidget()->toPlainText().toAscii().data());

post.Post();
m_text_edit.setText( "[ok: put your text here]" );
}


* This source code was highlighted with Source Code Highlighter .
void LjPlasmoid::PostPressed()
{
LjSession session;
LjRequest post(&session, recieve_responce, this );

post.AddData( "mode" , "postevent" );
post.AddData( "user" , "user_name" );
post.AddData( "password" , "user_password" );
post.AddData( "ver" , "1" );
post.AddData( "event" , m_text_edit.nativeWidget()->toPlainText().toAscii().data());
post.AddData( "lineendings" , "unix" );
post.AddData( "subject" , "[Posted via LjPlasmoid]" );
post.AddData( "security" , "public" );
post.AddData( "year" , "2009" );
post.AddData( "mon" , "11" );
post.AddData( "day" , "23" );
post.AddData( "hour" , "20" );
post.AddData( "min" , "00" );

printf( "text2send: %s\n" , m_text_edit.nativeWidget()->toPlainText().toAscii().data());

post.Post();
m_text_edit.setText( "[ok: put your text here]" );
}


* This source code was highlighted with Source Code Highlighter .



This is just an example of how to create a plasmoid for your own needs. It is for this reason that there is no reverse error, tweaking behavior parameters, etc. However, the general and superficial idea of ​​what a Plasma is from the inside is quite capable of giving this topic.

As for this widget, the plans are as follows: bring to mind; implement a sane setting; put on the kde-look. Recently, I have been pondering the idea of ​​putting all the protocol-dependent logic into lua-scripts, thus providing extensibility and the ability to work with various blog-based platforms.

PS And most importantly: many thanks to nsinreal habraiser for an invite!

Source: https://habr.com/ru/post/76371/


All Articles