Revision as of 20:37, 29 June 2011

Abstract

This tutorial will explain how to make simple KDE Plasma applet using Ruby. The applet will be a simple version of the paste applet. It will allow the user to put a bit of text on the clipboard.

Getting started

Before you get started you need to make sure to have the following installed on your computer.

KDE 4.2 or later

Ruby 1.8

KDE Ruby bindings and Plasma scriptengine

These packages can usually be installed through your distributions package manager.

Package layout

Plasma applets written in Ruby can be distributed as a plasmoid package. A minimal Ruby plasmoid package has the following structure:

contents/

code/

main.rb

metadata.desktop

The Ruby code for the plasmoid should be put in a file called main.rb in the contents/code folder of your package. The metadata.desktop file holds metadata about your plasmoid. This includes your name, name of your applet and a description. The metadata.desktop file is in the common .desktop file format, which looks a lot like an old INI file.

A minimal metadata.desktop file looks like this:

[Desktop Entry]Name=Simple Ruby appletComment=This is a simple applet written in RubyIcon=chronometerType=ServiceServiceTypes=Plasma/AppletX-Plasma-API=ruby-scriptX-Plasma-MainScript=code/main.rbX-KDE-PluginInfo-Author=MeX-KDE-PluginInfo-Email=me@example.comX-KDE-PluginInfo-Name=ruby-testX-KDE-PluginInfo-Version=0.1X-KDE-PluginInfo-Website=http://plasma.kde.org/X-KDE-PluginInfo-Category=ExamplesX-KDE-PluginInfo-Depends=X-KDE-PluginInfo-License=GPLX-KDE-PluginInfo-EnabledByDefault=true</code>== Code ==Let'sfirststartwiththemostbasicRubyappletandworkfromthere.EveryPlasmaappletyou'regoingtomakeinRubyhastohaveaclasswhichinheritsthe<tt>PlasmaScripting::Applet</tt>class.Youcanthinkofthisasyourmainclassforyourapplet.Itwillalwayshaveatleasttwomethods,<tt>initialize</tt>and<tt>init</tt>.Whilethesetwoseemverysimilar,thereisanimportantdifference.The<tt>initialize</tt>methodisRuby'sdefaultconstructor.ItwillbecalledbytheRubyinterpreterwhenanobjectofyourclassgetsinitialized(a.k.a.constructed).The<tt>init</tt>methodgetscalledbyPlasma.Plasmacallsthismethodaftertheapplethasbeenloaded.Youcanthereforeassumethateverythingissetupwhen<tt>init</tt>iscalled,whilewithinitialize,youonlyknowyourappletclassisready.Startyourcodefilewithrequiring'plasma_applet'andopeningamodule.AminimalRubyPlasmaappletlookslikethis:<coderuby>require'plasma_applet'moduleRubyTestclassMain<PlasmaScripting::Appletdefinitializeparentsuperparentenddefinitset_minimum_size150,150endendend</code>Themodulenamemustmatchthenameyouspecifyinmetadata.desktoponthe<tt>X-KDE-PluginInfo-Name</tt>line.Thename<tt>ruby-test</tt>translatestoamodulenameof<tt>RubyTest</tt>.Theonlylineinthe<tt>init</tt>methodnowis<tt>set_minimum_size</tt>.This,asthenamesuggests,setstheminimumsizefortheapplet.Torunyourapplet,youhavetwooptions.Youcaninstallitfirst,andthenrunit.Or,ifyou'rerunningKDE4.3orlater,justrunit.== Installing your appliet ==Thisiswhere<tt>plasmapkg</tt>comesin.It'sasmalltoolwhichinstallsandupgradesPlasmapackages.Toputyourcodeinapackage,createapackagestructureasdescribedintheabovesection.Outsidethepackagefolderrun<tt>plasmapkg-i<packagefoldername></tt>,<tt>plasmapkg</tt>willnowinstallyourapplet.<codebash>mkdirruby-test-appletcdruby-test-applet# Copy or create metadata.desktopmkdircontentscdcontentsmkdircodecdcode# Copy or create main.rbcd../../..plasmapkg-iruby-test-applet</code><tt>plasmapkg</tt>caninstallandupgradePlasmapackages.Sinceyou'venowinstalledyourapplet,youneedtoupgradeitaftermakingchanges.Thisisn'tmuchdifferenttheninstalling,justusethe<tt>-u</tt>commandlineswitchinsteadof<tt>-i</tt>.== Running your applet ==Youcanrunyourappletusingatoolcalled<tt>plasmoidviewer</tt>.=== KDE 4.2 ===InKDE4.2<tt>plasmoidviewer</tt>takesthenameofaninstalledappletasaparameter.Thenameofyourappletisspecifiedwiththe<tt>X-KDE-PluginInfo-Name</tt>lineinyour<tt>metadata.desktop</tt>file.Youshouldbeabletoviewyourappletafterinstallingit.<codebash>plasmoidviewerruby-test</code>=== KDE 4.3 ===InKDE4.3plasmoidviewerstillacceptsthenameofaninstalledappletasaparameter.Butitcanalsorunwithoutaparameter.Itwillthentrytorunaplasmoidfromthecurrentdirectory.Inorderforthistowork,thecurrentdirectoryshouldhavethe<tt>metadata.desktop</tt>file,thecontentsfolderandthenameofthedirectoryshouldexactlymatchthenameoftheappletasspecifiedinmetadata.desktop.<codebash>plasmoidviewer</code>== A label on an applet ==Whenyouhaveaverybasicappletrunning,youcangotwoways.YoucanputQWidgetsonyourapplet,ordrawtheappletyourselfbyimplementingthe<tt>paintInterface</tt>method.Iliketousestandardwidgetsmostofthetime,sowe'regoingtoplacesomeQWidgetsontheplasmaapplet.Plasmahasacoupleofthemedwidgets.Alistcanbefoundinthe[http://api.kde.org/4.x-api/kdelibs-apidocs/plasma/html/hierarchy.htmlPlasmaAPI].Toplacethesewidgetsonyourapplet,youneedalayout.Thelayoutyou'llbeusingmostofthetimewillbethe<tt>GraphicsLinearLayout</tt>,whichbasicallyputsyourwidgetsinahorizontalorverticalline.Whenputtinga<tt>Plasma::Label</tt>onanappletina<tt>GraphicsLinearLayout</tt>,you'llgetthefollowingcode:<coderuby>require'plasma_applet'moduleRubyTestclassMain<PlasmaScripting::Appletdefinitializeparentsuperparentenddefinitset_minimum_size150,150label=Plasma::Label.new self label.text = 'This is a label on a plasmoid, hello Plasma!'layout=Qt::GraphicsLinearLayout.new self self.layout = layout layout.add_item label end endend</code>Inthe<tt>init</tt>methodwecreatea<tt>Plasma::Label</tt>andassignitatext.Thefirstargumenttotheconstructorof<tt>Plasma::Label</tt>(the<tt>new</tt>)istheparentofthelabel,inthiscaseourapplet.Nextwecreatea<tt>GraphicsLinearLayout</tt>,assignittotheappletandputourlabelonit.{{tip|InRuby,instancevariablesalwaysbeginwithan'@'character.Allvariableswithoutan'@'arelocalvariables.Variableswithtwo@signsareclass(a.k.a.static)variables.}}{{tip|TheRubykeyword<tt>self</tt>isareferencetothecurrentinstanceoftheclassyou'rein.Youcancompareitwiththe<tt>this</tt>keywordinotherlanguageslikeC++andJava.}}Toviewyourapplet,run<tt>plasmapkg-u<foldername></tt>and<tt>plasmoidviewer<plasmoidname></tt>.<codebash>plasmapkg-uruby-test-appletplasmoidviewerruby-test</code>ThiswillshowyouaniceandsimpleHelloWorldinPlasma.== A line edit and a button ==Let'scontinuebyaddingalineeditandabuttonwithsomefunctionality.Toaddalineeditwidgetwecanusethe<tt>Plasma::LineEdit</tt>class.Thisclassisabasic<tt>KLineEdit</tt>(atextfieldwithoneline)themedforPlasma.Toaddittoourapplet,wedothesameaswiththelabel.Butsincewewantthelineedittobeempty,wedon'tsetatext.Nextisapushbutton.Wecanusethe<tt>Plasma::PushButton</tt>classforthat.Addingitisexactlythesameasaddingthelabel.Withalineeditandbuttoninplace,weshouldletthebuttondosomethingwhenit'sclicked.Qt,thelibraryonwhichKDEisbased,usesamechanismcalled'signalsandslots'.Youcouldcompareittoactionoreventhandlersinotherlanguagesorframeworks.Normally,onewouldconnectacertainsignal(event)toacertainslot(eventhandlermethod).Sincewe'reusingRuby,wecan'tonlydothat,wecanconnectasignaltoacodeblock.Thesyntaxforthisiseasy:<coderuby>button.connect(SIGNAL(:clicked))do# do somethingend</code>Now,whenthebuttongetsclicked,thecodeintheblockgetsexecuted.{{tip|TheRubylanguagehastheconceptofcodeblocks.Theseareanonymousfunctionswhichyoucansupplytoamethod.Acodeblockgetsexecutedwhenthereceivingmethodcallsit.}}We will do something simple when the button gets pressed. Qt makes it very easy to put some text on the clipboard, so let's do that. To put text on the clipboard we need <tt>Qt::Application.clipboard</tt>. This object has the very convenient method <tt>text=</tt> which puts text on the clipboard.Puttingitalltogether,wehavetofollowingcode:<coderuby>require'plasma_applet'moduleRubyTestclassMain<PlasmaScripting::Appletdefinitializeparentsuperparentenddefinitset_minimum_size150,150layout=Qt::GraphicsLinearLayout.new Qt::Vertical, self self.layout = layoutlabel=Plasma::Label.new self label.text = 'This plasmoid will copy the text you enter below to the clipboard.' layout.add_item labelline_edit=Plasma::LineEdit.new self layout.add_item line_editbutton=Plasma::PushButton.new self button.text = 'Copy to clipboard' layout.add_item buttonbutton.connect(SIGNAL(:clicked))doQt::Application.clipboard.text=line_edit.text end endendend</code>== Reading API reference documentation ==NowthatyouhavethissimplebutworkingRubyPlasmaapplet,youcanexpandit.YoucanstartbytryingoutsomeoftheotherPlasmawidgetsavailable.Theofficial[http://api.kde.org/4.x-api/kdelibs-apidocs/plasma/html/hierarchy.htmlPlasmaAPI]isunfortunatelywrittenforC++.Butwithalittleimaginationandsomelogicyoushouldbeabletomakeuseofit.Stillreadingthistutorial?Let'stakeitstepbystepthen.LookthroughthePlasmaAPIhierachyandfindtheLineEditclass.AtthetopofitsownpageisalistingoftheavailableSignals.Duplicatethecodeforthebuttonsignalinyourtexteditor:<coderuby>button.connect(SIGNAL(:clicked))doQt::Application.clipboard.text=line_edit.textendbutton.connect(SIGNAL(:clicked))doQt::Application.clipboard.text=line_edit.textend</code>Andnowreusethatcodeblocktomakeyourlineeditvariablealsopastethetypedcontenttotheclipboardwhenthereturnkeyonthekeyboardisbeingpressed.Saveandrunyourcode(inKDE4.2youmustnotforgettoupdatemanualy,inKDE4.3youcanrun'Plasmoidviewer'whenKonsoleispointingtothefolder/directoryofyourApplet).Myclipboardmissedafewpastesbutboththebuttonandpressingreturnworked.LookabitlowerontheClasspageforLineEdit:theC++codetosignalanactionlooksdifferentthentheRubysignalyoucopiedandtheRubysignalyoucomposedyourself,butitdoeslistinwhichKDEversionthesignalhasbecomeavailable.NowyouknowhowtoletyourPlasmaAppletreacttoanysignalandyouknowhowtofindallavailablesignalsinPlasma.== Enabling Public Member Functions ==ThesecondlistatthetopofthelineEditclasspageoftheAPIreferencedocumentationnamesallthePublicMemberFunctions.Thesearetheextrafeatureswhichwecanusefortheline_editclass.Anicelookingfeatureistheclearbutton,whichcanappearwhensometextistypedandwhenclickedwiththemousepointerclearsthetext,sotheuserofyourwidgetcantypesomethingdifferent.ThepagementionstwofunctionsrelatedtotheclearbuttonforC++programmers.InRubyhoweverthefunctionsarecleanlyunitedbytheRubyQtbindings.Sorememberyoumustdropboth'''is'''and'''set'''fromthefunctiontomakeitaRubymethod.Theclasspagealsosaysthatthisfunctionusesonlya'''true'''or'''false'''booleanparameter,indicatedontheclasspagebytheword"'''bool'''".Toenabletheclearbuttonfeaturewemustinserttheparametertruewithfollowingcode:<coderuby>line_edit.clear_button_shown=true</code>Notice that the Ruby Qt bindings allows us to use underscores which increases the readability of all methods for non-native English speakers. So "setClearButtonShown (bool show)" becomes either "clear_button_shown=true" or clear_button_shown = false". Also remember that when scrolling down the class page it states that this feature only works in Plasma version 4.3 or later. This means that on earlier versions your plasmoid application will suddenly not run at all and give an error. For optional features not available in earlier versions of Plasma we should always tell the applet not to run the code when it gives an error. So now we will place the line inside a rescue operation which does nothing but skip the code when it gives an error:<coderuby>beginline_edit.clear_button_shown=truerescueend</code>{{tip|Rubyexceptionhandlingallowsyoutodosomethingelsewhenablockofcodegivesanerrororjustskipthecodeblockcompletely.Itworkslikethis:<coderuby>begin# the piece of code which may error # when the program is usedrescue# the optional piece of code which you # want to run when an error has occuredend</code>}}Alsodon'tforgettoplacesomecommentsinyourcodesoyou(andothers)canunderstandwhycodeblocksareneededandwhattheyareusedfor.Youwillnotbeabletorememberwhyyouwrotemostcodeblocks,butyouwillbeabletoseethelogicwheneachreasonisgiven.Hopefullyyourexpandedcodeworksasexpected.Ifyoucan'tfindoutwhyitdoesn'trunthencompareitto[http://techbase.kde.org/Development/Tutorials/Plasma/Ruby/SimplePasteAppletCompletedthis]finishedandcommentedappletcode.== Learning all about Ruby ==NowthatyouknowhowtosetupabasicplasmoidinRubyandlearnedhowtoresearchfeaturesseeninotherplasmoidsandexpandyourownplasmoid,itistimetolearnallaboutRubyitself.ForthisyoucanuseothertutorialswhichteachyounothingbutRuby.Thesewillexplainwhyyouhavebeendoingthingsthewaytheyaredescribedabove.Theywillhaveexampleapplicationsusingtextinput,anditisyourtasktomakesuchexamplesintoplasmoidswithline_editwidgetsandbuttonswhichreset,advanceordootherstuffwithyoursamplecode.Onlywhenyoucanrewriteyourcodeyourselfwillyouhavebecomeaprogrammer.MyfavoriteRubytutorialis:[http://pine.fm/LearnToProgram/LearnToProgram].Youcouldalsotrylookingatsome[http://websvn.kde.org/trunk/KDE/kdeexamples/plasma/ruby/RubyPlasmaexamples].Thesearewrittenabitdifferentthentheexampledescribedabove,buttheyshouldstillbeuseful.IfyouhaveanyquestionsaboutPlasmadevelopmentthereareseveralwaystoaskforhelp.Firstofallthereisthe[https://mail.kde.org/mailman/listinfo/plasma-develPlasmamailinglist].SecondlyyoucanhopbyonIRC,#plasma on irc.freenode.org. As a third option you could try asking you question on the [http://forum.kde.org/ KDE forums].Goodluck,anddon'tforgettopublishyourPlasmaappletonkde-look.org!