Kde4

The Desktop Is Still a Workbench

I ran today’s KDE 4 session long enough to open a ported application, play a sound through Phonon, and watch a Plasma applet redraw. Then the panel vanished after a configuration change.

That sequence is a useful status report. The architecture is becoming tangible, but this is still a workbench, not a finished desktop. Ported applications exercise Qt 4 and the new libraries. Plasma prototypes test containment and data ideas. Solid and Phonon test boundaries around hardware and multimedia. Integration exposes where those boundaries disagree.

My current smoke test is intentionally small:

cmake ..
make
ctest
startkde

The last command belongs on a test account and display. Configuration formats and services are moving, and preserving my everyday session is more valuable than proving bravery.

I prefer testing one complete path, such as device arrival through Solid to an applet update, over collecting screenshots of disconnected pieces. The caveat is that integration failures can obscure which component broke, so each layer still needs its own focused test.

Today’s vanished panel turned out to be a containment lifecycle mistake, not a rendering failure. That distinction is the work now: finding ownership, sequencing, and API problems while change is still affordable.

It is exciting work. It is also unfinished work. Both statements fit comfortably in the same build, though not always in the same process.

CMake Build Trees Are Disposable

My KDE 4 build kept compiling code for a library I had just disabled. I checked the option twice, added a loud message to CMakeLists.txt, and still got the old generated header. The compiler was not being stubborn. I was looking at leftovers.

The first clue was CMakeCache.txt: the build directory had been configured against another source checkout. The second was a generated config.h whose timestamp did not move when I reran CMake. An earlier configure had put a copy in the source tree, and that directory appeared first in the include path.

make clean did not help. It removed compiled output known to the generated makefiles; it did not remove the cache, old makefiles, or a header generated by an obsolete rule. That distinction cost me most of the afternoon.

The useful diagnosis was simple. I configured a brand-new build directory from the same checkout and compared the generated command line and config.h. The fresh tree had the option I expected. At that point there was no reason to repair the old tree one cache entry at a time, so I discarded it and configured again.

I also removed the generated header from the source tree and made its destination unambiguous:

configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake
    ${CMAKE_CURRENT_BINARY_DIR}/config.h
)

Now the binary include directory supplies config.h, and a fresh checkout cannot accidentally inherit one. If the clean build disagrees with the old build, I check the old cache’s source path, generated-file timestamps, and include order before blaming CMake detection.

Build trees are cheap. An hour spent negotiating with stale generated CMake files is not.

Network State Is Not a Boolean

My test applet announced “offline” while NetworkManager was still associating with an access point. A second later it announced “online.” Technically energetic, socially useless.

I had reduced state to a boolean. The mechanism has transitions: unavailable, disconnected, preparing, configuring, connected, and failure are meaningfully different to a user and to an application deciding whether to retry.

The applet now maps backend states into three presentation states:

enum Connectivity {
    Offline,
    Connecting,
    Online
};

It preserves the detailed state in the adapter for diagnostics, but the paint code does not understand every NetworkManager value. Solid provides the abstraction boundary; the widget receives only what it can honestly display.

I prefer reacting to state-change notifications rather than polling every second. Polling wastes work and can still miss a short transition. The caveat is startup: the client must query initial state before relying on later notifications, or it may wait forever for a change that already happened.

“Online” also means only that the connection mechanism considers a network active. It does not guarantee a working name server, reachable destination, or paid hotel login. The applet should report connection state, not certify the Internet.

Three states are less satisfyingly binary. They are also less wrong, an increasingly fashionable property in software.

D-Bus 1.0 and Boring Interfaces

D-Bus 1.0 arrived last week, so I replaced a small experimental IPC call today and discovered that my “simple” interface exposed an internal class name, an internal enum, and optimism about call order.

The wire has four names worth keeping straight: a bus name identifies the service, an object path identifies an object, an interface groups methods and signals, and a member names the operation. Treating all four as one application string works until the service grows a second object.

For a thumbnail service I settled on deliberately plain values:

service:   org.kde.Thumbnailer
path:      /Thumbnailer
interface: org.kde.Thumbnailer
method:    Queue(string url, int width, int height)
signal:    Ready(string url, string file)

The exact names may change; the useful constraint is that callers do not need my C++ headers or object layout. Strings and integers cross the process boundary predictably. Errors should cross as named errors, not magic negative dimensions.

A method call can be synchronous, but that does not make blocking the GUI wise. Thumbnail generation may involve disk access or a broken file. The caller should queue work and react to completion, while also handling service disappearance. Processes are allowed to crash independently; that is among their principal features.

I prefer small, boring bus interfaces with operations phrased in domain terms. They are easier to inspect and less likely to preserve an accidental implementation forever. The caveat is round-trip cost and versioning. Turning every getter into a remote call creates slow, chatty code, and changing a published signature later can break clients I do not control.

Introspection is useful during development, but readable metadata does not replace a written contract. Callers still need to know whether requests are idempotent, which errors are expected, and how long returned object paths remain valid.

For KDE 4 porting, D-Bus 1.0 gives us a stable point to build against, not permission to export every object. I am writing the interface first, testing it from a separate process, and only then attaching the current implementation. If the test needs a private header, the boundary has failed.

Today’s service returns one error instead of hanging when the source file vanishes. This is less exciting than transparent desktop integration, but substantially more useful when transparent desktop integration loses a file.

Plasma Data Before Decoration

I changed the weather prototype’s frame today and accidentally made it fetch the forecast again. The border and the network request had become neighbours in one class, then naturally began borrowing each other’s tools.

The experiment now separates a data source from the visualisation. The source produces named values and announces updates. The applet chooses how to present them. Fake data is enough to exercise the boundary:

QVariantMap WeatherSource::snapshot() const
{
    QVariantMap data;
    data.insert("condition", "cloudy");
    data.insert("temperature", 12);
    data.insert("location", "Porto Alegre");
    return data;
}

The applet receives a complete snapshot instead of reading half-updated fields one by one. This matters if the source later performs work asynchronously: a temperature from the new report paired with yesterday’s condition is internally consistent only in avant-garde meteorology.

The visual item invalidates its content when data changes. Theme or frame changes invalidate geometry and decoration, but do not restart the source. Keeping those paths separate avoids needless work and gives the containment freedom to alter presentation.

For this little applet, pullable snapshots plus one update notification beat a long series of property-specific signals. A new field can appear without adding another connection, and a newly created applet can request current state immediately. Copying a large map for frequent updates would be wasteful, though, and weakly typed keys invite spelling mistakes. This fits small desktop data, not every stream.

Error data travels in the same snapshot rather than through a modal dialog. The applet can then show stale values with a warning, hide them, or offer a retry according to the space and purpose of that visualisation.

There are unresolved questions. Sources need lifetimes, update intervals, error states, and perhaps sharing between several applets. A clock should not require sixty private timer objects merely because sixty visualisations exist. On the other hand, premature sharing can couple applets through one source’s policy.

This remains a Plasma prototype, not evidence of a completed KDE 4 shell. The useful result is that I can replace the rectangle with text, or the text with a graph, without changing how forecast data arrives.

The forecast itself still says cloudy. At least this time it did not download new clouds when I changed the border colour.