Getting new mail onto the desktop
I had nice last weekend gathering new harvest of apples, drinking fresh apple juice and playing with SuperKaramba widgets – a good opportunity to take a sort of “recreational programming”. Perhaps all modern KDE users know those nice resource eaters eye-candies which are living right on the desktop surface and displaying the clocks, calendars, weather forecasts, system monitors and so on.
Instead of developing some Yet Another Big Animated Clock, I decided to write something practical. What I’d like to have is a widget which would ask my e-mail client (KMail) for the headers of the latest unread messages to show them on the desktop.

Two buttons in the top bar are for checking new mail from a server and for opening new message window. Clicking on the top bar somewhere else will open main KMail window.
SuperKaramba comes with a Python API, so everyone who is familiar with Pyton basics can write her own widget (aka “theme”) as a Python script. In my case, I wrote two scripts – one is for widget output and another as a simple KMail folder API wrapped around DCOP calls.
Patching KMail
There was a major problem – KMail DCOP interface had no a call to get unread message headers; only getting a number of them is possible. So I have had to dig into the KMail sourcecode (my current version is 1.9.4) for to add new function to FolderIFace interface (folderIface.cpp).
kmail.diff:
diff kmail/folderIface.cpp kmail_patched/folderIface.cpp
147a148,162
> QStringList
> FolderIface::unreadMessageHeaders()
> {
> QStringList msgs;
> mFolder->open();
> for( int i = 0; i < mFolder->count(); i++) {
> KMMsgBase *msg = mFolder->getMsgBase(i);
> if (msg->isNew() || msg->isUnread()) {
> msgs.append(msg->fromStrip() + "\\t" + msg->subject() + "\\t" + msg->dateStr());
> }
> }
> mFolder->close();
> return msgs;
> }
>
diff kmail/folderIface.h kmail_patched/folderIface.h
61c61,62
<
---
> virtual QStringList unreadMessageHeaders();
>
After adding new function header to folderIface.h and rebuilding KMail, new DCOP call “kmail FolderIface unreadMessageHeaders” became available to get the list of message headers in format “From/Subject/Date” divided by tab characters (\t).
Sourcecode
skkmail.py:
import karamba
import kmail
text = []
images = []
clickAreas = []
# Define widget area width here (height is adjusted automatically)
s_width = 350
# If an actual height is above this value, a widget area will be clipped
maxHeight = 600
# Margins inside a widget area
s_x = 10
s_y = 10
def _update(widget):
global text, images, clickAreas, s_width, s_x, s_y
x_gap = 10
y_gap = 4
s_height = 14
s_col1 = (s_width-x_gap)*0.66
s_col2 = s_width
s_col3 = (s_width-x_gap-16)*0.33
folderFont = "Franklin Gothic Medium"
folderFontSize = 14
for t in text:
try:
karamba.deleteText(widget, t)
except:
pass
for i in images:
try:
karamba.deleteImage(widget, i)
except:
pass
for c in clickAreas:
try:
karamba.removeClickArea(widget, c)
except:
pass
text = []
images = []
clickAreas = []
folders = kmail.getFolders()
y = s_y + 25;
for f in folders:
msgs = f.unreadMessages
if (len(msgs) > 0):
y0 = y
t = karamba.createText(widget, s_x+15, y, s_width, s_height,
f.name+" ("+str(len(msgs))+")")
karamba.changeTextFont(widget, t, folderFont)
karamba.changeTextSize(widget, t, folderFontSize)
text.append(t)
images.append(karamba.createImage(widget, s_x-10, y, "icons/folder.png"))
y = y + s_height + y_gap*2 +10
for m in msgs:
t = karamba.createText(widget, s_x+20, y, s_col1, s_height, m[0])
text.append(t)
t = karamba.createText(widget, s_x, y+s_height, s_col2, s_height, m[1])
text.append(t)
t = karamba.createText(widget, s_x+20+s_col1+x_gap, y, s_col3, s_height, m[2])
karamba.setTextAlign(widget, t, "RIGHT")
text.append(t)
images.append(karamba.createImage(widget, s_x, y, "icons/mail.png"))
y = y + s_height*2 + y_gap*2
clickAreas.append(karamba.createClickArea(widget, s_x-10, y0, s_width, y-y0,
"dcop kmail KMailIface selectFolder "+f.path+" && kmail"))
y = y + y_gap*2
if (y < maxHeight - 20):
karamba.resizeWidget(widget, s_width+s_x*2, y+20)
#this is called when you widget is initialized
def initWidget(widget):
bgImage = karamba.createBackgroundImage(widget, 0, 5, "icons/bg.png")
karamba.resizeImage(widget, bgImage, s_width+s_x*2, 20)
logo = karamba.createImage(widget, 0, 0, "icons/kmail.png")
t = karamba.createText(widget, 35, 5, 100, 20, "new mail")
karamba.changeTextFont(widget, t, "Franklin Gothic Medium")
karamba.changeTextSize(widget, t, 16)
karamba.createClickArea(widget, 0, 0, 100, 30, "kmail")
karamba.createImage(widget, s_width+s_x*2-18, 7, "icons/mail_get.png")
karamba.createClickArea(widget, s_width+s_x*2-18, 7, 16, 16, "dcop kmail KMailIface checkMail")
karamba.createImage(widget, s_width+s_x*2-40, 7, "icons/mail_new.png")
karamba.createClickArea(widget, s_width+s_x*2-40, 7, 16, 16,
"dcop kmail KMailIface openComposer '' '' '' '' '' ''")
_update(widget)
#this is called everytime your widget is updated
#the update inverval is specified in the .theme file
def widgetUpdated(widget):
_update(widget)
#This gets called everytime our widget is clicked.
# Middle button click forces to check new mail
def widgetClicked(widget, x, y, button):
if (button == 2):
kmail.dcopCall("kmail KMailIface checkMail")
kmail.py:
#!/usr/bin/python
import os, subprocess, string
def dcopCall(call):
cmd = "dcop "+call
pipe = subprocess.Popen(cmd, shell=True, bufsize=1024, stdout=subprocess.PIPE).stdout
res = pipe.read()
pipe.close()
return res
class Folder:
path = ""
name = ""
unreadCount = 0
unreadMessages = []
def __init__(self, path):
dcopCall("kmail KMailIface getFolder "+path)
self.path = path
self.unreadMessages = self.getUnreadMessages()
def getUnreadMessages(self):
r = dcopCall("kmail FolderIface unreadMessageHeaders")
ss = string.split(r, "\\n")
msg = []
for s in ss:
if (len(s) > 0):
msg.append(string.split(s, "\\t"))
unreadCount = len(msg)
if (unreadCount > 0):
self.name = string.strip(dcopCall("kmail FolderIface displayName"))
msg.reverse()
return msg
def getFolders():
r = dcopCall("kmail KMailIface folderList")
folders = []
for f in string.split(r, "\\n"):
folders.append(Folder(f))
return folders
skkmail.theme:
# you can change initial widget position, area size and updatin interval (default = 1min) karamba x=100 y=100 w=400 h=200 interval=60000 defaultfont font="Franklin Gothic Book" fontsize=12 color=230,230,230
All code above is GPL‘ed.


