KNOW HOW SuperKaramba

Brighten up your KDE background with SuperKaramba and Python Python Goes Karamba

SuperKaramba helps you do something useful with your KDE background. Now, with just a little help from Python, you can define exactly what that extra functionality you need is going to be. BY HAGEN HÖPFNER

nce you start using Super- Snake Charming /small_text_xmms.py Karamba [2] to a add clock and If we want to use Python to add more Oan MP3 player to your KDE functionality to themes such as the one Now open the theme file, small_text_ background [1], you will probably start discussed in [1], we do not need to mod- .theme, by selecting Open… in the yearning for more. The good is that ify the existing code. Instead, we can main SuperKaramba window, to trans- you can use the Python [3] programming simply add another file to the theme late the Python source code into Python language to add a wide range of interac- directory. The file will use the same byte code (see Box 1). (If you cannot see tive features to Karamba themes. For name as the theme itself, and is recog- the hidden .superkaramba directory, in example, you can create menus, dynami- nizable by its extension, .py. The the file selection dialog, press [F8].) As cally modify texts, and add drag & drop SuperKaramba developers recommend the compiler displays error and debug- support to your themes. starting off with a template (see [6]), and ging information on the standard output The underlying idea is as follows: modifying the template. You will find the channel, it makes sense to launch When a KDE event occurs (e.g. moving sample theme at [4]. SuperKaramba manually by typing the mouse, launching a program, or Unpack the latter by entering superkaramba (you may need to specify selecting a menu item), the program the path) in an X terminal (for example responsible for this event sends out a sig- tar -C ~/.superkaramba -xjvf U ). nal that is received and interpreted by a small_text_xmms.tar.bz2 For example, a message such as My function. Of course, SuperKaramba can Python extension has been loaded!, is interpret events of this kind. The in the ~/.superkaramba directory (you caused by the following print command SuperKaramba Python API, which is may need to create the directory first). described in detail at [5], allows you to This will create a theme directory called print "My Python extension hasU specify what small_text_xmms. Now copy the tem- been loaded!" happens. plate file, template.py, to the directory. Make sure you change the name to in the last line of the template. This reflect the name of your theme: allows me to ensure that the Python file translates correctly. cp template.py ~/.superkarambaU Sadly, this was not the case with /small_text_xmmsU my Suse 9 installation. It would seem that the distribution sets some of the environment variables used by Python incorrectly. Typing the following two commands in konsole before launch- ing SuperKaramba soon sorted out the problem:

export PYTHONPATH=/usr/libU /python2.3/ export PYTHONHOME=/usr/libU /python2.3/ Drag & Drop Our first extension will be drag & drop for .mp3 files, as described in [1], that allows users to drag a file from Kon- queror to the integrated MP3 player. For

44 May 2004 www.-magazine.com SuperKaramba KNOW HOW

the time being, we want XMMS to play the files. Table 1: SuperKaramba Signal Gages Function Called when Listing 1 shows our solution. If you do initWidget(widget) A SuperKaramba widget is created. not want to develop the template file, widgetUpdated(widget) The theme is updated.The update interval is defined in the .theme file. simply overwrite small_text_xmms.py widgetClicked(widget, x, y,button) A mouse click occurs within the theme. x and y indicate the coordinates with this file. (relative to the theme) where the click occurred. button indicates the mouse To allow a SuperKaramba theme to button that was pressed. support drag & drop, the theme needs to widgetMouseMoved(widget, x, y,button) A mouse movement occurs within the theme. x and y indicate the current be initialized. The best way to do this is coordinates (relative to the theme); button provides the number of the to create a SuperKaramba widget. This button and indicates the hold status. menuItemClicked(widget, menu, id) A menu item is selected.This passes on the menu handle (see the text) and transmits a signal that is picked up by the menu item that was clicked (id). one of SuperKaramba’s “gages”, the so- menuOptionChanged(widget, key,value) An item in the theme configuration menu is selected. key provides the menu called callback function initWidget(). item handle, and value the new value (true or false). We can enter meterClicked(widget, meter,button) A display device is clicked. meter provides the handle,button the number of the mouse button pressed. def initWidget(widget): commandOutput(widget, pid, output) A program is called by executeInteractive(),provided that this causes output to stdout.pid is the process ID of the program,output contains the text out- put. to define the reaction in the next line itemDropped(widget, dropText) Objects (e.g. icons) for drag & drop operations are dropped on the theme. when we use the theme as our desktop dropText contains the text for the object (e.g. its URL, see section “Drag and background: Drop”). startupAdded(widget, startup) KDE launches a new application.When the program launch operation has karamba.acceptDrops(widget) been completed, a startupRemoved() signal follows, and is turn followed by taskAdded(). In this case, we want the widget to startupRemoved(widget, startup) See startupAdded(). accept drop events. taskAdded(widget, task) See startupAdded(). SuperKaramba uses itemDropped() to taskRemoved(widget, task) A program is terminated. handle the signal. The function expects activeTaskChanged(widget,task) Another application is moved to the foreground. two pieces of information from the drop signal, as indicated in Table 1: a pointer string.split(string.rstrip(strU we did not do this, any MP3 files that to the widget and – in the case of files – a (dropText)),"\n") contained the file: string, would be multiple-line list of filenames in the hacked to pieces. The result is a list with dropText variable, where each line repre- We are using the newline character \n as two entries, which we store in another sents a file. a separator. The innermost function, variable, temp. The first element, Unfortunately, each filename is pre- str(), allows the content of dropText to temp[0], contains only an empty string ceded by the file: keyword. As XMMS be handled as a string, while after the first split operation. cannot handle full URLs of the string.rstrip() removes any non-standard For each iteration of the loop, we file:/path/to/file.mp3 type, but expects a characters from the right. append the filename to the existing con- filename like /path/to/file.mp3, we need Now we have the individual URLs, we tent of the xmms_filename variable. As to strip the superfluous data from drop- can use a for loop to remove the file: pre- the filename is the second element in the Text before passing it on to the media fixes. We will write the URLs to the temp list, we can access the name as player. filename variable one by one, and then temp[1]: call Stripping xmms_filename=xmms_filename + U We will need string manipulation func- string.split(U " \"" + string.rstrip(U tions [7] from import string. The next filename, "file:", 1) temp[1]) + "\"" is to define an empty variable xmms_filename=”” where we can store to remove the file: prefix from the file- To allow XMMS to play MP3s with the stripped filename list. We can then name. To be more precise, we split the spaces in their filenames, we need to call string.split() to split the URL list content of filename into two parts at the enclose the filenames in quotes. As from dropText into its URL components: first (1) instance of the file: separator. If Python also uses quotes, ”, to separate GLOSSARY

API: An Application Programming Interface Stdout: The standard output channel speci- also points to the screen, and a stdin channel defines a number of functions within a soft- fies where Linux applications should send for input, which typically points to the key- ware that other programs written in a specific their text output.This is typically the screen, board. language can call. In our case, Python applica- but you can redirect standard output to a file Widget: A generic term for the control ele- tions can use the functions implemented in or a printer. In addition to stdout, Linux also ments of a graphical interface.These include SuperKaramba. has a stderror channel for error output that windows, buttons, menus, checklists, and tabs.

www.linux-magazine.com May 2004 45 KNOW HOW SuperKaramba

tem is now stored in the global variable Listing 1: The theme supports drag & drop selectmenu. This is referred to as a han- 01 import karamba dle, as the number is used to identify the 02 import string menu internally. The following, some- 03 what lengthy construct stores a menu 04 def initWidget(widget): with two items in my_menu. The first of 05 karamba.acceptDrops(widget) these … 06 07 def itemDropped(widget, dropText): karamba.addMenuItem(widget, U 08 xmms_filename="" selectmenu, "", U 09 for filename in string.split(string.rstrip(str(dropText)),"\n"): "konqueror.png") 10 temp=string.split(filename, "file:", 1) 11 xmms_filename=xmms_filename + " \"" + string.rstrip(temp[1]) … creates an entry for konqueror in + "\"" selectmenu. The konqueror.png icon, 12 karamba.execute("xmms" + xmms_filename) which also has to be stored in the theme 13 directory, completes the menu item. The 14 print "My Python extension has been loaded!" second addMenuItem() does the same thing for an opera entry: strings, we have to escape the string IDs assigned to them. using ”\””, a fairly complex procedure. If In response to the theme window karamba.addMenuItem(widget, U xmms_filename actually includes opening, initWidget() adds a menu to selectmenu, "opera", U quotes, escaping them with \ tells XMMS the theme: "opera.png") that the ” is to be taken literally. After storing the file list in xmms_file- selectmenu=U Of course, the functionality is missing at name, we can use karamba.createMenu(widget) this point. To allow us to assign function- ality to the appropriate menu items, we karamba.execute("xmms"U The internal number assigned by the sys- need a method to distinguish the individ- + xmms_filename) Listing 2: Menu-Based Interaction to tell XMMS to call the filename of the 01 import karamba “dropped” MP3 file. 02 03 selectmenu=0 The Menu, Please 04 my_menu=[[],[]] Adding another menu to supplement the 05 generic right-click drop-down is another 06 def initWidget(widget): neat way of enhancing a theme. This 07 global selectmenu could be a quick launch menu that pops 08 global my_menu up when you double-click with the left 09 selectmenu=karamba.createMenu(widget) or center mouse button, and allows you 10 my_menu=[ to launch external applications. As it 11 "konqueror", karamba.addMenuItem(widget, selectmenu, "konqueror", would be inelegant to define an infinite "konqueror.png")], number of clickable areas in the .theme 12 ["opera", karamba.addMenuItem(widget, selectmenu, "opera", file, we want to use the Python API for "opera.png")] this task. 13 To quickly try this one out, replace the 14 def widgetClicked(widget, x, y, button): contents of the ~/.superkaramba/small_ 15 global selectmenu text_xmms/small_text_xmms.py file with 16 karamba.popupMenu(widget, selectmenu, x, y) the instructions in Listing 2. My apolo- 17 gies to professional developers for the 18 def menuItemClicked(widget, menu, id): hack with the global variables, select- 19 global my_menu menu and my_menu, which I used here 20 for index in my_menu: to keep things simple. 21 if index[1] == id: selectmenu is initially 0 and will repre- 22 if index[0] == 'konqueror': sent the object ID of the menu later. 23 karamba.execute("konqueror") my_menu=[[],[]] creates a storage 24 elif index[0] == 'opera': framework for a two element list. The 25 karamba.execute("opera") 26 list will be used later within the Python 27 print "My Python extension has been loaded!" program to map the menu items to the

46 May 2004 www.linux-magazine.com SuperKaramba KNOW HOW

We will not be evaluating the x-y When a user selects a menu item, coordinates and the mouse button SuperKaramba responds with menuItem- number in button, but if we did, we Clicked(widget, menu, id). This function could handle different areas within the uses id to provide the handle for the theme differently, or distinguish between menu item, and menu to provide the left and center mouse buttons. We could appropriate menu. As the system assigns map the right mouse button, but as handles arbitrarily, there is no real way right-clicking the SuperKaramba theme opens the SuperKaramba menu, this is GLOSSARY only a theoretical option. Global variable: The object orientied pro- Figure 1: Python creating menus. Note that mouse clicks will always gramming paradigm tends to encapsulate perform the action defined in the .theme functions and variables in objects. For exam- ual items. We can store konqueror or file. In our case, this means that clicking ple, assigning a variable for the button color, makes it easy to create multiple buttons with opera with the handle created by the the clock will open both the clock setting different colors, as the variable is stored in the addMenuItem() item in my_menu. The tool and the menu (see Figure 1). “button”object. In contrast, global variables content of the variables looks like this, To display the latter on screen, we are visible throughout the program. If you depending on the handle: need the handle, which is stored in the then assign the color green as the button selectmenu variable. We can use global color,any buttons you create will be green. Multithreaded: Programs are not normally (['konqueror', -22], U selectmenu to retrieve this from the capable of performing more than one action ['opera', -23]) global data space. The karamba.popup- at a certain time. For example, while a pro- Menu(widget, selectmenu, x, y) function gram is waiting for a file to open, it cannot We now have a menu. Of course it won’t allows us to pop up the menu at the perform any other activities.Threads allow a be displayed immediately, but when the same coordinates (x, y) as the click. If program to perform multiple tasks simulta- neously.Instead of sitting around waiting for SuperKaramba theme is double-clicked; these coordinates are missing, the menu file to open, a multithreaded program would that is, whenever a widgetClicked(wid- pops up in the top left-hand corner (0,0) assign the wait time to another thread. get, x, y, button) signal is generated. of the theme. Linux Apache PHP hosting Home Pro account FREE World class support Email virus scanning, web mail, SMS email alerts and 1 GB INSTANT SET-UP of web space on reliable, Linux servers, make this the ideal that never closes account for great value and great features. With support for . 99 £Monthly 8 +VAT or Every Fasthosts customer enjoys full access to Perl, PHP and CGI and optional MySQL databases, Home Pro £70 annually Xtreme Support: unsurpassed customer service, gives you everything you need to create high spec, feature All your hosting needs faster turnaround for technical problems and an rich websites. unparalleled level of help and advice. • Business packages from £14.99 • Developer packages from £19.99 • 24 x 7, 365 days telephone, email & online support Also includes: • Matrix Stats - real time data on visits to your site • Unlimited Reseller package from £50 • Xtreme Support website - with knowledge base, FAQs and more • 300 POP3 email and forwarding addresses • Dedicated server solutions from £89 • Trouble ticket system for a fast accurate technical response • Easy to use website builder • UK's best value domain names at www.ukreg.com With multiple internet connections and our advanced • Access to URL security, streaming media and much more UK data centre, it's no wonder we're known as • Manage everything from the web with our award 'the power behind web hosting'. winning control panel

For instant advice and set up, call 0870 888 3631 or for more details and to launch your service within minutes, visit www.fasthosts.co.uk KNOW HOW SuperKaramba

to guess them, but we got around this by …, we will launch Konqueror by calling API provides a number of additional storing them in global variables: karamba.execute(“konqueror”); if not, functions, which are documented at [5], my_menu for the menu items, and select- we use there are a few issues with the API. The menu for the menu itself. As we only biggest issue is the fact that it cannot have one menu, we do not need to han- elif index[0] == 'opera': handle dynamic sensors (see [1]). If we dle this distinction. In other words, we wanted to add a feature to our theme to only need main_menu from the global to check if Opera has been clicked. support switching between various sen- data space. If we merge the functions from List- sors, we would be able to click to update for index in my_menu: allows us to ings 1 and 2 to create a single file, we the text content, but we would be unable iterate through the elements in the can omit a few lines. For example, we to swap the underlying sensor display. my_menu variable and map the lists it only need one instance of import There is another problem here. Python contains to the index variable one by karamba at the beginning and one print can only access elements it created itself. one. During each iteration, we need to statement at the end of the file. Also, we If you intend to use a text element to tog- check whether the menu item handle need to merge the content of the “def gle a function, you need to create it with passed by the signal matches the num- initWidget(widget):” blocks to create a the Python createText() function. Texts ber stored in the second item of index: single block. If one of the functions is defined by the .theme file cannot be missing after you reload the theme, manipulated using the Python API. ■ if index[1] == id: delete the .pyc file, which is automati- cally created in your theme directory. INFO After finding the my_menu pair that cor- [1] Introduction to SuperKaramba:Hagen responds to the menu item that was The Borders of the Snake Höpfner,“Karamba on the Desktop”, clicked, we need to check which browser Kingdom Linux Magazine Issue 41 entry it belongs to. If it is Konqueror … Although it is amazingly simple to han- [2] SuperKaramba: dle such complex tasks as drag & drop in http://netdragon.sourceforge.net/ if index[0] == 'konqueror': SuperKaramba, and although the Python [3] First steps with Python: http://www.python.org/doc/Intros.html Box 1: What is Python? [4] Sample theme: If you already speak another programming condition is terminated with a fi.Pascal uses http://wwwiti.cs.uni-magdeburg.de/ language, you might not be too thrilled the begin and end keywords. Python does ~hoepfner/download.html about the prospect of having to learn a new not use any of these methods:instead of a [5] SuperKaramba Python API documenta- language just to keep SuperKaramba happy. tag,you simply indent a block of contiguous tion:http://netdragon.sourceforge.net/ But for newcomers to programming, Python statements. api.html has a few advantages,being a universal Thus, two successive lines with the same [6] SuperKaramba Python template:http:// language. One of the main reasons for this degree of indenting,form a block. If the netdragon.sourceforge.net/template.py is the fact that Python combines three second line starts farther to the left than major programming paradigms in one. the first line, it does not belong to the [7] Python string manipulation functions: Python can be used as an object oriented block. A colon introduces a new level, as http://www.python.org/doc/2.3.3/lib/ language, just like C++ or Java, or as a pro- the listings show. Lines with the same module-string.html cedural language like Pascal or C. At the degree of indenting that follow a def line, [8] Loops and conditions in Python: same time it is a scripting language like PHP belong to the definition of this function. http://www.python.org/doc/2.3.3/ref/ or Perl, which does not need to be compiled Unfortunately,Python needs at least one compound.html by the user. It supports multiple inheritance, function per level.This is why the template can interface with databases and access net- [9] Python Library Reference:http://www. file has a pass function instead of an empty python.org/doc/2.3.3/lib/lib.html work protocols, and also supports block.This function does not perform an multithreaded programming. operation when the program is executed; it Just like Java, Python source code is first is simply a placeholder that allows us to pop- Hagen Höpfner has a converted to byte code by a compiler.This ulate the level as required. higher degree in code shows up in the SuperKaramba theme On the one hand, the indenting trick ensures Computer Science directory as an automatically generated file that Python code is always neatly structured and is a member of with the .pyc suffix.The code is executed by and easy to read in contrast to code in other scientific staff at the a virtual machine. Python is far quicker than programming languages. But it can drive Otto-von-Guericke Java byte code. newcomers to distraction because a University of Magde- If you move to Python from another pro- function with the wrong level of indenting burg, Germany.Between time spent gramming language, there is one thing you simply drops out of the context of the block tinkering with his collection of Linux will need to get used to: the definition of where it should reside. Be aware of this computers, Hagen likes to direct his contiguous blocks. Blocks are used to define pitfall while experimenting with the THEHOR AUT the statements that will be executed if a examples and creating your own extensions. creative energy into song-writing, particular condition is fulfilled. C uses curly And make sure you use the right level of composing lyrics, and playing the gui- brackets for this,and in programming indenting! tar for a rock band called “Gute Frage with Bash, the statement block of an if-then !?”(translates “Good Question”).

48 May 2004 www.linux-magazine.com