Kde

KDE 3.3 Feels Settled

I upgraded my main workstation to KDE 3.3 because I wanted the newer applications, not because I was looking for excitement. Desktop upgrades have supplied quite enough excitement already.

My first attempt was the usual impatient one: replace the packages, keep every old setting, and hope. The desktop started, but a couple of panels behaved oddly and Konqueror inherited some settings that no longer made much sense. I briefly blamed KDE. Then I tried a fresh user account and discovered that my carefully accumulated configuration was the real antique.

What impressed me was how little else needed attention. Session restoration brought back the applications I expected. The file manager, terminal, editor, and control modules felt like parts of one desktop rather than strangers sharing a theme. Even mundane details such as keyboard shortcuts were consistent enough that I stopped thinking about them.

That is what maturity looks like to me. It is not a spectacular new dialog. It is being able to spend the afternoon in C++ rather than repairing the environment used to write it.

I copied only the settings I understood into the fresh account and left the archaeological layers behind. KDE 3.3 may not make for dramatic dinner conversation, but a desktop that gets out of the way is doing its job very well.

Small KDE 3.2 Habits That Save Time

After several months with KDE 3.2, the features saving me time aren’t the ones that make attractive release screenshots. They’re small habits around Konqueror, the Run Command dialog, and reusable KDE components.

The first is using location protocols directly. Konqueror is not limited to local paths and HTTP URLs. Typing an sftp:// location gives me a remote file view through the normal interface. I can keep local and remote views open and copy between them without teaching every application a separate transfer procedure.

I still use command-line scp for scripted or large transfers. A graphical view is convenient, not evidence that errors no longer occur. If a copy matters, I verify its size or checksum at the destination.

The second habit is splitting Konqueror’s view when comparing directories. One window with two linked views is easier to reason about than two overlapping windows. Because the file view is a component, the shell can arrange it without becoming a separate file manager for every layout.

The third is assigning keyboard shortcuts only after noticing repeated actions. KDE permits a heroic quantity of customisation, but configuring twenty speculative shortcuts creates a keyboard dialect I will forget by Friday. I add one shortcut when an action has annoyed me several times, then use it until it becomes natural.

Profiles are useful for the same reason. A Konqueror profile can restore a practical arrangement of views and locations. I keep one for file work and another for browsing rather than forcing one toolbar and sidebar arrangement to serve both jobs.

Finally, I use KDE’s Run Command dialog—the minicli utility—for applications I already know by name. Navigating a menu helps while discovering software; pressing Alt-F2 and typing the program name is faster afterward. Command history makes repeated invocations painless.

None of this is revolutionary. That is the point. KDE’s strength is the common infrastructure beneath applications: URL handling, parts, shortcuts, and session behaviour. Once I use those facilities consistently, individual programs require fewer special habits.

There is a danger in turning desktop configuration into a hobby that prevents desktop work. I avoid changes that save two seconds once and require an evening of maintenance. The useful tweaks survive upgrades, use standard KDE facilities, and are easy to explain six months later.

KDE 3.2 gives me plenty of choices. The trick isn’t exercising all of them. It’s finding the few that remove recurring friction, then leaving the control centre alone long enough to get something done.

A Model Pattern for Qt 3 List Views

I have a Qt 3 dialog that displays several hundred server records in a QListView. The first implementation stored the actual application state in QListViewItem subclasses. It worked until another window needed the same records and sorting the view began to feel suspiciously like rearranging the database.

Qt 3 does not provide the general item model API one might wish for here. QListView owns a tree of items, and those items naturally contain display text. That does not require making them the authoritative business objects.

My simpler pattern is to keep records in an ordinary domain collection and make each list item an adapter containing only a stable identifier. Display columns are copied from the record when the view is populated or refreshed.

class ServerItem : public QListViewItem
{
public:
    ServerItem(QListView *view, int id)
        : QListViewItem(view), serverId(id) {}

    int id() const { return serverId; }

private:
    int serverId;
};

When selection changes, the controller reads the item’s ID and looks up the record. Editing updates the record first, then refreshes the item text. Deleting the view item never deletes the underlying record unless the user explicitly requested that operation.

This separation fixes several observed problems. Sorting changes presentation order without changing application order. Two views can show the same record differently. Reloading the widget cannot silently discard unsaved state hidden in a child item. Unit-like tests can exercise record operations without constructing widgets or starting an X connection.

Signals and slots keep the pieces reasonably loose. The dialog connects selection and activation signals to slots that translate a QListViewItem * into a record ID. The record-owning object emits a signal after a successful change, and the view refreshes the affected row.

There is a caveat: copying all text into items can be expensive for very large datasets. For hundreds or a few thousand rows it is straightforward and fast enough. If the data is enormous, a custom widget or a specialised table that fetches visible values may be warranted. I would measure before building that machinery.

Stable IDs are important. Storing a pointer into a collection is tempting, but reallocating a vector or reloading records can invalidate it. An integer or other durable key makes the lookup explicit and failures easier to detect.

I do not call this a framework. It is three rules: own data outside widgets, put identities in items, and route changes through one owner. Qt’s item widgets remain useful presentation objects without becoming a tiny, badly documented database. Most dialogs need no grander architecture; they merely need the courage not to store reality in column zero.

Flicker-Free Custom Painting in Qt 3

I wrote a small Qt 3 widget that draws a graph, and it flickered whenever another window crossed it. The first version painted the background and graph directly onto the widget. The user could occasionally see the exciting interval between those operations.

The obvious cure is to draw a complete frame off-screen and copy it in one operation.

void Graph::paintEvent(QPaintEvent *event)
{
    QPixmap frame(size());
    frame.fill(colorGroup().base());

    QPainter p(&frame);
    drawGrid(&p);
    drawValues(&p);
    p.end();

    bitBlt(this, event->rect().topLeft(), &frame, event->rect());
}

The pixmap receives the background and every graph element before the screen changes, so the widget never displays a half-painted frame. For a frequently updated widget, I keep a cached pixmap and rebuild it only when the size, palette, or data changes.

Calling update() schedules a paint event and allows Qt to combine several dirty regions. Calling repaint() paints immediately. I use update() unless the application genuinely requires synchronous drawing; repeated immediate paints are an efficient way to make smooth animation less smooth.

Another option is the WNoAutoErase widget flag, which prevents Qt from erasing the background before paintEvent(). It can remove one source of flicker, but then the paint code must cover every exposed pixel. Missing one produces attractive garbage from whichever window was there before.

Double buffering costs memory proportional to the widget area, and redrawing an elaborate pixmap for every tiny exposure wastes time. Respect the event’s rectangle and cache expensive static parts.

The result is not clever: compose, then copy. That is precisely why I like it. Rendering bugs are much easier to diagnose when the screen sees only finished frames.

KDE 3.2 in Daily Use

KDE 3.2 was released this week, and I have moved my normal account from 3.1 to the new version. The upgrade was painless on this machine, but I still copied .kde first. Confidence is a fine emotion; it is not a backup strategy.

The feature I notice most is Kontact. Having KMail, KOrganizer, the address book, and related tools in one window sounds cosmetic until one uses it all day. The components remain useful separately, but the shared shell reduces window hunting and makes the PIM suite feel like one piece of software rather than neighbours who happen to share a fence.

Konqueror feels more polished as both browser and file manager. KHTML handles more of the troublesome pages I encounter, although “works in Safari” still does not guarantee “works in Konqueror.” They share ancestry and code, not every platform integration or every patch. Web developers should test both instead of converting the relationship into a new browser-detection shortcut.

I also like the many small improvements more than any single headline. Configuration pages are easier to navigate, applications agree more often about behaviour, and the visual result is cleaner. KDE already had enough knobs to operate a modest submarine. The useful work now is choosing good defaults and making the common paths obvious.

My post-upgrade check is deliberately mundane:

send and receive mail
open old calendar entries
print from two applications
test file associations
visit SSL sites
check keyboard shortcuts
log out and back in

That last step catches session restoration and startup problems that a quick tour misses. I also removed third-party panel applets before upgrading and added them back one at a time. Plugins compiled against an older set of libraries are not where I want to begin debugging the desktop itself.

Performance is difficult to judge scientifically from a chair, but the desktop remains responsive and startup is reasonable. The larger applications naturally consume memory; integration does not repeal arithmetic. On a modest machine I would choose which Kontact components to load rather than assuming the complete suite is free.

KDE 3.2 is a substantial release, but it succeeds because the desktop feels more connected, not because the version contains a longer feature list. I can do the same work with fewer interruptions. That is not glamorous, and it is exactly what I want from a desktop.