Blog

KDE 4 Alpha on a Spare Partition

I installed a pre-alpha KDE 4 SVN snapshot on a spare partition because running it beside my normal files seemed like a more entertaining mistake than merely reading about it. The announced alpha release was due the next day; this was still a snapshot from the day before. The packages installed cleanly, the session appeared in the login manager, and that was approximately where normality ended.

My naive plan was to reproduce my KDE 3 setup immediately: restore the same panel arrangement, point everything at the same home directory, and judge whether the new desktop was faster. That plan survived for perhaps ten minutes. Several settings had no equivalent, applications still looked inconsistent, and the desktop shell was plainly being assembled while I watched.

What does work is more interesting than the rough edges. Qt 4 painting feels noticeably less burdened when windows resize. The new artwork gives the session a coherent direction rather than the collection-of-themes appearance I feared. A few applications already show cleaner separation between their data and their widgets, which should matter long after the screenshots stop being novel.

What does not work is still substantial. The panel is not something I would trust for a working day. Desktop actions occasionally disappear. Some configuration modules are present but ineffective, a particularly refined form of optimism. Logging out once left processes behind, which then made the next login look broken until I killed them from a console.

This is not KDE 3 with fresh icons. KDE 4 is changing the toolkit, desktop shell, hardware and multimedia layers, and a fair amount of application plumbing at once. That explains why familiar checkboxes cannot simply be carried over. It also means measuring this snapshot as a replacement desktop misses the point.

After a second installation with a clean test user, many of the mysterious failures vanished. Sharing an old configuration directory had introduced stale service files and assumptions from KDE 3. The snapshot still crashes and still lacks ordinary conveniences, but at least those failures now belong to the new code rather than to my archaeological collection of dot files.

Don’t install it on the account used to earn money. Still, the architecture is visible enough to poke at, and a bug report from a clean account may help. Complaining that a pre-alpha snapshot is unfinished is accurate, but not exactly investigative journalism.

Qt Model/View Without the Magic

I added sorting to a log viewer with QSortFilterProxyModel, clicked the third visible row, and opened the wrong log entry. The view had done exactly what I asked. I had used a proxy row as an index into the source list.

A proxy has its own indexes and its own order. Once sorting or filtering is active, row 3 in the view says nothing useful about row 3 in the source. The handoff needs to be explicit:

QModelIndex proxyIndex = view->currentIndex();
QModelIndex sourceIndex = proxy->mapToSource(proxyIndex);
if (sourceIndex.isValid())
    openEntry(sourceIndex.row());

The reverse direction matters too. When the parser reports a source index that should be selected, mapFromSource() finds its current position in the proxy. Calling view->setCurrentIndex() with the source index may look plausible, but the index still belongs to a different model and should not be handed to that view.

My next bug was staler. I changed a severity threshold stored by the proxy, emitted a signal from the dialog, and nothing disappeared. The filter result was cached. After changing the threshold, the proxy had to invalidate its filtering so that filterAcceptsRow() ran again:

void LogProxy::setMinimumLevel(int level)
{
    if (minimumLevel == level)
        return;

    minimumLevel = level;
    invalidateFilter();
}

Resetting the source model also made the screen update, but it was the wrong hammer. It discarded selections and told every attached view that the source structure had vanished when only the proxy’s mapping was stale.

Dynamic sorting has a similar edge. If a source value used by the sort or filter changes, the source must emit dataChanged() for that value. The proxy can then reconsider the affected mapping. Without that notification, asking the proxy to repaint merely gives it another chance to use the same old answer.

Selections and drag-and-drop code are where I now look first for mapping mistakes. Anything crossing the proxy boundary should say which side its index belongs to. That small bit of bookkeeping beats opening the wrong error at two in the morning.

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.

One Event Loop, One Owner

A worker emitted a progress signal today, the label updated twice, and then the application hung while closing. The visible update tempted me to declare the cross-thread code correct. The shutdown was less charitable.

Qt gives each QObject thread affinity. Queued events for that object are processed by the event loop in its owning thread. A signal connected across threads normally becomes a queued call, so the receiver’s slot runs where the receiver lives. This permits a worker to report results without directly touching GUI objects.

The safe shape is simple:

connect(worker, SIGNAL(progress(int)),
        dialog, SLOT(setProgress(int)),
        Qt::QueuedConnection);

The explicit connection type documents the boundary. The worker emits an integer; the dialog owns the label and updates it on the GUI thread.

My hang came from destruction. The dialog waited for the worker while handling its close event, and the worker was waiting for a queued reply from the dialog’s event loop. The GUI event loop could not deliver the reply because it was blocked waiting. Both sides were admirably patient.

I removed the synchronous callback. Closing now requests cancellation, disables the interface, and lets normal event processing continue until the worker announces completion. Only then is it destroyed. Data passed in signals is copied as needed, so custom value types must be registered if they cross a queued connection.

I prefer message-like queued signals between worker and GUI code. They make ownership visible and avoid shared widget state. The caveat is that queued delivery is asynchronous: the sender cannot assume the slot has run, event loops must remain active, and ordering guarantees do not replace a proper state machine.

Nested event loops are another temptation. Opening a modal operation or manually calling event processing can keep paints moving, but it also permits unrelated events to re-enter code whose invariants are half changed. I use that technique only with a very clear boundary, never as a general cure for long work.

The practical test now closes the window at several stages of the job. Starting and finishing are easy; cancellation and teardown reveal who actually owns what. If a design works only while the user behaves, the user is not the unreliable component.

KVM After 2.6.20

Linux 2.6.20 was released this week with KVM included, so I tried booting a small guest rather than merely reading patches. The first attempt failed immediately because the processor’s virtualisation support was disabled in the firmware. Progress began with entering setup, which keeps systems programming humble.

KVM uses the processor’s hardware virtualisation extensions and exposes a kernel interface through /dev/kvm. A user-space program supplies the virtual machine’s device model and asks the kernel to run virtual CPUs. This is not a complete machine monitor appearing from one kernel option; kernel and user space divide the work.

The basic checks on this Intel test box were:

grep vmx /proc/cpuinfo
modprobe kvm
modprobe kvm-intel
ls -l /dev/kvm

On an AMD processor I would look for svm and use the corresponding module. Seeing the flag is necessary but not always sufficient, because firmware can still disable the facility.

After loading the modules, I launched a guest image with the available QEMU KVM support and watched the kernel log in another terminal. The guest booted, though virtual disk and network performance are not conclusions I can draw from ten minutes and one ageing drive.

I prefer this architecture because putting CPU execution support behind a kernel interface lets normal Linux scheduling and memory management participate, while device emulation remains in user space where a failure is less likely to take the host with it. The caveat is that the boundary can impose overhead, hardware support varies, and young interfaces may change as use exposes mistakes.

Security deserves restraint too. Hardware isolation is not a promise that a hostile guest can never escape. Device emulation processes parse guest-controlled input, and kernel code now manages another complicated processor mode. I am treating guests as isolated test systems, not as magical bags into which all risk disappears.

The useful result today is narrow: with 2.6.20, suitable hardware, enabled firmware support, kernel modules, and matching user space, a Linux host can run a hardware-assisted guest. Whether KVM becomes the preferred general solution will depend on performance, management tools, and how gracefully it handles less cooperative machines.

For now it boots. In infrastructure experiments, reaching a login prompt is the traditional point at which confidence rises faster than evidence.