Wednesday, August 29, 2012

Exploring Desktop Objects #2

In the first part of this text, I explained a couple of reasons why I created edelib-dbus-explorer. In the mean time, this tool got a couple of quite handy features I will try to explain here.

IMHO one of the killer features of Common Lisp, Python or Clojure are docstrings. You write the code and document it at the same time; the documentation becames a part of code, meaning you can easily get it at any point: from REPL or from some GUI fronted.

That is why I added docstring support in edelib-script (based on tinyscheme), so:


(define (foo a b)
  (+ a b))

you can write as:


(defun foo (a b)
  "This is foo function."
  (+ a b))

Yes, it is quite Common Lisp-like, but to avoid messing with interpreter internals and to leave some room for turning off docstring collection in case of optimizations, I put it as defun macro. Maybe I could use different name to reduce confusion, like s7 which uses define*, but I'm not going to bother with that right now.

Now imagine in similar fashion you can document DBus methods or signals. This feature would be extremely useful for tools like edelib-dbus-explorer which, for example, could display method/signal prototype and description as tooltip when user hovers over the name.

Actually this was implemented in edelib-dbus-explorer from the start, but without descriptions, as DBus does not have official way how methods and signals should be documented. However, searching through the various implementations, I noticed EggDBus and GDBus can provide them via annotations. Then I became extremely happy, meaning edelib-dbus-explorer got immediate support for them.

Since both EggDBus and GDBus put docstrings in different namespaces (but ends them with DocString), edelib-dbus-explorer will simply scan for annotations whose names ends with .DocString and pick the value. With this, I don't have to change it when I extend edelib DBus binding to generate introspections with e.g. org.equinoxproject.DBus.DocString annotation name.

Unfortunately, not all (gtk+) applications uses this feature yet, and the worst of all, this will not work with Qt applications. I'm not sure what is official way from Qt/KDE standpoint, but I noticed some of projects are using <tp:docstring> tag inside introspection xml for documentation. I'm not sure even if it is transmitted to DBus server or is stripped when binding tool is creating source code from introspection xml. This needs further investigation.

Beside of this, I added builtin help (you can invoke it by evaluating (help) function) where are described common functions and how is done mapping between DBus and Scheme types. I didn't have enough time to explain it briefly in previous post, so it gets deserved space now.

Tinyscheme (thus edelib-script) is a R5RS based implementation and as most of Scheme implementations have a few object types: string, number, list, vector and some of them hashmaps. Opposite to this, DBus have much richer types and is quite strict about them: if method call expects variable with int32 type, it will refuse to be called with int16 type. Which can be a problem as Scheme does not have notion of 32-bit or 16-bit integers; it only understaind number which is often largest possible integer (sometimes even seen in bignum form).

So I added type hints, inspired from Emacs DBus hints: int16 is represented as :int16, string as :string and so on. All hints must be added to method or signal call arguments if that call requires arguments. For example, dbus-call will call DBus method and using hints it can look like:


(dbus-call "org.foo.baz" "/org/foo/baz" "org.foo.Interface" "Method"
           :string "Some string"
           :uint32 3)

where the first 4 parameters are service name, object path, interface and method. Things gets complicated when we have DBus complex types (like array or struct), but thanks to Scheme/LISP lists, these problems are easy to overcome. So, to represent an array of 4 uint16 types, this is used:


'(:array (:uint16 1 :uint16 2 :uint16 3 :uint16 4))

I know, it is messy, so I cooked a function called dbus-make-array that will simplify this like:


(dbus-make-array :uint16 1 2 3 4)

On other hand, DBus struct type behaves much like C/C++ structs and can have many different types inside own collection, much like Scheme lists. Unfortunately, you still needs to explicitly add types, like:


'(:struct (:uint16 1
           :string "Foo"
           :object-path "/org/baz"))

Dictionaries are list of lists, where the first element is key and the second is value; both again must have types:


'(:dict (:string "key1" :bool 1)
        (:string "key2" :bool 0))

And any of these can be a part of each other, creating even more complex combinations. Truth to be told, from syntax stand of point, things can be improved, but it is all matter of creating additional functions or macros. For example, we can simplify struct syntax like:


(make-struct :uint16 1
             :string "Foo"
             :object-path "/org/baz")

I didn't cover other supported types, like Variant or ObjectPath and I'm leaving documentations to do that. However, one thing I would like to mention is the plan to add support for implicit conversion; for example, all positive Scheme numbers could be uint32 type and the negative int32. This would make typing and overall things much easier.

Anyway, since video speaks more than thousand images, here is a small demo of the main edelib-dbus-explorer features in usage. If you would like to get hands on it, you will need to download edelib svn source code and compile it.

Feel free to ping me if you find some issues :)

Monday, August 27, 2012

Taskbar Icons Fix

When the new taskbar applet landed in ede-panel, application icons were fetched in pretty standard way: inspect _NET_WM_ICON hint and decode image data, if application set it.

However, I overlooked one major feature of mentioned _NET_WM_ICON: this hint can support multiple icons (by different sizes), and modern GUI applications are starting to use it extensively. I added support for this in one of recent commits.

What are benefits of this? First of all, take a look at the provided picture:

application native icon

The first image is natural sized (16x16) provided by application and the second one is explicitly scaled, which was done until now. So beside cleaner icon look, we saved a couple of CPU cycles that would be wasted for unneeded scaling.

Thursday, August 16, 2012

Exploring Desktop Objects #1

Recently I played a little bit with Pharo (which is a fork of Squeak Smalltalk) and I was quite impressed with it. Since this was my first connection with Smalltalk, the language simplicity and clarity struck me hard, wondering why we are still living in dark ages of C++/Java or whatever language that is daring to call itself Object Oriented.

A perfect companion for this language comes in form of it's own environment: you have a full desktop under single executable which isn't desktop in a normal sense: it is much more like environment of objects, where everything you touch and move (window, button) is a true object.

Of course, every sane GUI C++ program will use object notation for buttons or windows, but at the end, they are compiled down to assembly and you are done with it. To have a false sense of ability to change it, you would modify some configuration files, reread them and load the program again.

With Smalltalk is different: if you want to change how button looks in certain window, you just get it's object and call whatever method you can call (in Smalltalk parlance: you send a message). Or, if you, at some point would like to see how this window is written, you simply query it's source code.

If you are still not convinced, check these videos from Alan Kay's Etech Presentation. Remember that was 2003 and we still can't do many of those things with (insert your favorite language here), no matter how fancy it is.

But, this article is not about how Smalltalk is glorious but what can be done to improve current situation. And some things can be done indeed, even if we are still living in stone age of modern languages (sic).

Now lets go to the matter.

Today modern way to communicate between desktop components and applications is DBus so situation here is very much status quo. DBus became stable, everyone use it and everyone is happy.

DBus brings notation of object paths, interfaces and methods; you can see object paths as instances living in certain namespace, which is pretty neat since you will have a lot objects floating around.

So DBus is very much object oriented, but why we are still have stone age tools to handle it? I'm not counting here language bindings (where btw. some of them are awesome), but the tools for exploring current objects (or object paths) and their context. Let we see what we have:

  • standard tools shipped with dbus (dbus-monitor and dbus-send): well unless you know how to manually encode the message with array of strings or, for God sake, struct of arrays and dictionaries, you have to look somewhere else
  • qdbusviewer and qdbus: much better, comes with Qt. Even qdbusviewer will popup a dialog to fill method arguments when you are going to call that method. However, services which do not have introspection data will make it unresponsive (you will need to restart it). Setting complex parameters (like arrays or dictionaries) is not possible.
  • DBus Explorer: never tried it, but C#/Mono background decided for me to never try it; I don't have mono installed and not planning to do so.

How about some tool with exploring ability and ability to write and call custom code from the same place? Or maybe to have some IDE capabilities like generating code or displaying documentation of selected methods? Unless you are going to write it, there isn't one.

Why this matters when we have nice language bindings and even better archaic tools like dbus-send?

Well, let suppose you are going to write a client for PackageKit, but your language doesn't have ability to integrate packagekit-glib2 (or it was packagekit-glib :P) or simply, you don't want to add another library as dependency?

In that case, the only solution is to read reference api where you will get lost in a matter of seconds. Who needs examples when all methods are nicely documented and colored. What to call in which order? Well, either read the code or use dbus-monitor.

With the same approach applied above, if you are going to write your console http client (for example), you would either have to consult firefox source code or use wireshark to decipher http protocol. C'mon people, we are not living in '90-ties any more; we are lazy today and we prefer to see examples first.

Or, let put PackageKit aside (as we don't write package management tools every day). How about to see what (DBus) services we have on our system, which interfaces and objects they exposes? Or simply, your program exposes services; how the hell you are going to test it? Again, you will use either dbus-send or write some testing code with python/ruby/etc. (before that make sure to download all their dependencies as their developers like to depend on as much libraries as possible).

So to make situation in this field less painful as possible, the last couple of days I was working on edelib-dbus-explorer (it comes with edelib from svn). With it, I was trying to address above issues that itched me for some time.

edelib-dbus-explorer (as you can see from the shot) looks much like qdbusviewer, in layout form, but adds scheme interpreter as the main communication point (or better say edelib-script, which is nicely packaged tinyscheme with a bunch of addons).

In a Smalltalk fashion, you explore services and objects, find some method and hit 'Send to editor': you will get a code snippet ready for evaluation. Then, you continue to write some more code, add another method call and at the end, save everything. Could it be more complicated?

edelib-dbus-explorer recognizes almost all DBus types (except signatures and file descriptors); return values will be converted to scheme objects (simple types to corresponding scheme values, like DBUS_STRING to string and complex to lists, or list of lists like dictionaries). For input types (those that serves as arguments to method calls), explicit type designation must be appended as DBus is picky if you use uint32 or int16 because signature is different.

But, explicit typing is not an issue: when is instructed to generate code, all types will be correctly placed with added REPLACE_ME placeholder, which must be replaced with appropriate values. Hitting Shift-TAB will jump between those placeholders.

Is this better than previous solutions? I'm confident it is and can be even better, which adds more room for improvements.

to be continued...