Thursday, April 13, 2006

plasma data engines

the last couple of days i've been working on plasma data engines, a concept that we discussed on kde-panel-devel. it is a response to the following issues:
  • writing things like cpu monitors, pim integration and IM status updaters is neither trivial nor "fun" so it should be done exactly once wherever possible
  • certain kinds of information (e.g. windows) are used by multiple desktop components (e.g. taskbar, pager, window lists) but that information shouldn't be duplicated everywhere
  • getting certain kinds of information takes time (e.g. the weather information) and shouldn't interfere with interactivity
  • artists and casual applet developers should be able to create new bobbles without having to become immersed in how the gritty details of things work if someone else has figured it out previously


for precedence here we have superkaramba's library that provides easy access to information such as cpu and memory usage; we have libtaskmanager which provides information for the taskbars and pager from one data model of the windows; we have the weather dcop service. so they provide some nice prior art to build on.

a dataengine in plasma is a way to encapsulate a set of data (a "model") that can then be easily hooked up to a visualization on the desktop (which includes panels, floaters, etc). here's a quick overview of the pieces.

datasource



a datasource is a simple class that provides a standardized API for something that needs to communicate a state to the outside world every so often. it provides a standard signal signature (void data(const DataSource::Data&) where DataSource::Data is typedef'd to QHash), allows the update frequency to be set (still working out exactly how to handle it when different items request different update frequencies) and gives itself a name (unique to the engine). datasources are data-only; no visualization.

so a visualization doesn't have to concern itself with what exactly the data represents (CPU? memory usage? temperature?) nor with how it's retrieved.

dataengine



an engine provides a semantic umbrella for a set of datasources as well as some management glue. each engine, along with its datasources, is loaded from a plugin via ktrader and is the gateway to the capabilities provided. in the current design they are assumed to be singletons.

it handles any initialization and post-usage cleanup needed, provides usage ref-counting, provides a listing of all its datasources (QStringList) and allows for a visualization to be connected to a DataSource. it also provides a query interface for on-demand information lookups.

engines will be provided for hardware, windows (the evolution of libtaskmanager), IM and more... essentially whatever can be dreamed up. beyond the datasources, engines can provide custom interfaces; so the taskmanager engine will provide signals and methods specific to window management. while that particular engine probably won't make a lot of use of datasource, it will still offer a simple and standard way to get at that API as opposed to today's custom linkage.

visualizations



visualizations are (at this point anyways) qgraphicsitems that can be used in a graphicsview. they have a standard slot that takes a DataSource::Data parameter. from there they can decide how to display the data passed in, allowing any visualization to be attached to any datasource (whether that results in something meaningful being shown is another matter, of course).

a set of standard visualizations will be provided for use like lego bricks when building new applets so one doesn't have to create their own visualizations all the time.

widgets / applets / plasmoids / plasslets / whatever they get called



this allows someone creating a new applet to do something along the lines of:

loadEngine("hardware")
Graph g
connect(g, "hardware", "cpu")


done. this way applets don't have to have any direct dependencies on engines since all standardized interaction happens via the applet base class which in turn passes requests to PlasmaAppInterface for fulfillment. some applets will need to depend on given engines directly, still, however for specific functionality (e.g. the taskmanager engine's stuff). i haven't (yet? ;) figured out how to abstract out such custom functionality that doesn't map nicely to the "data received, now display it" model that covers most needs without making it stupidly complex.

plasma's role



plasma sits in between all this insanity and provides loading and unloading of engines, calling the appropriate engine methods (e.g. connect) when requested from applets, managing ref counting (it knows about applets, engines don't, so it needs to tell an engine whenever an applet uses it and when it stops using it)

current status



it's still a work in progress, but it's taking shape nicely. trying to keep it as simple as possible and once the design is somewhat working i will be documenting it with pretty pictures and articles on how to write engines, data sources and use them from applets.

i committed some draft code yesterday and if i could get kdebase compiling today i'd commit some working code that builds on that =/ oh well, soon enough i'm sure.

leaving thoughts...



this is all a bit of a departure from how most applets have been written, both for kde and other platforms. my hope is that it allows people with domain specific expertise (e.g. window manager devs or hardware gurus) to provide low-barrier ways to get at that information while making it stupidly simple to create new widgets that do cool and useful things.

things that this design does not account for are needs like a standardized set of web tools (screen scraping, a class that wraps khtml to make it a one-liner for applet artists to get a canvas to draw on, etc) or standardized applet treatments, but these are completely different parts of the challenge that is plasma so that's ok. but they'll get similar treatments, so that all widgets can use the same brush (which may be a pixmap, a gradient, etc) quite easily for consistency.