JBrowser Source Docs
You are reading the documentation for JBrowser 2.0.1. The newest release is 2.0.3. Go to the latest documentation

jbrowser.ui.backdrop

Generated from the source code of JBrowser 2.0.1.

jbrowser/ui/backdrop.py · 505 lines

One owner for a top-level window's Windows 11 look: the system material behind it and its light/dark mode.

Windows keeps that state per native window, and more than one party touches it: JBrowser, and Qt, which re-applies its own idea of light/dark to every window frame when the application palette or colour scheme changes. Earlier versions applied the state from several places, read it back, rebuilt the material when it looked wrong and changed JBrowser's whole look when Windows reported a failure. On some PCs those reactions fed each other: pale windows behind dark text, a stale rectangle after maximising, a caption that stopped dragging, a window that flashed black or white and stopped responding.

So, per window, one Backdrop:

  • applies the material and the mode when they change (once for each new native window, and with the same values again when the window comes back from the taskbar), and never reads anything back from Windows;
  • after anything that can reset the mode (palette or theme changes, activation, window state changes, Windows settings broadcasts), sets the mode again. Setting the same value is free and changes nothing on screen, so nothing can loop;
  • never rebuilds the material, never forces a frame refresh and never restyles the application.

JBrowser also paints its own base colour under its content (Theme.backdrop_layers), so the window stays readable whatever Windows draws behind it. When Windows isn't drawing the material at all, or draws the wrong one, LookGuard makes that base opaque (Theme.see_through).

Backdrop#

class Backdrop(QObject)source
Backdrop(window: QWidget, kind: str='window')

Keeps window's system backdrop and light/dark mode in step with the theme.

kind is "window" (a frameless JBrowser window with a material), "popup" (a borderless popup: Acrylic over the whole window) or "frame" (a dialog with a native title bar: only the mode and the caption colours).

Attributes

Name Value
CLOAK_MS 120

Backdrop.schedule#

schedule() -> Nonesource

Apply soon, once, after the current event (Qt's own handling of it comes first).

Backdrop.apply#

apply(showing: bool=False) -> Nonesource

Qt overrides: eventFilter

WindowTransitions#

class WindowTransitions(QObject)source
WindowTransitions(window: QWidget, native: 'win.NativeFrame', repaint=None)

Minimise, maximise and restore without the colour warp.

Windows animates these with a snapshot of the window. On some PCs the see-through parts of that snapshot come out in the wrong colours (pale, dark or tinted) until something repaints. So the window paints itself opaque just before the change (Theme.hold_opaque), stays opaque while Windows animates, then repaints normally. Commands from Windows itself (taskbar, Win+arrow keys, double-clicking the caption) arrive as WM_SYSCOMMAND: the window takes them over, paints, and sends them again (NativeFrame.on_transition).

Attributes

Name Value
PAINT_MS 40
HOLD_MS 420

WindowTransitions.run#

run(action) -> Nonesource

Qt overrides: eventFilter

LookGuard#

class LookGuard(QObject)source
LookGuard(parent: QObject | None)

Decides whether Windows is really drawing Mica / Acrylic behind JBrowser (Theme.see_through).

When it isn't, the see-through parts of JBrowser's windows show whatever Windows draws instead: a flat grey, white or black fill that needn't match the theme. JBrowser then paints an opaque base of its own, so its windows look like the Solid material, and goes back to see-through when it can. It learns this from:

  • Windows settings that turn materials off (transparency effects, energy saver, high contrast, Remote Desktop): checked every few seconds and whenever Windows broadcasts a change;
  • Qt saying that the graphics driver can't give windows see-through pixels (note_qt_message);
  • the screen itself. After a window appears, the theme changes, Windows changes a setting, or now and then on activation, JBrowser leaves a tiny spot at the top edge of the active window unpainted for one frame and reads what Windows composited there: the bare material. Black means see-through pixels don't work on this PC; a light material behind a dark JBrowser (or a dark one behind a light JBrowser) means Windows draws the wrong one. Two readings in a row must agree.

Attributes

Name Value
POLL_MS 3000
SETTLE_MS 160
CONFIRM_MS 450

LookGuard.instance#

class method instance() -> 'LookGuard'source

LookGuard.watch#

watch(window: QWidget, background: QWidget, spot: Callable[[], QPoint | None]) -> Nonesource

Probe window when it's the active window. background paints its backdrop layers (and calls paint_probe_hole); spot() is a point in background where nothing else paints, or None when there is none right now.

LookGuard.system_changed#

system_changed() -> Nonesource

Windows broadcast a settings, theme, power or display change (NativeFrame.on_system_change).

LookGuard.check#

check() -> Nonesource

Windows settings that turn materials off, and Qt's graphics messages.

LookGuard.probe_soon#

probe_soon(ms: int) -> Nonesource

Qt overrides: eventFilter

Functions#

note_qt_message#

note_qt_message(text: str) -> Nonesource

Called with every Qt message (app.py). Remembers one saying that the graphics driver can't give windows see-through pixels (no Direct Composition): Windows would show them black.

paint_probe_hole#

paint_probe_hole(p: QPainter, widget: QWidget) -> Nonesource

Leave LookGuard's probe spot unpainted (call last in the paintEvent that draws widget's backdrop layers). Only for the one frame LookGuard reads back; otherwise does nothing.

look_guard#

look_guard() -> LookGuardsource

caption_hit#

caption_hit(window: QWidget, local: QPoint, max_button: QWidget | None) -> intsource

The hit-test code for a point in a frameless JBrowser window: the caption (drag), the maximise button (Snap Layouts) or ordinary client area. Never raises: an error here used to make the window procedure fall back to "client area", and the window stopped dragging.