Tuesday, December 29, 2009

QML Hello World (or calculate world)

Some thoughts about QML

QML reminds me a lot of Adobe Flex on Flash - my personal favourite tool for creating anything. Only difference is that QML is more suited for application development, as it allows full access to all system components - and is easily extensible with pretty much any normal qt components.

Read more on the snapshot:
http://qt.nokia.com/doc/qml-snapshot/
and from Kenneths excellent blog on the subject:
http://kenneth.christiansen.googlepages.com/DUI.html

Anyway, intro aside, I have also started doing a bit of coding now on QML and I really love it. It has nice separation of the declarative part (QML) and the logic part (either qt components or javascript). You can easily embed javascript to the qml code, but the clever guys at qt labs have made sure that you can only have tiny snipplets there. A welcome separation.

What has also been fun is that I have done ALL the coding on the pygtkeditor, so no coding on the mac, and all the coding on n900. Well, I did work on some button gfx a bit on mac, but that's it. Painting is not coding ;)

Anyway, take a look at the result of less than 400 lines of code. And the code is clean, sweet and easy to extend. Check out those transitions! They are 10 lines of code for the advanced, and about the same to get the fancy glow effect done to the buttons.



What I am really eagerly waiting for is a chance to see a proper flash-like editor for qml.

Monday, December 07, 2009

Theme Maker 1.2.5 out - Fremantle Beta

Now theme maker is on the Beta level. You can actually consider creating themes with this one and give those to your friends and not only to your enemies.

What really was improved:
1. Optification - Theme maker theme deb files are optified so they don't eat any root
2. Icons are also optified
3. Fonts work again (and are stored in user home, which is as good as optification)
4. Theme selection works now without need for device reboot


What is missing:
1. build-deb needs to be added - not a biggie
2. Icons need user to restart the device - it's a bug in the launcher code, that is being fixed by Nokia tam .
3. Application manager new icons are not yet themable - doh! - I cannot release features that haven't officially been released. Damn!
4. Theme based transition tuning is not yet part of theme maker - see above

I guess the bottom line is that I'll be releasing a new version soonish, but you'll at least now know what is going to be in there. I'll probably make a 1.2.6 version that fixes at least the part 3. by having a copy of the icons from the base theme.

Download here: Garage

Have a test with nuvofre in the same location.

I'll upload some shots later on. Carry on!


EDIT: You Must delete your old theme folder for theme maker to be able to optify the content. So extract that zip to a new folder and start there from scratch. Never re-use old theme maker folders.

Sunday, November 22, 2009

On gaming on n900 and the newly found lack of arrow keys

Everybody who has seen the n900 with english/generic keyboard thinks all keyboards will have arrow keys. Well, they don't. And this sucks big time for any gaming applications, as they cannot assume that keyboard has specific direction keys that would actually work. In most of the keyboards, there are only left and right keys. While up and down are behind fn+left/right.

Only thing we can really do to fix this 'great kb layout design' is in my opinion:
Forget that we ever even had the arrow keys and start using the usual WASD combo for the default direction controls. And to balance the AB,XY buttons, we should probably use the I,O,K,L buttons. All of these buttons are the same in all kb layouts that I know. This is a pretty balanced layout, but again, not so easy to discover. Grr.. I hate the kb layout mistake that we made. Sane solution would have been to move the extra letters behind fn key.

Otoh, I have finnish kb on the device, but I have switched to english layout so that I can have a sane d keys on the device. But it feels confusing.

On a whole different note, I just read an interesing articles on DUI, the UI frameworks of Harmattan written by Zchydem:

Part one:
http://zchydem.enume.net/?p=128
Part two:
http://zchydem.enume.net/?p=149

I'm eagerly waiting for part three.

We are also preparing for a small update for the N900 owners to come really soon, which is going to keep me busy next week in preparation of it. Let's see when we can deliver it to you guys. After we have released that, I'll start blogging a bit more on what is up for the end of the year update and what is brewing for the other near future updates.

Sunday, October 18, 2009

Theme Maker 1.2.4 released



A new version of theme maker contains a few more icons, fixes bg issue with media player bg, add new bgs for clock, call-ui and app manager, has better example files, now also PSD files are included, of which an example above, showing the cut layers and the example layers for the backgrounds template.

What else. Linux version now is also able to create debs, but seems to need a bit more mem that the shell script gives, so first build your theme, then close theme maker, reopen it, and the click on make debian button. I'll check if I can sort the memory issues at some point on linux as well.

There is a short suggestion text document included on how windows users can develop until I get the debian creation working on windows again.

Oh, link: Garage downloads section

[Edit] Always rebase your theme template, icon and background files on top of the new ones. I have again changed the resolution of the bg template.

Tuesday, September 29, 2009

Snes on n900

Thanks to the great developers of nrnoksnes, we have now snes running on n900 fullscreen. Wiimote supported, as well as tv out.

take a look at the video:



[Edit] I ported wiicontrol on the weekend just to get this awesomness up and running. While it's great that you can play games on the go and to be able to continue later from your couch with wiimote, you can also just bring your wiimote with you and use that to play games. It's just perfect.

And kids, don't pirate games.

Saturday, August 29, 2009

Theme Maker for N900

N900 is now out and we all want to make it even cooler. Even more My device than it already is. To the majority of the world that probably moot point as you don't yet have one, but you will. Soon. And then you want to make it more You. Enter Theme Maker N900.

I have updated Theme Maker (from now on, TM) to fully support N900 Theming. Not only can you convert the buttons, toolbars, all the widgets, but TM themes also convert the fonts, the icons and bacground images.

Wwhat is so different from before. Base theme template is larger than before. It's mostly legacy support stuff and you only really need to touch the right third of the template if you are lazy. In addition you will have two new templates: icons and backgrounds.

Lemme show these to you:



The icon template contains all the apps you have by default in the launcher and also for different mime types, devices and some control panel items. I'll be adding a few more later on. Ideas for good candidates are welcome. The reason these are not Nokia icons is that we need to have a CC basis for the icons so that you can work on top of them. Nokia Icons are of course strictly copyright Nokia, so I just used these beautiful Oxygen icons to set a good example for you.


Backgrounds contains on the top part a full 4 screens wide image (3200x480), so you can easily put an image that pans nicely on the device. Under it there are / will be some bgs for some additional apps.

So, even if you don't have N900 yet, I urge you to download theme maker and the example tempaltes and start hackign for a new theme, because you will surely be able to install it on your beautiful N900 very soon.

Theme Maker comes with two default templates, one for dark themes and another for light themes. This should set up the basis nicely for your new theme.

Link to download:
https://garage.maemo.org/frs/?group_id=36

[Edit: Forgot to mention that theme maker requires bigger java heap on linux than by default. OSX app handles it nicely, just doubleclick to open, but on linux you need to start with -Xmx1024M parameter. I'll add a .sh script to next release to easen the pain of linux users. Windows version will follow soonish. You can edit the theme template anyway already and that's the most important thing. ]

Thursday, August 27, 2009

Maemo 5 is out

It's out!
http://maemo.nokia.com

I'm so proud of what we have achieved in maemo team.

Monday, April 27, 2009

Album Art in Fremantle

Most of the media players need album art. So, ever application does the handling of the art by themselves (just like getting the metadata). For the metadata, we have tracker to get the metadata - one less headache. For the album art, we have tracker, hildon-thumbnailer and a standard to help alleviate another headache.

Standard? In Fremantle we have finally agreed on a standard on how to store album art and media art in general. This means that applications will be able to share the files, so album art is stored only once, retrieved from the internet if needed and a thumbnail suitable for list views is stored in common way.

We also worked together with Banshee team to make this a standard on linux desktop as well (Kudos to Philip van Hoof for it). You can read the spec in http://live.gnome.org/MediaArtStorageSpec

So, what does this mean in practice?
1. Tracker and hildon-thumbnailer do a lot of work for you in advance
- Tracker gets the embedded album art automatically
- Hildon-thumbnailer makes the thumbnails in advance in freedesktop.org standard
- Heuristic search is used in tracker and hildon-thumbnailer as specified in the media-art spec.
2. You can extend hildon-thumbnailer with content source plugins that download missing covers from the internet.
3. You can handle the album art all by yourself and just save some time if the condition 1. has hit its mark.

The option 2. is of course the preferred way of handling the album art, but heck: this ain't a perfect world, and I'm doing things a bit dirty, so I'll go for route 3. If the condition 2. would apply and an internet download plugin is available, I would change ukmp to depend on that package and thus, the following code would (mostly) not be needed at all.

However, quite a bit of it is useful. First of all: How is the album art filename (to the full version) calculated? I have nice copy paste functions here. Feel free to use them as is under any license.

You will need unicodedata and md5 as non-usual dependencies, so:

import md5
import unicodedata



Then the functions. First we create the album art filename as specified in the standard. The following function handles that conveniently for you. Now, it's up to you on how to use that. You can either just depend on whatever tracker and hildon thumbnailer have created for you (with or without the plugins), or, as ukmp does, which is, that if first checks whether the album art exists, if not, it downloads it from the internet.

coverlocation=homedir+"/.cache/media-art/"

def getCoverArtFileName( album ):
"""Returns the cover art's filename that is formed from the album name."""
albumString=dropInsideContent(album,"[","]" )
albumString=dropInsideContent(albumString,"{","}" )
albumString=dropInsideContent(albumString,"(",")" )
albumString=albumString.strip('()_{}[]!@#$^&*+=|\\/"\'?<>~`')
albumString=albumString.lstrip(' ')
albumString=albumString.rstrip(' ')
albumString=dropInsideContent(albumString,"{","}" )
albumString=albumString.lower()
albumString=string.replace(albumString,"\t"," ")
albumString=string.replace(albumString," "," ")

try:
albumString=unicodedata.normalize('NFKD',albumString).encode()
albumString=albumString.encode()
print albumString
except:
try:
albumString=albumString.encode('latin-1', 'ignore')
albumString=unicodedata.normalize('NFKD',albumString).encode("ascii")
albumString=str(albumString)
print albumString
except:
albumString="unknown"
if len(albumString)==0: albumString=" "

albumMD5=md5.new(albumString).hexdigest()
emptyMD5=md5.new(" ").hexdigest()
albumArt=coverlocation+"album-"+emptyMD5+"-"+albumMD5+".jpeg"
return albumArt


def dropInsideContent(s, startMarker, endMarker):
startPos=s.find(startMarker)
endPos=s.find(endMarker)
if startPos>0 and endPos>0 and endPos>startPos:
return s[0:startPos]+s[endPos+1:len(s)]
return s




Ok, great, now we have the full version. But, as ukmp needs mostly the thumbnail version, we need the filename to the thumbnail itself.


thumbnailLocation=homedir+"/.thumbnails/normal/"
def getCoverArtThumbFileName( album ):
artFile=getCoverArtFileName(album)
thumbFile=thumbnailLocation+md5.new(artFile).hexdigest()+".jpeg"
return thumbFile


If it happens that the thumbnail does not exist (e.g. wasn't created, has been removed or whatnot), you have a few options:
1. you can create the thumbnail yourself (I'll give an example soon for that)
2. you can request hildon-thumbnailer to create it for you

For the first option, you can just call hildon-thumbailer on the dbus:
https://stage.maemo.org/svn/maemo/projects/haf/trunk/hildon-thumbnail/daemon/thumbnailer.xml

I am not using the method myself at the moment, so here is a quick example. The method is not blocking, so proper use would need to also receive the finished signal from h-t with the thumbnailHandle property. Of course, you can also be polling to see when it has been generated. Usually in non congested situation, this is going to be some tenths of a second. If there is congestion, the content is handled lifo fashion in h-t.


import dbus, time
filename="file:///user/home/.images/01.jpg"
bus = dbus.SessionBus()
handle=time.time()
thumbnailproxy = bus.get_object('org.freedesktop.thumbnailer','/org/freedesktop/thumbnailer/Generic')
thumbnailHandle=thumbnailproxy.Queue([filename],["image/jpeg"],dbus.UInt32(handle))


I'm scaling inline in ukmp. I'm using PIL to scale down the image. It's slower than using pygame (or h-t), but looks better, as it has good anti-aliasing. Anyway, it's once in a lifetime happening, so it's ok to take a while. Here we are also using the above created functions (wehey). I'm using freedesktop org standard size: normal, which is 128x128. Be aware that the media player in Fremantle uses 124x124, so I might switch to that resolution as well. The coverlocation will then also switch from '~/.thumbnails/normal' to '~/.thumbnails/cropped'.

import PIL
thumbFile=getCoverArtThumbFileName(album)
fullCoverFileName=getCoverArtFileName(album)
if (os.path.exists(fullCoverFileName)):
thumbFile=getCoverArtThumbFileName(album)
fullCoverFileName=getCoverArtFileName(album)
image = Image.open(fullCoverFileName)
image = image.resize( THUMBNAIL_SIZE, Image.ANTIALIAS )
thumbFile=thumbFile
image.save( thumbFile, "JPEG" )

Sunday, April 26, 2009

A little tracking for the people waiting for Fremantle

I haven't been blogging much about Fremantle yet. But, yesterday there was a question on the maemo developers mailinglist about what files are indexed to the trackers metadata database, so I though to clear out that issue and also to tell a bit about how your app can use tracker.

So, to answer that question first: Tracker tracks the user home and any mounted media that is attached to the device. For the memory cards, it retains a stack of 3 cards in it's database, so, you can change card A to card B, and back to card A and tracker won't need to reindex the content of the cards. And yes, you can be then swithing to B, to A, to B and you won't lose any data. The amount of cards to support is a configuration option, but by default it's set to 3. So, internal card=1, external card1=2 and then you have the one more as exteral card2. For a third external card, the device will need to flush the oldest seen card away from it's indexes.

There was some concern also as to whether applications can put sound effects and pixmaps into the cards and to make sure they won't be indexed. Well, to this, we have two solutions:
1. put the files to a folder that is hidden (so, it has a "." in the beginning of the folder name) - tracker won't index any hidden folders by default
2. Add the folders to trackers blacklist file

I recommend the solution 1 for multiple reasons.
1. it's simple.
2. user doesn't have any reason to see application data anyway, so this way it'll be also hidden in the file manger. Just make sure your app will flush the data on uninstall of your app.

Ok, then a bit on how you can use Tracker.
As you probably have read, I've been on paternity leave, from which, I've taken a bit of time to integrate ukmp to the new Fremantle stack.

So, first thing I did was, I replaced my own indexing code with code to load all music metadata from tracker database. Loading of this data on startup takes almost no time and tracker also does sorting of the data really easily for me. Not that sorting would actually be any issue in python, nice anyway.

On startup, I hear you saying? Why not on demand? Sure, that would be an option, just happens that how ukmp was built, it's easier for me to get all the content on startup and not on demand. Both are fine. I could write a small comment on how to do stuff on demand as well, but let's start with this.

We'll need to use two interfaces: search and metadata

Corresponding dbus introspection files are: search and metadata

You can find the whole dbus introspection from here


Let's start with defining the needed proxy objects:

import dbus
bus = dbus.SessionBus()
searchproxy = bus.get_object('org.freedesktop.Tracker','/org/freedesktop/Tracker/Search')
metadataproxy=bus.get_object('org.freedesktop.Tracker','/org/freedesktop/Tracker/Metadata')

#Ok, let's then get all music files and for those, the artist, album, title and track# sorted by artist

metadata=searchproxy.Query(-1, "Music", ["Audio:Artist","Audio:Album","Audio:Title","Audio:TrackNo"],"", dbus.Array([], signature='s') ,"",False,["Audio:Artist"], False,0, 40000)

#Now that we have the data, we'll just add it to the internal structures

for songItem in metadata:
fileUrl=songItem[0]
artist=songItem[2]
album=songItem[3]
song=songItem[4]
track=songItem[5]
self.appendSong(track, album, artist, song, fileUrl)



Nice and simple. Now we have the data. This saved me about 300 lines of code, plus multiple library dependencies and tons of headache.

Of course, with my approach of loading everything on startup, I need to update the data when the data changes, but for this, tracker provides a really nice signal that looks like this:


signal sender=:1.15 -> dest=(null destination) serial=403 path=/org/freedesktop/Tracker; interface=org.freedesktop.Tracker; member=ServiceStatisticsUpdated
array [
array [
string "Files"
string "2320"
]
array [
string "Music"
string "543"
]
]

I won't show the implementation on how to keep the data update on this blog post, I'll save it for a future blog post. I'll instead now tell how to keep Tracker up-to-date on usage of the files. All media players on Fremantle should either use MAFW or do the following so that we would all be happy campers no matter which media player user uses.

When you are playing a music file, please notify tracker of the play event. I do so at the end of a track, but your heuristic may vary. Firts we get the current playcount, then we add 1 to it, then we set the new playcount and the curren playtime. We set the time in GMT in UTC format, which is rather easy to get in python.

import time
currentCount=metadataproxy.Get("Music",currentPlayFile, ["Audio:PlayCount"])
newcount=1
if len(currentCount[0])>0: newcount=int(currentCount[0])+1
currentTimeUTC=time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
metadataproxy.Set("Music",currentPlayFile, ["Audio:PlayCount","Audio:LastPlay"],[str(newcount),currentTimeUTC])


Ah, now we have the data in tracker, we are able to update the playcounts and playtimes so that all music players can benefit from the data. In my next blog post, I'll tell how the album art can be handled in common way across the platform. I'll tell you how you should do it and I'll tell you how I do it now (which might not be the case I will do when the device has been out for a while).

Then I'll make a blog about how to make dynamic lists, e.g. to list most popular tracks, most recently added and the most recently played tracks.

Then, to top this, I'll let you know how the signaling can be used to keep your internal data structures up-to-date, in case you are not using on-demand loading of the data.

edit: fixed typo as noticed by timeless

Monday, April 20, 2009

I'm a daddy!



Almost exactly a week ago I became a dad of a very sweet little girl. Her hello world message will be coming a bit later on when a name has been bestowed upon her.

I am the happiest man on the planet.