Pull to refresh

KDE4 Plasma Desktop. Простой плазмоид своими руками

Reading time7 min
Views2.6K
imageНачиная с версии 4.x, на смену проверенных с годами, но морально устаревших (по этому поводу, конечно, мнения могут и разделиться) KDesktop, Kicker и SuperKaramba в KDE пришел Plasma Desktop. Этот фреймворк представляет рабочий стол (по крайней мере, его видимую часть), как совокупность виджетов или плазмоидов. Обзаведясь в один прекрасный момент некоторым количеством свободного времени, я решил немного разобраться с Plasma SDK, реализовав функцию, которой на тот момент мне действительно не хватало в составе моего рабочего стола. А функция эта — возможность без привлечения дополнительных приложений отправлять записи в LiveJournal. То есть этакий миниклиент, встроенный прямо в десктоп. «Было бы здорово», — подумал я и принялся ворошить интересующую предметную область.

Для того, чтобы осуществить все, что описано далее, в системе должны присутствовать, собственно, KDE4, а также следующие установленные пакеты: kdesdk, kdebase-devel, kdelibs-devel, cmake. В зависимости от дистрибутива, пакеты могут иметь немного другие названия (я привожу имена для Fedora Core), но общий смысл, думаю, ясен.

Начнем с того, что плазмоиды бывают бинарные и скриптовые. Особо не раздумывая, я решил использовать близкие сердцу «плюсы» и создавать, соответсвенно, бинарный виджет, который представляет из себя .so (shared object) модуль, то есть динамически загружаемую библиотеку. Элементарный каркас должен выглядеть примерно так:

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



Все вполне очевидно: конструктор, деструктор, инициализация и отрисовка интерфейса. Ничего сложного. Почти пустая реализация:

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



Сохранив все это, я принялся собирать свой плазмоид, чтобы безотлагательно убедиться, что что мой виджет, отрисовывает пустую область в красивой рамке. Для этого помимо самого модуля необходим .desktop файл следующего содержания:

[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


Внимание здесь следует обратить на то, что значение поля X-KDE-PluginInfo-Name должно совпадать с первым параметром макроса K_EXPORT_PLASMA_APPLEТ. Далее сам модуль необходимо скопировать в папку с библиотеками KDE4 (для большинства случаев это '/usr/lib/kde4', либо в случае x86_64 сборки '/usr/lib64/kde4'), а .desktop файл следует отправить по адресу '/usr/share/kde4/services'. Ну и финальным штрихом нам нужно заставить плазму перечитать свои данные, чтоб вновь созданный виджет появился в списке доступных. Делается это путем выполнения смешной команды 'kbuildsycoca4'.

Есть два способа увидеть плазмоид в действии: добавить его непосредственно на рабочий стол, либо использовать утилиту 'plasmoidviewer', которая покажет виджет в отедельном окне. Однако мне не помог ни тот, ни другой. Вместо своего «детища» я упорно взирал на сообщение об ощибке, которое утверждало, что объект с именем 'ljplasmoid' ну никак не может быть создан.

Попытки локализовать проблему протекали долго и мучительно. В ход пошли все средства, вплоть до прекрасной утилиты 'strace', с помощью которого я пытался определить, обращается ли процесс 'plasma-desktop' к моего бинарному модулю. Оказалось, таки да, обращается, но толку от этого было мало — ошибка упорно продолжала проявляться. В самую последнюю очередь через несколько часов топтания на одном и том же месте я стал подозревать, что проблема возможно кроется в сборке (для редактирования исходного кода и сборки я использовал IDE CodeBlocks). Отчаявшись решить проблему иным способом, я решил попробовать использовать для компиляции предлагаемый на сайте KDE cmake-script. Вот он c минимальными изменениями:

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})


Для сборки с использованием утилиты 'cmake' нужно выполнить команду 'cmake -G«Unix Makefiles» && make' в папке, где находится файл CMakeLists.txt (в нем и содержится сам скрипт). По не совсем пока ясным для меня причинам смена метода компиляции принесла плоды — плазмоид заработал! Появившийся на рабочем столе полупрозрачный пустой прямоугольник помимо неописуемой радости, вызвал во мне сильнейший приступ энтузиазма, и я принялся продолжать начатое. Единственное, что омрачало мое удовольствие при такой модели разработки — это отсутствие единой IDE и как следствие необходимость постоянно переключаться между терминалом и редактором. Но и тут выход был найден довольно быстро. Среда разработки KDevelop и ее встроенный шаблон проекта 'CMake-based project' быстро решили все мои проблемы.

Дальше дело техники — добавить элементы пользовательского интерфейса (мне всего-то нужно поле для ввода и кнопка «Отправить»). Плазма использует Qt, хотя по факту приходится подключать классы, которые являются обвязками над Qt-шными. Итого у нас появляется несколько новых include'ов и объявлений в классе:

...

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



Ну, и, естественн, о реализация становится при этом чуть более осмысленной:

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.



Таким образом у меня получился ничего не умеющий, но обладающий простенькой «мордочкой» виджет:

image

Для работы непосредственно с LiveJournal использовался API, описанный на официальном сайте, а также написанный мной для этих целей простой набор классов, использующий 'libcurl'. Исходники данного класса я публиковать не буду, поскольку они выходят за тему топика, но заинтересовавшиеся могут скачать их здесь.

Итак, остается реализоваться последний метод — отправку сообщения в журнал:

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.



Это всего лишь пример того, как создать плазмоид для своих собственных нужд. Именно по этой причине здесь нет обратки ошибок, тонкой настройки параметров поведения и т.д. Однако, общее и самое поверхностное представление о том, что что такое Plasma изнутри, этот топик дать вполне способен.

Что касается данного виджета, то планы следующие: довести до ума; реализовать вменяемую настройку; выложить на KDE-Look. С недавних пор обдумываю идею вынести всю протоколо-зависисую логику в lua-скрипты, обеспечив тем самым расширяемость и возможность работать с различными блог-платформами.

P. S. И самое главное: огромное спасибо хабраюзеру nsinreal за инвайт!
Tags:
Hubs:
Total votes 21: ↑17 and ↓4+13
Comments6

Articles