🏠 Go home.

Elegance, code, Ryan"January"Rix and feeling forky -- or why I haven't blagged abou SoC lately

Published on

My summer of code had hit a bit of a dead end between some Nepomuk woes (your week is up Vishesh ;) ) and some general issues with plasma integration in all of the plasma-related SoC projects… Half of that is hopefully solved with a bit of a nice solution, imo, which Aaron came up with at Akademy

At Akademy, Aaron talked a lot about Elegance; in our interface, our applications, our API. Make things fun to work with, easy, organic. It's something we should strive for, and something that I have strove for in my code; sexy code is a hell of a lot more fullfilling than ugly hacks.

Since the beginning of SoC I have had the interesting task of making sure that applications have some sort of way to talk to the KPart I have been working on (which is now feature complete enough for me to start cleaning up the code for kdereview and eventually kdebase-runtime, w00t), which is incredibly difficult because KParts simply aren't designed for that. There is the KTextEditor interface, but that is really the only way which most KParts have to communicate, and that isn't an interface that makes sense to implement in Plasma::KPart. So a new solution was necessary. This is simply because you cannot link with KParts, they have to be their own separately loaded entity. The next obvious solution is to implement an API via signals and slots, which is done at runtime, rather than compile time. I did some research on this, and some testing and playing…. It works in some cases but it still has a lot of limitations, and is not very elegant – it's a fairly ugly hack quite frankly. :)

QWidget* ContainmentShell::createConfigurationInterface(KDialog** parent)
            connect(this,SIGNAL(sigCreateConfigurationInterface(KDialog**)), m_part, SLOT(createConfigurationInterface(KDialog**)));
            emit sigCreateConfigurationInterface(parent);

Okay, that "works", but it's ugly as a general solution to do everything. Since this is specfic to the KPart, I have no real qualms in leaving this in here, it makes things just a wee bit easier in the long run, not having to maintain Yet Another Abstract Base Class in kdelibs, but i can't sanely make this the solution for all of the KPart's problems. It also would not work for one of the use cases I needed, passing a pointer to Kontact's KontactInterfaces class (which is used to control various applications when they are embedded in Kontact) through three or four layers of loaded, non-linked KDE Plugins (kontact plugin, to the kpart to the applet) I floundered on all of this for a while, completely missing the obvious part of the solution: Add something to libplasma itself. And thus Aaron brought some sanity to my mind, in the form of a new libplasma class: Plasma::PluginLoader

Fixing things where it matters

While at Akademy, Aaron explained to me in a fashion which I could grok (far better than over IRC, IRL provides so much more bandwidth), and it turns out that this class would provide a solution to my problems, and some problems in two other SoC Projects (Siddharth and Shaun) and the integration work of Aleix Pol to put a Plasma Dashboard into KDevelop, which is win. Yay for code sharing! :) To be 100% honest, I am not really very well versed in C++, I mostly bumble my way through my work based on my C knowledge… This includes the fun of inheritance; most of that is like trying to learn brainfuck for me. That made Aaron's proposed solution a little… hard to grok at first for me.

The basic idea was to add a class to libplasma called… ExternalAppletLoader, or something like that, which would be an Abstract Base Class which would allow Plasma::Applet::load to call back into the application hosting the Plasma shell, and allow them to supply Plasma::Applet* which can be added to the shell. By sticking this right in libplasma you get a lot of stuff for free that you wouldn't get by adding it to Plasma::KPart….. loading and saving of external (from within the application rather than Plasma) applets comes for free, for example, which is a big blocker. Before this, applications would have to store the layout configuration of applets which were supplied by the application themselves, now it is simple to let Plasma do this, and as long as the plugin names are the same across sessions, Plasma will ask the application to load the applets when Containment::loadLayout or Containment::initializeLayout is called.

Even harder to grok was my lack of knowledge with C++'s use of static class members. My initial implementation was a KGLOBALSTATIC singleton, but meh, that code wasn't very pretty, something like:

manager = PluginLoaderManager::getPluginLoader

                  if( manager)
                  loader = manager->getLoader()
                  if( loader)

… by moving the manager code into PluginLoader, this became a lot cleaner, a lot more elegant:

loader = PluginLoader::pluginLoader()


But of course, statics, etc, confuse the hell out of me, and that was far too confusing. Even more confusing was me being completely stumped by some linker issues when I tried to subclass PluginLoader… which weren't related to all the linker hell I was having while playing with statics (yes, you actually have to make sure they exist, kinda like externs in C :P). Sometimes you get so drawn into a particular mindframe when debugging, you completely miss the obvious:

22:31 ( rrix) I feel like a dork not being able to get this working ;( 22:32 ( Chani) rrix: the most frustrating bugs usually end up having the most stupidly obvious causes 22:32 ( sreich) yep, we all have them 22:33 -> rrix knows 22:33 ( Chani) so, you'll feel like even more of a dork when you fix it ;) but that's normal 22:33 ( rrix) still doesn't keep me from feeling forky :P 22:33 ( rrix) dorky <hack and slash with teh aaronz> 22:50 -> aseigo laughs 22:50 ( aseigo) rrix: dude, look in kpart/shell/CMakeLists.txt 22:51 ( aseigo) rrix: there is no ${KDE4PLASMALIBS} :) 22:51 ( aseigo) rrix: easy fix! :) 208113 22:51 -> rrix cries 208114 22:52 ( Chani) rrix: told you ;)

Urk…. :)

So, as of my commit last week, KDE Development Platform 4.6 will have a class that anyone willing to implement Plasma in their application can take advantage of to provide dynamic Plasma::Applet, Plasma::DataEngine and Plasma::Service to their Plasma shells. It is as simple as subclassing Plasma::PluginLoader and reimplementing internalLoadApplet, internalLoadDataEngine and internalLoadService, to return either null or the corresponding class. You can see this in action, somewhat, in trunk/playground/base/plasma/shells/kpart/shell/testshellpluginloader.cpp and testshellpluginloader.h. It just does some kDebug output, and doesn't load any objects, but it shows roughly what you have to do.

plasma-kpart-shell(9993) TestShellPluginLoader::internalLoadApplet: loadApplet called with "newspaper" 1 ()
                  plasma-kpart-shell(9993) TestShellPluginLoader::internalLoadApplet: loadApplet called with "news" 1 ()
                  plasma-kpart-shell(9993) TestShellPluginLoader::internalLoadApplet: loadApplet called with "org.kde.specialdates" 5 ()
                  plasma-kpart-shell(9993) TestShellPluginLoader::internalLoadApplet: loadApplet called with "opendesktop" 3 ()
                  plasma-kpart-shell(9993) TestShellPluginLoader::internalLoa
                  dApplet: loadApplet called with "weather" 2 ()
                  plasma-kpart-shell(9993) TestShellPluginLoader::internalLoadDataEngine: loadEngine called with "calendar"
                  plasma-kpart-shell(9993) TestShellPluginLoader::internalLoadDataEngine: loadEngine called with "akonadi"
                  plasma-kpart-shell(9993) TestShellPluginLoader::internalLoadDataEngine: loadEngine called with "ocs"

The Future

Right after I committed this to trunk, Aaron moved the entire loading logic for these classes into the PluginLoader, which is nice, because the code becomes a hell of a lot cleaner :)

There are a few things that may be missing still, and I will probably implement over the next few days or today, depending on what I do tonight. (possibly another incoming post, to prove that I have more things to spend my time on than awesome blag posts)

For example, right now, there has to be some logic to actually expose these applets, how do you tell the user they even exist? They don't appear in the AppletSelector (which works again, thanks to the awesomesauce of Aleix Pol's implementation of KDevelop's Plasma Dashboard), how does the user go and add them? That is probably next, a function in PluginLoader which returns a Plasma::Applet::List. Services and DataEngines are more dynamic, and I can probably get away with applications knowing that they are needed and exist (since they're written by the same people, most likely).

Here's to one step closer to Plasma's world domination! :)

PS: Expect some cool stuff upcoming in Plasma's calendar applet, the team will be coming up with a few verrrrry interesting patches for it ;)

Respond to this note:

Ryan Rix is a privacy rights advocate and net-art wannabe. Reach them on the Fediverse as @rrix@cybre.space, twitter as @rrrrrrrix, via email to ryan@whatthefuck.computer or on Facebook or on Matrix as @rrix:whatthefuck.computer.