Ikke's Blog

Apr 19
New prototype

Lots of traffic on GIMPNet today, many different and interesting things were discussed between some GNOME hackers. But I guess others will write about those things (Philip? Jeff?).
Anyway, more related to myself and my own project (yeah, CDIS, you know): I had a great talk with Robert "Robot101" McQueen, who gave some very sensible insights in the D-BUS system, and how I could (ab)use it.
First of all, last night I was thinking about the D-BUS glossary a little, and came to the conclusion that "interfaces" might at a certain level be compared to "namespaces" instead of "interfaces", at least in some point of views. Might be interesting if you try to "get" D-BUS. Questions? Leave a comment ;-)

After this talk and some help from J5, #1 python-dbus guru, I managed to get a new sample setup working. In this new design, there is no central daemon at all any longer, which is great, obviously. Some changes/enhancements to the D-BUS bindings might be necessary though (I hate the fact you can't get the sender service/object path in a signal handler!).

As a picture says more than a thousand words, first open up this screenshot. Code's here.
As you can see, first the user starts his favorite media player, RhythmBox, and spins his favorite song (1). In the background, a screensaver application is running (in the sample I started it after RB, but hey, its a sample) (2). After a while (3 seconds ;-)), the user starts his VoIP softphone, Ekiga (3). As the user is very popular, he almost immediately receives a call, and accepts it (4).
As you can see, Ekiga knows about music players, and asks them to pause playback. RB is CDIS-aware, and stops playing (5). Obviously, the music player should do a generic "Paused" signal here (see later). Next, Ekiga sends out a signal on the org.freedesktop.CDIS.SoftPhone interface, "IncomingCall". This signal can be used by any application listening for it. It is not related to pausing music players: in (4-5), Ekiga tells all music players to pause. It knows about this kind of applications, and knows how to handle them. In (6) Ekiga provides application types it doesn't know about (or, maybe more likely, doesn't want to know about, doesn't care about) to do some action based on the fact there's an incoming call.
As this is a video conference, the screensaver traps that signal, and stops his internal timer (7).
After a while, the call is over, the user disconnects (8). Ekiga sends now tells all music players they can resume playback if they were playing before (9). It also sends out a "CallTerminated" signal on the SoftPhone interface, which is again seen by the screensaver, who restarts his timer.
Then, something happens that will/should not be supported, but I just implemented it as a sample. When the screensaver decides it's time to blank the screen (11), it tells all SoftPhones to go "Idle" (12). This is not the way we should handle this in "real" applications, as a screensaver should not put SoftPhones in idle state, it should send out a signal "ScreenSaverStarted", the softphone should watch for that one, and go idle when the screen blanks. Anyway, I just wanted to give one more example of the "action" paradigm, just like "Pause" and "Resume" on the MediaPlayer interface.

As usual, the prototype code is extremely ugly, but it does show what I got in mind regarding code generation. There should be 3 "objects":

  • CdisMusicPlayer: inherited by a "real" music player, or by some internal CdisHandler object. Needs function pointers to all supported CDIS function calls. In the sample, used by RhythBox.
  • CdisMusicPlayerController: Used by code that wants to control a class of applications. Used by Ekiga to pause all music players. Only provides "active" functions that, when called, result in a change on remote objects.
  • CdisSoftPhoneClient: helper class for "generic" applications that want to be notified about things by a SoftPhone application. Used by ScreenSaver to be able to work with SoftPhone applications on the system, as the SoftPhone doesnt know about screensavers

For all of these objects, I'm sure there's some pattern for them. Philip, help! :-)

This should be fairly clear I guess... If not, ask. Lots of things can/will/should change, eg authorisation, and issue raised by sri yesterday. Don't know yet how this should be tackled thogh.
Duplicate events should be prohibited too (although this can for a big part be done by having well designed interfaces): when app A asks MusicPlayers to pause, then B does the same, and A sends a "Resume" signal, the player(s) should not resume unless B also sends the "Resume" command. This and other issues will need to be fixed!

After all a pretty fun day :-) Although you can't imagine how much I hate Blast by now :> Big thanks to all help on IRC, I should get all of you a beer at GUADEC. Sadly enough due to exams I can't be there though ;-)

Apr 18
More CDIS spam

First of all: Evolution is sooooo "1337":

Guess what: I've been thinking some more about CDIS. Yesterday I had a little discussion about it on #gnome-hackers with Robot101, who seems to have some good knowledge of D-BUS. Obviously, he rejected the idea of adding one more daemon. Indeed, it shouldn't be there, I hate it myself too, but currently it's the only solution to get things working.
He suggested to specify some well-known service and object names, and call methods on the desired services that way. This is not a possible solution though: think of someone running 2 VoIP softphones (eg Ekiga and Skype), 2 IM clients (Gossip for Jabber, aMSN for MSNP),... A service is unique for one application.

So some other solution should be found.
The best one, IMHO, is to add a method to the org.freedesktop.DBus service/object, something like "GetObjectsByInterface", which accepts a string, and returns an array of (servicename, objectpath) tupples, both strings. Using that one can do a specific call on all objects that need to be called.

Next to that, there's the versioning issue. If I remember correctly, a long long time ago this has been discussed on the D-BUS mailing list, and people decided interface versioning support wouldn't be added to D-BUS. As the CDIS interface specifications won't ever be "final", it should be possible to get around this.
It's not that hard though. We can use the standard x.y versioning system, x.y is backwards compatible with x.(y-1), so in a version bump from x.y to x.(y+1) only methods or signals can be added. Bumping x allows a complete API break.
Like this, if we release version 1.2 of the org.freedesktop.CDIS.FooInterface interface, and application FooApp got an object implementing this interface version, it should register itself to the D-BUS sessionbus, and tell it it implements org.freedesktop.CDIS.FooInterface.1.0, org.freedesktop.CDIS.FooInterface.1.1 and org.freedesktop.CDIS.FooInterface.1.2. Now if some other application wants to call a function added in version 1.1 of our spec, it just checks what service/objectpath pairs implement org.freedesktop.CDIS.1.1, and calls the method(s).
All this can be done behind the scenes by some helper library that makes it easier to make applications CDIS-aware.

As now is the time to come up with some project for Google's Summer of Code, I think it'd be great to work on this (now don't steal the idea). The only issue is: would someone be willing to mentor this?
I'd like to do the initial work somewhere under the hood of the GNOME project, if that'd be possible/allowed/accepted.

Here's a TODO:

  • Add the previously described method to the D-BUS service
  • Come up with some XML format to define CDIS interfaces, including interface version support
  • Write code generators that generate helper libraries based on these XML descriptions. Some ideas:

    • Plain C: using vtables with function pointers
    • GObject: standard GObject things like signals and GObject interfaces
    • Python: decorators
    • CLI/C#: decorators too

    The helpers should use the language-native D-BUS bindings, which makes things easier to debug (IMHO)

  • Write up an initial interface for some specific service type, and make some projects ("servers") aware of it
  • Change some other applications ("clienst") so they can make use of the servers

Regarding the helper libs: these should abstract the complete D-BUS backend and versioning issues from the actual application. An application should just initialize it, say "Hey, I'm a MusicPlayer, I want to support version x.y of the org.freedesktop.CDIS.MusicPlayer interface, here are my callbacks".
In pseudocode:

/* Hello world, I want to implement a CDIS interface */
CdisMusicPlayer *cdis_self = cdis_musicplayer_new("1.2", "com.eikke.CoolPlayer", "/com/eikke/CoolPlayer/CDISController");
/* When a client makes a "pause" call to apps implementing org.freedesktop.CDIS.MusicPlayer, please jump to myapp_playback_pause
 * This uses D-BUS methods
 */
cdis_musicplayer_set_playback_pause_cb(cdis_self, myapp_playback_pause);
/* Hey listeners out there, I started playback
 * This sends out a D-BUS signal
 */
cdis_musicplayer_playback_started(cdis_self);

Next to the server object, there are clients:

/* Hey, I'd like to control music players. I support version 1.5 of the org.freedesktop.CDIS.MusicPlayer interface */
CdisMusicPlayerClient *c = cdis_musicplayer_client_new_with_bus("1.5", my_dbus_connection);
/* If a player starts, please run this callback */
cdis_mediaplayer_client_set_playback_started_cb(c, playback_started);
/* Tell all MusicPlayers to pause */
cdis_mediaplayer_client_pause(c);

Maybe the "object" instance isn't even necessary!

Behind the scenes, when the client calls cdis_musicplayer_client_pause(), the helper will know this method was added in version 1.1 of the specification. It will request a list of all service/object-pairs that implement the org.freedesktop.CDIS.MusicPlayer.1.1 interface from the D-BUS service, and do the Pause() call on all returned objects.
When the server "connects" to the system, telling it implements version 1.2 of the spec, the helper will connect to the session bus and will tell the D-BUS system the object implements org.freedesktop.CDIS.MusicPlayer.1.0, org.freedesktop.CDIS.MusicPlayer.1.1 and org.freedesktop.CDIS.MusicPlayer.1.2.

Like this it should be fairly trivial to make existing and new applications CDIS aware. And that's the way it should be ;-)

Obviously, an application could use "pure" D-BUS calls to handle all this itself too. But why make things so complicated?

Next to that, it should be possible to write "testkits" too, based on the XML specs. Python might be very usefull here. One test then looks up the highest version of the spec, and executes all methods new in this version on all objects claiming to implement the interface. Then it takes the last-but-one version, and does the same thing, all the way down to x.0. This way an application developer can easily check whether his application is CDIS compliant. This needs some more thinking though ;-)

Anyway, lots of things to be done, and obviously, not all of this can be done in only 2 or 3 months. Still, some results/progress can be made, and I'm 99% certain incorporating this in the desktop would be a great thing.
I know one should just apply for SoC without thinking about a mentor. I would like to know someone'd want to be mine though before applying (just to be on the safe side), so if these things interest you and you want to get some experience on the mentor side of things, please let me know!

Apr 17
Easter hacking

Writing code on easter day, after spending a day with your family (including the obligatory champagn/wine/beers) isn't such a good idea (#gnome-nl):

23:43 <@ikke> damn, help!
23:43 <@ikke> g_return_if_fail(foo() != TRUE)
23:43 <@ikke> returnt dat nu al foo() TRUE is, of FALSE?
23:43 <@ikke> ik ben helemaal aant flippen :s
23:43 <@kris> het failt als foo() != TRUE niet true is
23:43 <@kris> dus als foo() true returned
23:43 <@ikke> dus returnt als foo true is
23:43 <@kris> oh nee
23:43 <@kris> wacht ff
23:43 <@ikke> kijk, jij ook al :p
23:44 <@kris> all foo() false returnt, is foo() != TRUE true
23:44 <@kris> ja
23:44 <@kris> dus het failt als foo() true returnt
23:44 <@ikke> dus ie returnt als foo true is
23:44 <@kris> want dan is foo() != TRUE false
23:44 <+qball> leuk he :D

For the people who dont know dutch out there:

23:43 <@ikke> damn, help!
23:43 <@ikke> g_return_if_fail(foo() != TRUE)
23:43 <@ikke> does it return if foo() is TRUE, or FALSE?
23:43 <@ikke> I'm going nuts :s
23:43 <@kris> hit fails when foo() != TRUE isn't true
23:43 <@kris> so, when foo() returns true
23:43 <@ikke> so it returns when foo is true
23:43 <@kris> oh no
23:43 <@kris> wait a moment
23:43 <@ikke> look, you got the same issue :P
23:44 <@kris> when foo() returns false, foo() != TRUE is true
23:44 <@kris> yes
23:44 <@kris> so it fails when foo() returns true
23:44 <@ikke> it returns when foo is true
23:44 <@kris> caus then foo() != TRUE is false
23:44 <+qball> fun heh :D

Oh well, it's fixed :-)

I got Gentopia SVN commit access now. Gentopia is a project set up by some Gentoo devs aiming to get the Project Utopia stack properly integrated in the distribution. I committed an updated networkmanager-vpnc version, enjoy ;-)
Cleaned up the NetworkManager Gentoo backend a little too.

Could someone tell me how to mark a bug as a dupe in Bugzilla?

No CDIS mails yet, busy for some uni project (link) taking too much of my time, which I don't like actually ;-) Looks like some people picked up the idea though, great!

Next to that: jay for new fglrx drivers! Now I *will* be able to run Linux on my laptop when I get it (will not be within next 2 months though I'm afraid :-(), which is some *great* news.

Apr 12
First CDIS "proof of concept"

Well, proof of concept, it's not that much actually :-)
Been fighting with DBus today to get something as I described yesterday working. Thanks to the people on the mailing list and IRC (#dbus@freenode) for all help, hints and pointers!

I hacked together a very small sample in Python (yes, I hardly know Python, so the code might be very very bad, I just wanted to test whether what I want to do is possible using DBus).

The setup uses a central daemon (don't shoot! It looks like it's the only usable way to cut the job) which keeps track of all objects that want to implement some CDIS interface. Objects subscribe to the concentrator (thats how I called it anyway), and clients talk to it too.
See this screenshot to get an overview how it works. First the concentrator is started. Then the user starts Gaim and Kopete (this is just a sample, obviously). They both register to the concentrator, which keeps track of them. Now some user app (think "a screensaver") connects to the concentrator, and asks it to set the status of all IM clients to "idle".
The concentrator receives this request, checks his list of connected objects, and runs the "SetState(s)" method on all objects implementing org.freedesktop.CDIS.InstantMessenger.

All of this is completely transparant to the actual application: it doesn't know about DBus, it shouldn't care about subscribing to the concentrator (unsubscribing can be done using NameOwnerChanged etc, not implemented yet) etc. Just provide all functions to implement the inteface.

The best way to tackle this, I think, is to write the specs using some XML format (we might want to look at the dbus-glib-bindings format), then generating code using that (plain C using function pointers, GObjects and their signals, QObjects and their in-process signal mechanism, dunno about the best way to do this in Python and others). It should be fairly painless to get this working.

Other TODO's:

  • Write a *decent* concentrator (this one can be started using DBus activation on the first subscription call, jay!) that's error-savvy, handles killed applications, can scan the bus on startup for existing objects it should handle,...
  • Write a spec XML format
  • Write specs (this one will be the hardest part I guess)
  • Get desktop apps to use this beast!
  • Tons of other things

[edit] Per RealNitro's request, code is online. Beware, it's ugly.
I've been thinking: for the Python "bindings", function decorators could be very well suited...
Tomorrow I'll send something about this to XDG, I hope something useful can come out of this.

Apr 11
Common interfaces

The recent discussion on desktop-devel on the inclusion of GNOME Power Manager into the 2.16 desktop release (big thanks to the developers for this software, it took a while to get suspension working on my desktop but now it does, I really like GPM even if it's no laptop) ended up in two completely different discussions: the usage of notifications (libnotify) and the notification area versus normal applets, and sharing a base daemon with eg the KDE power manager (somewhat related to what NetworkManager does: a central daemon running as root, and a client applet on top of that, using DBus for IPC, although the power management daemon should not run as root, as all privileged tasks are handled by hald, which runs as root).

The second issue is one which interests me a lot, as more than a year ago (IIRC I was still using Windows as main desktop at that time :oops: as my Linux machine was too slow to run any desktop app) I sent an email to the XDG list about what was to become CDIS, the Common Desktop Interface Specification (the email I link to is just the first of bunch of long threads, from the initial idea almost nothing was kept). Lots of email on the list later, no actual result came out of it (which is mainly due to me).

Shared interfaces are, just like open file formats etc, very important. We got some great desktop specifications that ensure a developer his/her code and application will work on all platforms supporting the specification. Think of the notification area spec, autostart spec, .desktop files,...
Shared IPC interfaces (think DBus) are very important too. In the case of a power management app like GPM or it's K* equivalent, they should both use the same interface for several functions, eg "DontHibernateNext5Minutes" (dumb and useless example, but hey). If I write an application that doesn't need user input, but does a lot of work (think of a CD burning app), I don't want the machine my software runs on hibernates during the burning process, whilst it's perfectly possible the user leaves the machine and his sessions idles out. But I don't want some construct like

if(user_runs_gnome)
    do_gpm_dont_suspend_call();
if(user_runs_kde)
    do_kde_power_manager_dont_suspend_call();

or something alike. Maybe this isn't a big issue for some simple program, but think of a large app that should be cross-desktop made by some ISV...
Same thing for a DVD player: I don't want to notify both gnome-screensaver, kde-screensaver and whatever they shouldn't pop up next minute, I just want to notify the org.freedesktop.ScreenSaver service it shouldn't take control of the desktop.

Another sample: I'm a VoIP softphone (think Ekiga), and I get an incoming call. Obviously, I'd like all media players that might run on the current console/desktop to pause. I don't want to send one signal to PlayerA using some custom socket, one to PlayerB using his own DBus interface! I just want to notify all media players they should pause, and send a "Pause" signal to (eg) org.freedesktop.CDIS.MediaPlayer. When the call is ended, I could send a "Resume" signal to the same object path.

I don't know whether all this is possible using DBus, still need to read the docs once again (there's some black magic in there, really!), but I guess you get the idea.
Obviously, an application implementing a CDIS interface can also implement extra functionality, and if multiple applications start implementing the same extra functions, this functionality might be added to the a new version of that interface spec. Like this, we never limit the service developers. There can even be "NotImplemented" errors etc.

The only thing we need is getting some developers together in all fields to write down such a spec in some standard format. Not too many people though, so there's less chance of huge flamewars and more results.

Some application types I think of now that can use a shared interface:

  • Screensavers
  • Power management
  • Media players
  • Instant Messaging apps ("SetStatus(STATUS_AWAY)",...)
  • Email clients ("NewMailArrived")
  • ...

Maybe it's time to get this on XDG again...


Completely unrelated: dear lazyweb, within a month or so (at least, I hope) I should get a laptop computer (Asus W3J, dualcore 2*1.83Ghz, 1GB, 80GB, pretty cool stuff). Obviously I'd like to run Linux on the machine (oops, GNU/Linux, sorry!) once I can, as it got an ATI X1600 GPU which is completely unsupported today.
I was thinking to run both Gentoo Linux (like I do now on my dekstop) and Ubuntu on it: Gentoo for development things and just playing around, Ubuntu as "serious" desktop and university stuff. Next to that I also need Windows on it (some university soft is Windows-only).
I wrote down a possible partition layout for this setup today, and got some questions about it:

  • Will this work? The Gentoo part will, as that's +- what I run now, but will Ubuntu be able to handle a foreign bootloader, and the LVM stuff?
  • Won't I get in trouble by sharing my homedir between both distributions? I shouldn't, but there are no more certainties in life these days

Thanks!

<< Previous Page :: Next Page >>

Categories

Who's Online?

  • Guest Users: 324

Misc

XML Feeds

What is RSS?