Skip navigation.
KDE Developer's Journals

rich's blog

rich's picture

Advertising

Just watched a very clever advert for the new iphone.

  • It's a manual, it shows you how to download (and buy) new apps.
  • It's very short, just one feature
  • User ends up having fun - playing game, and then call from a guy
  • Interupting you in the middle of the game is presented as a feature!
  • Slogan about this changing everything (not sure how it's supposed to do so)

The advert seems well put together, but I wonder if we couldn't create something similar regarding KDE features?

rich's picture

Akademy 2008

As you've seen from all the stores on the dot and on planetkde this week has seen all the KDE
developers gathering in Mechelen in Belgium. The organisation this year has
been excellent - even the network (usually the achilles heel of KDE
conferences) has worked from day one.

As well as the usual socialising, talks and BoF sessions there has also been a
lot of coding. I've focussed on ksnapshot and plasma, KSnapshot gained a few
minor changes:

  • KSnapshot will now record the window title in the image if you've chosen
    to capture the window decorations. Hopefully this should be useful to indexers
    like strigi.
  • I've fixed the 'not saving settings' bug - it looks like kdelibs changed
    behaviour.
  • I've increased the JPEG quality setting a little so screen shots look nicer.
  • Tackat has persuaded me to look into writing a simple post processing app
    so that you can easily apply effects like screenie before you upload your pics
    to the dot.

The work on plasma was again to do with scripting, I first of all got the code
that was broken by the API changes fixed - this meant that the spinning
squares demo now works again. I then got the scripting support for the new
widget api working. You can see this in action in the screenshot below which
shows a calculator written in javascript using the plama widgets next to the
current C++ calculator.

This isn't quite ready to commit because the actual calculator logic is a bit
broken, but it shows that the widget support is nearly ready. In order to make
it easy to test this, I finished the implementation of package uninstalling in
plasma libs so that you can now use the plasmapkg tool to easily install and
remove scripted plasmoids.

I've done a little work on a few other things, but they're not quite ready
yet, so I'll save them for another post.

rich's picture

New Plasma Widgets Design

This is the draft design for a new widget API for plasma, it will be appearing on techbase later, but here's what we're thinking.

General Notes

The intention of this API is to provide a very simple way for users to create
plasma applets. The API can be used both for scripting and from C++. For the
simple javascript API, this API will be all that is provided allowing us to
run untrusted applets as they will not have access to any dangerous
facilities.

From C++ or more advanced scripting APIs (such as the 'full' Javascript
bindings) you can gain access to a pointer to the underlying Qt widget
contained within the QGraphicsProxy allowing you to access all of its
methods. For most simple uses however, this should be unnecessary as you can
do most of the customisation using the Qt stylesheet facilities.

All widgets have a stylesheet, which is a string property containing a Qt
stylesheet. This allows for simple but powerful configuration of the widgets -
for example you can configure the alignment of the text in the label using the
text-align property, or the font using the font property. Using this you can
do some extremely advanced interfaces without having to learn how Qt works.

A nice side effect of the way this API is defined is that it is possible to
implement the simple widget API inside a web browser using HTML, javascript
and HTML stylesheets to provide the implementation.
API Reference

Label

Constructors

  • Label(Widget)

Properties

  • Widget parent
  • String text
  • String image
  • String stylesheet
  • QWidget nativeWidget

Note that the image property is a string and specifies the name of the
image within the plasmoid package. The image can be either a bitmap (in any
supported format) or an SVG image.

PushButton

Constructors

  • PushButton(Widget)

Properties

  • Widget parent
  • String text
  • String image
  • String stylesheet
  • QWidget nativeWidget

Signals

  • clicked()

CheckBox

  • CheckBox(Widget)

Properties

  • Widget parent
  • String text
  • String image
  • String stylesheet
  • bool checked
  • QWidget nativeWidget

Signals

  • toggled(bool)

RadioButton

  • RadioButton(Widget)

Properties

  • Widget parent
  • String text
  • String image
  • String stylesheet
  • bool checked
  • QWidget nativeWidget

Signals

  • toggled(bool)

Note that a RadioButton must exist within a ButtonGroup, the group box ensures
that only one radio button is set at any one time.

Widgets To Do

  • WebContent
  • GroupBox
  • ButtonGroup
  • ComboBox
  • LineEdit
  • TextEdit
  • Meter
  • Graph
  • Throbber
  • Simplified versions of the QGraphicsLayout classes

Non-Widgets To Do

  • URLOpenner
rich's picture

Plasma Sprint Day One

After a day's work at the Plasma sprint, there's already quite a lot of news
to report. After a lot of trawling through log files, I was able to fix the
problem that was preventing the Plasma binding plugin from loading. In the end
it was something simple (as usual) namely that the method that allows the
plugin to load was not being compiled into the module since it was missing
from the generated .pri file. Once this was fixed, it was simply a matter of
changing the name of the extension we load from 'qt.plasma' to
'org.kde.plasma' to match a fix in the generator and we had a successfully
loading set of bindings.

Lots of thanks are due to Kent Hansen of Troll Tech
for this - not only did he write the binding generator and the type system for
the Qt bindings, he also fixed up the one for plasma. Oh, and if that wasn't
enough he's even figured out the bug that has been preventing the generated
code from having anti-aliasing enabled.

In order to test that these bindings worked properly, I wanted to create a
small demo that exercised the script engine code, the Qt bindings and the
plasma bindings in the same plasmoid. My initial attempt worked ok, but didn't
look very good (though it had the advantage of requiring only a tiny amount of
code). Instead, I'll show a slightly more complex example that looks prettier.

Obviously, you can't see the animation in the screenshot, but this shows four
squares spinning around a common axis at different speeds and changing
colour. Ok, it's not the best piece of graphic design you've ever seen but it
does illustrate that the crucial facilities are in place.

In addition to the coding, we also spent some time today going over the
results Seele obtained from her interviews with some of the developers. We
were looking at the user populations we are currently supporting well, but
more importantly at those that we could potentially encourage to adopt KDE and
Plasma to consider how we can improve the facilities we offer for them
too. Before anyone gets hot under the collar, this doesn't mean ripping out
functionality to 'dumb down' the interface, in fact a lot of the suggestions
were more about how we can improve the interface consistency.

Following this discussion we did some more coding and also broke down into
smaller groups so we could continue to plan for our inevitable world
domination.

rich's picture

QtScript Web Browser

As some of you may have seen, Kent has released the QtScript binding generator on Troll Tech labs. I've been playing with the code for a bit, and as with KJSEmbed one of the first tests was to make sure you could use it to write a simple web browser. Kent recently added support for QUiLoader to the bindings and as a result, I can use the QWebView designer plugin to make things simple. The result is a basic web browser in less than 10 lines of javascript:

var loader = new QUiLoader(null);
var file = new QFile("browser.ui");
file.open(QIODevice.OpenMode(QIODevice.ReadOnly, QIODevice.Text));

var web = loader.load(file,null);
web.show();

QCoreApplication.exec();

There's also a very simple designer ui file that just contains the web view and a layout. Here's the obligatory screenshot:

rich's picture

Qtscript Binding Generator

In 4.0 plasma had support for writing applets using Qt's built in javascript interpreter QtScript, but the facilities have been fairly limited. In KDE 3.x KJSEmbed gave us reasonably complete bindings to the Qt and KDE api's, allowing us to write applications such as a web browser in 10 lines of javascript. I'm glad to say that some plans that were discussed at the KDE conference in Glasgow are now a reality and Kent has released a qtscript binding generator based on the one used for QtJambi. The result is that we will very soon have good access to the Qt API from qtscript.

I've been playing with the output of the generator for a couple of weeks now and while it still has a lot of rough edges, it's definitely a solid foundation. Even better from my point of view as a KDE developer, the Jambi generator was designed from the start to allow you to use it to write bindings for Qt based code that is not part of the main Qt API. Using it to build bindings to the plasma APIs and in future the kdelibs API is definitely feasible.

rich's picture

XML Doesn't Beep

I learnt a something new about XML today, a part of the specification that deals one of the many edge cases that exist in every file format. To illustate this, lets take a look at a few examples. Why is this XML document well-formed :

<test>X</test>

this one also well-formed:

<test>& #9;</test>

But this document isn't:

<test>& #7;</test>

Note that I've added an extra space to these examples as the blogging software used by kdedevelopers.org seems to quote the characters required to make this appear directly.

To find out why it's broken, read on...

rich's picture

Programming Styles - Why Encapsulation is a Good Thing

I was reading a blog post on beautiful code about different styles of programming earlier this week. The author was comparing the 'ruby style' of direct access to member variables with the getter/setter pattern common in Java code. His basic question was is this simply a matter of your programming background?

Here's the Java version of his example:

public class GlazeObject implements Renderable {
    private ClassStore store = new DefaultClassStore();
    private Formatter formatter = new DefaultFormatter();
    
    public void setStore(ClassStore store) {
        this.store = store;
    }
     
    public void setFormatter(Formatter formatter) {
        this.formatter = formatter;
    }
	
    public void render()
        …
    }
}

As you can see the Java version doesn't permit direct access to the members and instead uses accessor functions. For me, this is a good solution because I expect my code to evolve over time. Lets look at a couple of possible future versions of the same code:

public class GlazeObject implements Renderable {
    private ClassStore store = new DefaultClassStore();
    private Formatter formatter = new DefaultFormatter();
    private int expensive = 0x1234;

    public void setStore(ClassStore store) {
        this.store = store;
    }
     
    public void setFormatter(Formatter formatter) {
        this.formatter = formatter;
        this.expensive = doCalculation(formatter);
    }
	
    public void render()
       // Use precalculatede expensive value in fast path
        …
    }
}

In this future, we've discovered through profiling that one of the calculations we need in our render function is a performance bottle neck. To avoid the issue, we precalculate the value and simply use the cached version. Having accessor functions makes this trivial - we don't need to track down every use of the member variables and fix them as we have acheived proper encapsulation.

Of course, the future could be different. How about if we discover that the particular instances of the above object are often obscured so we don't need to render them. Well, now we might code something like this instead:

public class GlazeObject implements Renderable {
    private ClassStore store = new DefaultClassStore();
    private Formatter formatter = new DefaultFormatter();
    private bool dirty = true;
    private int expensive = 0x0000;

    public void setStore(ClassStore store) {
        this.store = store;
    }
     
    public void setFormatter(Formatter formatter) {
        this.formatter = formatter;
        this.dirty = true;
    }
	
    public void render()
       // Calculate expensive on first use then reuse it
        …
    }
}

Again, we're saved by our encapsulation. It's easy to make when the cached value needs updating because all accesses are via a single method. The downside here is that the first call to render() after the formatter is updated is slower than subsequent calls, but that is generally a good trade off.

Now all of the above examples are in Java, where we have a much more modern object format than is available to us in C++. In C++ we have to consider the dreaded binary compatibility. A C++ version might look something like this:

class GlazeObject : public Renderable
{
public:
  void setStore( ClassStore *store );
  void setFormatter( Formatter *formatter );
  void render();

private:
  class GlazeObjectPrivate *d;
};

class GlazeObjectPrivate
{
public:
  ClassStore *store;
  Formatter *formatter;
};

Here we're using the PIMPL pattern (a d pointer) to conceal the internal structure of the object from callers. This means we can change the implementation without needing to recompile things that are calling our object. Again as you see encapsulation gives us a big win. Programming is always a matter of trade offs, but frequently the good choice for the long term is to write a little bit more code and separate concerns.

rich's picture

EEE PC

I finally got my hands on an EEE PC on Friday after having waited for nearly a month for the one I ordered by mail order to arrive. I found out that 'Toys R Us' had some stock and checked that the one in manchester had some. Now I've just got the difficult decision of whether to cancel my original order or not!

The device itself feels a lot more solid than I was expecting, and the pearly white look is actually rather nice. It comes with KDE 3.4 installed, but with a cut down launcher UI. Switching from the 'easy mode' to a real KDE desktop only took a couple of minutes, so I now have a tiny KDE laptop!

I had some trouble getting it onto my home wifi network, but giving it a static IP address has meant things now work fine. Given that the forums indicate no one else has had a problem, I suspect the problem was something specific to the way my network here is set up.

The set of installed software is impressive - in fact most of the things I was planning to add in turned out to be there already! Some of the highlights I've noticed so far are:

  • Python 2.4.4
  • ssh
  • krdc (VNC client)
  • mplayer (all the video files I've tried worked first time)
  • konqueror, konsole, ksnapshot, etc. etc. Basically all of the common KDE applications.

One thing that really impressed me is that it comes with the python Qt bindings included making it very easy to write tools to overcome any missing pieces I find. One that I've started some UI mockups for is a backup application which will be my first chance to play with Qt programming in python.

Another neat feature is that the supplied media includes a tool to put a bootable rescue image onto a pen drive - this means that I can feel quite free to replace the Xandros install it comes with if I want to. Putting the image from my mandriva pen drive (or the image for the intel classmate) onto the EEE for example should be easy.

Now it's time to get started trying to put some code around the UI mockups for my backup tool, and learning the python side of Qt programming.

rich's picture

QtScript is also good for tiny things

Here's a quick example of why it's nice to have a script interpreter embedded in Qt: Plasma's KRunner has a calculator which used code borrowed from the KDE 3.x minicli. The old code started up the bc command line calculator then displayed the result - not exactly an efficient way to do things. I've just committed a change that makes it use QtScript and the code is trivial:

QString CalculatorRunner::calculate( const QString& term )
{
    QScriptEngine eng;
    QScriptValue result = eng.evaluate( term );
    return result.toString();
}

This replaces 23 lines of code and is quite a bit more powerful. Nice!

Syndicate content