Getting out of the reversing camera's way
Clutch Cargo turns the MIB2 head unit in my Volkswagen Scirocco into a games machine: QNX 6.5 on an i.MX6, an 800 by 480 dashboard panel, and an 8BitDo pad behind a Mayflash adapter in the USB-A socket. Since the Home screen post, holding HOME on the pad opens a ClutchOS Home drawn on the GPU, and from there ES-DE and the games.
With Home open and the car parked, I selected reverse. Home stayed on top and the camera never appeared.
That is the one thing a screen in a car must not do. Every other bug in this project costs me time. This one could cost a bumper, or worse, and it had been there since the first ClutchOS window went on the glass.
The factory already says when it wants the camera
I did not want to guess at the gearbox. The factory camera software polls a 35-byte shared record, /dev/shmem/shm_cda, every 50 ms, and a trace from a few days earlier had shown that the low two bits of byte 4 are its camera request. I sampled the record read-only about twice a second while I went into reverse three times, twice back to P and once to N.

It reads 0 until the lever first moves after boot, 1 exactly while reverse is selected, and 2 once it leaves. Bytes 27 and 28 hold a CRC-16/XMODEM of the first 27 bytes, so a half-written record can be told apart from a real one:
int cc_guard_camera_request(const unsigned char *r, int len) {
if (!r || len != 35) return -1;
unsigned crc = 0;
for (int i = 0; i < 27; ++i) {
crc ^= (unsigned)r[i] << 8;
for (int b = 0; b < 8; ++b) crc = crc & 0x8000 ? (crc << 1) ^ 0x1021 : crc << 1;
crc &= 0xFFFF;
}
if (crc != ((unsigned)r[27] << 8 | r[28])) return -1;
return r[4] & 3;
}
Every one of the 13 samples passed. The field is the factory's control state, the value its own camera path acts on, which is exactly what something trying to stay out of the camera's way should follow.
One window was the easy part
Home owns its window, so the first release simply hid it while the request read 1 and showed it again afterwards. That was 0.2.7. With Home open, reverse now brought the camera up.
ES-DE and the game hosts open windows of their own in other processes, and each would need the same code. QNX's Screen has a better place for it: a window-manager context, which receives an event for every window created and may hide any of them. The reference reserves it for root, which everything here already is. A probe run beside the factory HMI saw ClutchOS windows come and go, and no factory window at all, because the HMI does not draw through Screen windows. A guard started at boot, before ClutchOS opens anything, therefore sees every window it will ever need to hide and nothing it must leave alone.
That guard went into release 0.2.8. From Home, from the ES-DE menu and from a running game, reverse brought the camera up and the ClutchOS screen came back when I left it.
The VW screen in the gaps
With the guard working I noticed something I had not been looking for. Moving between Home, ES-DE and a game, the factory's VW home screen showed for a second or two while one window closed and the next one loaded. It looked broken, so I added a backdrop: one plain window under everything ClutchOS draws, up for the whole session.
The first backdrop was a software window at z -1, and it covered Home. Placed at the default z instead, it left the pad's HOME badge stuck on screen above it while Home disappeared underneath. Neither worked. Software windows and GPU windows on this unit do not stack by z or by creation order against each other, which I have not seen written down anywhere. A backdrop drawn through the same GPU path as Home, created before Home, sat underneath as intended. Among GPU windows at the default z, creation order decides.
Reverse, then black
Release 0.2.10 came out of a bug that only reverse could produce. I went into reverse with a game running, saw the camera, went back to P, and got a black screen with the game nowhere.
The guard had hidden every window and then shown them again in the order of its own table. Showing a window in Screen raises it to the top, so whichever window was shown last ended up on top, and that was the backdrop. Home also hid and showed its own window on the same signal, which reordered things a second time. The fix was to keep a creation sequence for each window the guard learns about and restore them oldest first, so the stack rebuilds itself with the backdrop at the bottom:
int cc_guard_order(const cc_guard *g, int *slots) {
int n = 0;
for (int i = 0; i < CC_GUARD_MAX; ++i) if (g->used[i]) slots[n++] = i;
for (int i = 1; i < n; ++i) {
int s = slots[i], j = i;
while (j > 0 && g->created[slots[j - 1]] > g->created[s]) { slots[j] = slots[j - 1]; --j; }
slots[j] = s;
}
return n;
}
Home stopped toggling its own visibility at the same time; the guard is the only thing that does it now. The same reverse test with a game running then brought the game back each time.
Plain black in the gaps was an improvement on the VW screen, but it still looked like something had stopped. The backdrop now draws a waiting screen through Home's painter. To keep it from spending GPU time under a running game, the guard reads each window's id string, and while the backdrop is the only ClutchOS window visible it creates a flag in /dev/shmem; the dots animate only while that flag exists.

A re-render on the Mac of the backdrop's frame, from the same drawing code the unit runs.
The badge that would not go
Holding HOME shows a small house with a bar that fills over a second and a half. Let go early and it should vanish. For a while it had been staying up until the next full hold, which I first blamed on the new window manager and the backdrop, since both arrived around the time I noticed.
The pad watcher's log said otherwise: it recorded every early release, from 248 ms to 1,355 ms, and the call that hides the badge each time. So the watcher knew the hold had ended and Screen kept showing the window. Two changes were suspects, the rounded corners (which made the badge a blended window) and the guard's window-manager context. One probe cleared both at once: a square window and a blended one, each posted once, hidden three seconds later with the guard running, both left the screen. Neither was the cause.
The difference between that probe and the real badge was timing. The badge redraws its bar every 20 ms while HOME is held and hides within 20 ms of its last redraw. A replay of the real badge code with no pad, filling the bar for 300, 600, 1,000 and 1,300 ms and then hiding it, reproduced the fault on the unit every time. The window only went when it was destroyed at the end. Destroying the window has removed the badge every time I have tried it, so an early release now destroys it and the next hold makes a new one; the same replay cleared the badge after each hold. Why Screen loses a visibility change that follows a burst of posts, I still do not know.
Where it stands
Release 0.2.14 carries all of it, and it passes every reverse test I have run. The limits are worth stating. The camera is the only factory overlay tested. A parking-sensor alert or an incoming call may come up in a way ClutchOS would also cover, and I have not timed how quickly the camera appears once the windows are hidden. The badge fix works around a Screen behaviour I have measured without explaining.
While I was in the HOME area I also gave Home's highlight a diagonal sheen. My first version looked flat on the panel, so I read the pixels back from the GPU before the swap: 253,176,34 at the tile's top-left corner and 216,141,1 at the bottom-right. The gradient was being drawn, just too gently for the glass, and it now runs about twice as far.
Next on the list is the groundwork for apps from outside ClutchOS, starting with what such an app would be allowed to reach on this unit.