ChaniBlog











I’ve been meaning to blog about this for ages, but I seem to have writers’ block. Time to break through it!

Going from desktop kde/qt programming to mobile and web development has been quite a change. Some of the lessons I’ve learned along the way, I wish I could have read about instead of walking into. So, I’m writing about them now to save the next person from that. :)

Let’s start with node.js. I love node.js, it’s a lot of fun to work with. A shame there’s always web browsers at the other end. ;P But, node is a place where you are guaranteed to run into one of javascript’s biggest annoyances:

Callback hell

Now, for KDE programmers, callbacks might not sound so bad. Signals and slots are technically callbacks, right? And they’re easy and fun to work with. But when you strip away all that nice abstraction, you get a lot of ugliness. Ugliness like this:

doAsyncThingOne(data, function(error, result) {
    if (error) {
        ohshit();
    } else {
        doAsyncThingTwo(data, function(error, result) {
        if (error) {
            ohshit();
        } else {
            doAsyncThingThree(data, function(error, result) {
                if (error) {
                    ohshit();

…and so on. (sorry about the ugliness of the code formatting, that’s what you get on a free wordpress account.)

And that’s assuming that all your async methods use the “data, callback” pattern. it’s a popular one, but there’s another popular pattern, “data, successCallback, errorCallback” – and sometimes “data, {success:callback, error:callback}”. And then there’s the question of what pattern they expect for those callbacks you’re passing in – is it “error, results”? “results, error”? Something Completely Different?

It can get to be quite a headache quite quickly when the libraries you’re working with don’t all use the same pattern, and you always have to remember which one expects which. and there’s no compiler to warn you, either – you just get things breaking horribly or, just as often, silently dropping bits on the floor.

Cleaning it up

Fortunately the majority of libraries I’ve worked with follow the pattern in my example – including async, a library purely for reducing the pain of callback hell. Async can get that awful example down to something more manageable:

async.waterfall([
    function thingOne(next) {
        doAsyncThingOne(data, next);
    },
    doAsyncThingTwo,
    function thingThree(dataFromTwo, next) {
        doAsyncThingThree(dataFromTwo, function (error, result) {
            if (result.isCool()) {
                next(null, result);
            } else {
                next("not cool!");
            }
        });
    },
], function finalize(error, dataFromThree) {
    if (error) {
        ohshit();
    } else {
        yay(dataFromThree);
    }
});

note that since thingTwo fit async's callback expectations perfectly, we didn't even have to wrap it. :)

However, this is still pretty inflexible – what if a particular result from thingOne means that you can skip things 2 and 3 but still need 5? I've heard that Promises are more flexible in this regard, and I plan to try them out sooner or later, but I'm not sure what to do about all the libraries that don't offer a promises api. We shall see.

The ‘dummies’ part

Now, I actually got way off topic there. There’s a different problem with callbacks that inspired this blog post. I felt really goddamn stupid when I noticed I’d done it, but then I realised… everyone else working on the project had also done it somewhere.

See… the thing about callbacks, is that when you take one, you're promising to call it once, and exactly once. Not twice, not zero (excepting that thou then proceed to one ;). What we had was some callbacks that might never be called, and some that were always called twice. Or more.

Oops.

So, yeah, don't do that. It’s bad.

And… that’s it, really. I keep feeling like I should have more to say about it (One shall be the number of the counting, and the number of the counting shall be one?) but it’s just a matter of checking your code. And hopefully keeping the methods simple enough that checking the callback call doesn’t require a state diagram. :)

If you want more information, just google “callback hell”. There are plenty of other blogs about it. :) (ooh, Elm sounds interesting…)

Advertisements


{October 27, 2010}   opensuse plasmoid workshop

okay, I promised I’d blog about this… me and Will did a plasmoid workshop on saturday. :)
There are no slides, because the whole thing was an interactive sort of tutorial, using this suse live image. In order to show off the qml bindings, we needed the latest kde stuff from trunk. The live-image gives us that, and a guaranteed working development environment in general. :) It also has the cool feature that it will write back to the usb stick, so you can shut it down without losing your work.

There were two example projects we worked through, one for javascript and one for qml. They’re both my old victorycalendar example, but with a bit of polish. :) The qml one doesn’t go all the way yet – just as far as I’ve figured out so far. :) We have lots more qml examples, though – iirc they’re hiding in the mobile shell in playground. And of course there are more javascript examples too. :)

To get my javascript example, run this command:
git clone git://git.kde.org/scratch/chani/examples-plasmoid-js.git
and, of course, change the js to qml to get the qml one. :)

I used git repos for my examples so that I could easily break them up into simple steps, and have everyone go through them in order. The idea is that you git checkout step01, and then each of the steps in turn (this was broken during the workshop but is fixed now). The git log has comments on each step, although not as much as in my blog. :) Also, if you make changes, you can either commit them or git stash when you want to jump to the next step. Later, I may add some side-branches with other fun features… I might also rewrite history, though, if I find a better way of doing something. If git refuses to pull someday, that’ll be why. :)

To test the plasmoids all you have to do is run plasmoidviewer in the folder containing metadata.desktop (or run it with the path to that folder). If you want to install it so that you can try it in plasma-desktop or other shells, use plasmapkg (there’s documentation, plasmapkg –help). To make it into a .plasmoid package that you can send to others, just zip it up. :)

Oh, and although most of the resources you’ll want are mentioned in the git log, I missed a couple:
The Plasmoid Package Specification
The Plasma JavaScript API

Have fun! :)



time for more javascript! yay.

First, a quick little thing: my last javascript post was slides from my LFNW presentation, which had an extra little thing about dataengines. I never did blog about that code, though.
It’s pretty simple. I wanted the time engine to give me an update once a day, so that I can reset the flag. For demonstration purposes, though, once a day isn’t so great, so I set it to reset every ten seconds instead.


plasmoid.dataUpdate = function(source,data)
{
progress.setIcon("flag-red");
progressValue = 0;
}
engine = dataEngine("time");
engine.connectSource("Local", plasmoid, 10*1000);

I define my dataUpdate function, which gets the source and data – but doesn’t actually use them. It just resets the flag back to red (maybe later I should set it to double-check the date, in case there’s a forced update). then I grab the time engine, and connect the local time to my plasmoid with an update of ten seconds.

now for something a bit harder: I want more than one task.

So, first attempt. I put the task creation into a function, and calling this function made things work just the same as before. So far so good. Next, I changed all references to the label, icon and progress counter into arrays. New tasks are appended to the end of each array, and the dataUpdate clears them all. the config UI only controls the name of the first task for now; a second one is hardcoded in there.

Then I realised that the slot for changing the flag could only work for one icon. huh. :/ maybe it would be possible to add the function to each icon? but it’d still not know its index in progressValues. what I really want here is for the label, icon and counter to be wrapped up in their own little class. and if that class was a widget with its own layout, then I could easily stack them vertically instead of having everything all in one row.

I haven’t a clue how to do classes in js though. inheriting graphicswidget, creating slots…
well, I read up on javascript prototypes, and found out about the extends keyword… but I bet we don’t have QGraphicsWidget in the js bindings. :P ok, for now I’ll skip the inheritance.

I spent a long time trying to understand how to do classes in javascript. It’s weird. It hurt my brain (probably didn’t help that I was half asleep the whole time). I did get it working eventually, though. and then discovered that connecting signals and slots in javascript didn’t work quite as I thought it did. if you want to connect to a function that’s in your class, you have to use either foo.mySignal.connect(this, this.mySlot) or foo.mySignal.connect(this, “mySlot”) – with these it refers to the function in the class (not a global function) with “this” properly set.

Here’s the code using classes – I ended up reorganizing the code a bit in the process. There’s the Task class constructor, which sets up all the variables (label, icon and progress counter) and layouting and connections. Then there’s the reset function, which is called on timeout, and the moreProgress function, called when the icon is clicked. After that I have some setup code that creates two Tasks, and the old dataengine and config stuff. Only the name of the first Task is configurable, still (and I’m being bad and setting it directly instead of putting a function in the class for that).

So now what? Well, the layouting is ugly. Let’s see if we can improve it a bit. Wow, I managed to crash plasmoidviewer. It doesn’t like me doing new LinearLayout(plasmoid) more than once – riight, because the plasmoid itself can only have one controlling layout. I want new LinearLayout(layout) to have layouts inside layouts. Fixed that, and now I have nested layouts. :)

Notice that the flags aren’t aligned with each other. that’s what happens when you put hboxes in a vbox instead of using a gridlayout. I could hide it by putting the icon on the left, but really I should do it properly…
uhm. looks like we don’t have gridlayout bindings ATM. we do seem to have qgraphicsitem bindings… but I don’t want *those* any more, because with a gridlayout there’d be no point.

Oh well – I think that’s enough for now. I’m going to go work on something else… or see when lunch is… :)



I’m starting in ten minutes. oh boy. my slides are here

there’s an extra bit added to the victory calendar for the presentation – dataengines. I might poke at that code some more and maybe blog about it later…

update: one thing I forgot to put in the slides is that the key value in main.xml must match the widget in the .ui file that you want to control it. if you have key=”foo” you need the widget’s name to be kcfg_foo

update 2: plasmoidviewer is now easier to use thanks to aaron :)



{February 7, 2009}   adventures in plasmaland, part 4

tokamak is going well, and I’m hacking again. I decided it’s time for my victorycalendar plasmoid to get a config dialog. to start off, we’ll just try to configure the text of the label.

[oops. it seems I forgot to blog about my last bit of work. quick detour: it now uses flag icons and cycles between three colours when clicked. didn’t take much code. here’s the diff.]

sooo… we need a config file. from the package spec we see that it should be at config/main.xml and from the kconfigxt tutorial we’ll learn what to put in it.

I’m not going to repeat that tutorial, so go read it. at least the bit on the contents of the xml file. ignore the c++ generation stuff – obviously we’re not using c++. :)

so I’ve written a very simple config file now (I copied the crud at the top from an existing file). all it has is an entry for the label. next step: making a config ui to set it with.

this one goes in ui/config.ui, and of course I’ll be making it in Designer.

it’s pretty easy: a label and a lineedit. the important bit is that the linedit is called kcfg_label, to match the “label” name in main.xml.

so… er… I have these files. now what?
now it crashes, that’s what. :) kconfigdialogmanager doesn’t seem to like my config ui.
…turned out to be something that needed adding in libplasma, and aaron fixed it for me. :)

anyways. now we have a config dialog, and it saves its one setting… time to actually *use* that setting. :)

taskName.text = plasmoid.readConfig("label");

that gets us the right value on startup. now we need it to update when hte config is changed. for this, we implement the configChanged function, and… umm… do something. something like this:


plasmoid.configChanged = function()
{
taskName.text = plasmoid.readConfig("label");
}

except… that function isn’t getting called. looks like I hit another bug. aaand that’s fixed too now. :)

whee! now the text is all nice and configurable. I think the next step will be to add multiple rows.

oh, btw – I won’t be working on the kconfigmenu plasmoid any more. sebsauer beat me to it: if you add the traditional app launcher and configure it to hte system settings view, you get exactly what I was aiming for. :) this is a good thing; I have no shortage of stuff I want to work on.



{January 18, 2009}   adventures in plasmaland, part 3

it’s day… 2? now, and near the end of the presentations I got the urge to write code. so now I bet everyone else is in the ocean, but I just can’t tear myself away until I get a few more bits working. :) perhaps it’s a good thing the internet is being crap, or I’d end up on irc… although not being able to commit is a PITA, and will make it harder for me to show incremental code improvements. we need git.

anyways, I started a new plasmoid. I think I might rewrite the other one in C++ – it’s either that or write a bunch of bindings or write a dataengine. but this new one should be more suited to scripting. it’s something pete calls a “victory calendar”. the idea is that you have a list of tasks that you need to do every day (like studying a language or doing pushups), and every day you record whether you did a lot, a little or nothing for each task, and so long as you don’t have lots of nothing you reach victory. :) recording your progress is meant to motivate you to actually do things – either by showing you that you’ve been slacking off, or showing you that you’re doing well – either way you’re less likely to forget about it and give up.

so, being lazy, I start by copying my last plasmoid. then we change the metadata – we need a name, icon, description and sane default size – and delete half the crap in the old code. now we’ve got something we can install and run and it shows a pretty icon. :)

next, I added a label.

layout = new LinearLayout(plasmoid);
layout.setOrientation(QtHorizontal);

//start with one task and name it
taskName = new Label();
layout.addItem(taskName);
taskName.text = "do something"; //setText doesn't exist. interesting.

I stole this code from the nowplaying example. what I found interesting is that it’s using the qt properties system, so instead of taskName.setText(“do something”); we have taskName.text = “do something”;
while adding the label, I also set the layout to be horizontal. I’ll need a better layout later, but for now I’m just making one task with one day’s record.

so, that pretty icon… that turns into the progress indicator. :)

progress = new IconWidget();
progress.setIcon("view-calendar-tasks");
layout.addItem(progress);

//and the icon does something!
plasmoid.moreProgress = function()
{
print("triggered!");
progress.setIcon("configure");
}
progress.clicked.connect(plasmoid.moreProgress);

we make a function to change its icon, and connect that to its clicked signal. we’ll need three states with appropriate icons soon, but for now I’ll just make it change back to the configure icon.

victory!

and so another plasmoid has begun… and I want to go to the beach now. :) after we get that progress icon working we’ll need to configure the name of the task, allow more than one task, then track and display data from previous days.



{January 8, 2009}   adventures in plasmaland, part 2

we’ve got a bit more in the way of javascript bindings, and only one of my teachers has posted homework, so I decided to work on kconfigmenu some more. :)

now that it can install and run, I want it to display a pretty icon. so, first thing, we create an icon:

icon = new IconWidget();
icon.setIcon("configure");

re-using kde’s confiugure icon once again. :)
but it turns out that plasmoids have no layout by default, and that’s not good… so at the top of the file we have to create one, and then after out icon is made we have to put it in the layout.

layout = new LinearLayout(plasmoid);
icon = new IconWidget();
icon.setIcon("configure");
layout.addItem(icon);

now, unfortunately javascript plasmoids are defaulting to 200×200 on the desktop, and if i try to resize my plasmoid it overrides the configured size every time plasma restarts (a Bad Thing). that’s gonna have to be fixed in the bindings; until then, I start with a ridiculously large config icon. :)

Update: fixed! I made it possible to set a default size in the metadata :)

now that that’s working, the next step is to figure out how to put things in hte contextmenu.
ideally my code should pop up a menu on left-click instead, but I’m going to be lazy right now and try to get it working before I get it pretty.

getting a dummy action in the contextmenu was easy. copy&pasted this from the tiger plasmoid:

plasmoid.setAction("myAction", "Select Me!", "plasma");

plasmoid.action_myAction = function()
{
print("myAction triggered!");
}

and once again I’ve committed it.
it even has an icon! :)
the action

now, what we want is some data to make actions out of. if I was using c++, I would start with KService::List modules = KServiceTypeTrader::self()->query("KCModule"); – but I’m not. I’m just using a simple javascript API. there *is* a dataengine that will execute arbitrary commands, and kcmshell4 can output a list of all the modules… but then I’d have to parse the list, and I’d only get the module name (in a not-very-userfriendly form) and the description (which isn’t always something I can show as a title either).

hmmmmm. I’m gonna have to think about this next step a bit.



{December 29, 2008}   adventures in plasmaland, part 1

huzzah! I finally fixed all of plasma-overlay’s known bugs, and made the config ui actually work :) it only took a couple of days to round up the last few things, surprisingly. now I finally have the option to write code that is *not* bugfixes for my damn soc project.

I think it’s about time I did some fun little plasmoids instead of working on big crazy things. yes, we’re in feature freeze, but I’ve been bugfixing for 4 damn months :P I need a break. I have a ton of ideas for small, (hopefully) simple plasmoids and I want to try them out. I also thought it’d be fun to try and do them in ecmascript (or javascript or qtscript or whatever you call it) to see just how hard it is to do this. :)

so, join me as we dive into plasmaland and try to create a brand new widget fropm scratch without any of that silly crashy c++ :) right now I have no idea how to do this; I knlow plenty about plasma internals, but almost nothing about the language bindings or how a modern widget needs to be made.

let’s start with techbase. hmm. plasma’s tutorials page has a c++ tutorial… not quite what we’re looking for, and I’m not sure whether it’s up-to-date, but it’s sure to give us *some* useful info.

well, looks like we need a .desktop file to start out (ok… I already knew that from seeing them in every applet’s folder, but I had forgotten). there’s a nice little example here to copy, or I could grab one from an existing applet.

as for other files in the plasmoid… I imagine this will depend on whether I want to make a plasmagik package that can be bundled up and downloaded easily (hooray for GHNS) or just a folder in svn that can be compiled and installed like the oher c++ plasmoids there. hmmm. well, I can only find one scripted plasmoid in playground and it’s not being compiled, so it’s time to ask for help.

ok, so it turns out that while it’s *possible* to have a scripted plasmoid that gets installed when I compile and install from svn, it’s a small amount of extra work (that of writing a proper CMakeLists.txt) and I first have to have a regular plasmagik package anyways. the usual method of getting scripted plasmoids to show up in plasma is either the “install new widgets” button in the add widgets dialog or `plasmapkg -i` – so let’s start with making a regular package and maybe I’ll fiddle with cmake at the end. NTS: the install button only works with zipped packages; unzipped folders can only be installed manually with plasmapkg.

so I guess before I should go any further I should probably tell you what plasmoid I’m writing. :) I’m going to make a little popup menu that lists all the kcm modules (spot the redundancy ;) because I just don’t like the new system settings app. in kde3 I found a little applet that gave me quick access to any config module from my panel, and I miss it. I’ve already memorized where most of the options were in that old tree structure, so I might as well keep using it.

this should be pretty simple: all I need to do is get a list of all the modules, display that list (preferably within categories), and then have the config module launched when its entry is clicked.

so, we start at the very beginning with a folder. I hate thinking up names for things, so… let’s call the plasmoid kconfigmenu. now, according to the plasmagik structure, we need a metadata.desktop and a contents/ folder. apparently we should have a metadata.xml too, but there’s no real explanation of that, so we’ll skip it for now (the tiger plasmoid seems to do just fine without one).

so, what to put in our metadata.desktop? well, let’s steal one of the examples and modify it to suit our needs. change the name and comment, pick an appropriate icon (I’m not going to be making any of my own art for this, just using existing icons), set the author and so on… that techbase page mentions some other options that aren’t shown (like a minimum plasma version) but I’m just going to skip those for now.

now that we’ve got our metadata, maybe we can put in some code. we need a code/ folder in contents/ and then a file called main.js in code/.

so now… what the hell do we put *in* this main file?
haven’t the foggiest. my knowledge of javascript is pretty faint, too. but let’s start by trying to make an applet that fails to launch with a specific message: that should be easier than trying for some hello-world with widgets right away, because Applet has a setFailedToLaunch function and I should be able to figure out how to call that in javascript, right?

from looking at the tiger plasmoid, I get the impression we start with an applet already existing, conveniently called “applet”. ok, let’s try using that.

well, I installed it, and it showed up in the appletbrowser all pretty, but actually running it didn’t go so well. it failed to launch, yes, but with the wonderfully unhelpful message “script initialization failed”.

next step: running it in plasmoidviewer. from there it’s easy to watch the debug output, and among some odd things that make me question the sanity of the bindings, I see this:

QScriptApplet::reportError: Error:  "ReferenceError: setFailedToLaunch is not defined"  at line  3

ouch.

so… do the qtscript bindings not expose that function, or am I doing something else wrong?

several hours later…

they don’t have it. they’re also missing a bunch of other stuff. I’m gonna go into technical details now that are farily irrelevant to people only wanting to *use* the bindings and not actually understand them.

So I fixed a blatant bug in libplasma and added a couple of functions; seems we have this AppletScript class that has to exist to expose protected members, because bindings can’t access those and they cover fairly important bits of Applet. had to add some methods to that class; there are probably more things that’ll need adding later, but let’s just get config and failedtolaunch stuff working first.

so then in the qtscript bindngs there’s a QScriptApplet that inherits AppletScript and does some odd binding-magic… it exposes the applet directly, which is fairly useless because only slots (and maybe qinvokables, etc) are actually accessible that way. it also has a half dozen static methods, some of which expose useful Applet functions and some of which do other strange but presumably useful things. I started trying to add functions here to expose AppletScript API, but then I realised that that way lies madness. I also find it really weird that things like update and setLayout are static functions that jump through strange hoops to get an applet pointer. it’s already weird enough that we’ve got some things accessible through applet and some as top-level functions (from the script’s point of view).

I decided the sane way to add a bunch of functions that merely expose AppletScript API would be to put them in their own class and have QScriptApplet expose an instance of that… then I realised that doing that meant I could also give my new class functions to expose bits of Applet that couldn’t be directly accessed. yay! to the script it’ll look like just one happy applet object.

another hour or so later…

huzzah! I have an interface… it only has one function, setFailedToLaunch, but that one function does work. :) now I just have the long task of writing a function for every useful method… *sigh*

hello world!
we’ll continue writing this applet after I write myself some bindings. ;)

goddamnit fuck. I had another whole day’s worth of writing here, and it just vanished into thin air when I pressed the save button. wordpress and konqueror are both pissing me off a lot recently. :(

I don’t feel like rewrting it all. suffice it to say, qtscript is weird and hates enums and its documentation about them is wrong to boot. still, I made the damn things work in the end. for certain values of ‘work’.

I’ve spent all day working on those bindings. not exactly what I’d planned, but it is fun. :)



et cetera