Skip to content

Alt+e makes a zone's window fullscreen below a bar that names its zone - #191

Merged
DevomB merged 7 commits into
mainfrom
fullscreen-zone-bar
Oct 9, 2026
Merged

DevomB merged 7 commits into
mainfrom
fullscreen-zone-bar

Conversation

@DevomB

@DevomB DevomB commented Oct 2, 2026 •

Copy link
Copy Markdown
Owner

The guide's known limitation said a fullscreen window shows its zone only by its border colour. On main a zone's window cannot be fullscreen at all: dwl refuses every request from a zone, Alt+e included, so the Alt+e row and that bullet described something that no longer exists.

The design

  • Alt+e, the compositor's key, makes a zone's window fullscreen. A zone program's own set_fullscreen can take its window out of fullscreen but never into it (fullscreennotify).
  • A fullscreen window keeps its border. The top 22 px of its output become a bar in the zone's colour, with the zone's name in 5x7 capitals, black or white depending on how light the colour is. The window gets the rest of the output. Zone 0's fullscreen windows get a bar too, reading ZONE 0.
  • The bar is drawn by dwl as rects in the window's own scene tree, placed above its frame (zonebar in tools/desktop/dwl-zone-borders.py). The lettering comes from one table, FONT in that script, so the compositor and the screenshot check use the same glyphs.

Why a zone cannot draw over the bar

  • The window's surfaces and subsurfaces are clipped to its frame, and the bar is outside the frame.
  • A zone has no popups (the proxy refuses get_popup) and no layer shell (the proxy hides it).
  • A zone's windows never float. They reach the fullscreen layer only by being fullscreen themselves. A zone's child toplevel used to follow a fullscreen parent into that layer, where it would cover the parent's bar; it now stays in the tile layer.
  • Anything drawn above a fullscreen window is either zone 0's or another fullscreen window. A fullscreen window covers the whole output and has its own bar, so the bar on screen always names the window below it.
  • Not covered here: while the pointer is over a zone's window, the zone's cursor image (wl_pointer.set_cursor) is drawn above every layer. That gap already exists on main, and A zone's pointer shows dwl's default cursor, never the zone's own image #201 closes it.

The pointer

dwl's xytonode used to keep looking through lower layers when the pointer was over a border or a background rather than a surface. Over a fullscreen window, a click on its bar or border therefore went to a window hidden below it, possibly another zone's. The search now stops at the first thing drawn under the pointer.

The chrome

A fullscreen zone window covers the chrome windows that were already open, such as the launcher, because the user asked for fullscreen. Any window the chrome opens afterwards ends that fullscreen and takes the focus, as before: a passphrase prompt, a transfer question, the menu. The zone then cannot get fullscreen again by itself. The header of kryptik-chrome now says this.

Tests (desktop suite)

  • zone0-fullscreen-granted: wlprobe fullscreen in zone 0 asks for fullscreen and gets a fullscreen configure. This shows the probe would see a grant.
  • zone-fullscreen-refused: the same probe in untrusted gets a configure that is not fullscreen.
  • fullscreen-by-key: Alt+e on the untrusted terminal, after which the chrome's record has fullscreen=1.
  • The fullscreen screenshot: the window's frame covers the whole output, 22 + 6 px on top and 6 px on the other sides. Every pixel of the bar matches UNTRUSTED as drawn from FONT, barpx and barscale. A mismatch prints the bar as text.
  • fullscreen-off-again is unchanged.

Docs

Overlap with #201 (cursor confinement)

Both PRs change wlprobe.c's mode check and usage line and the header comment of kryptik-chrome. Whichever merges second keeps both; #201 gives the comment's wording with both in.

The focus under a fullscreen window

A non-author read of this branch found a hole the design above left open, verified against dwl 0.8's source: focusstack returns early only for a fullscreen window without children. A zone can give its fullscreen window a child toplevel (set_parent is forwarded), which this branch keeps in the tile layer, hidden below the parent; setmon then gives the child the focus on map, and from either window Alt+j/k walked the focus to any window on the output, zone 0's launcher or another zone's terminal included, while the screen showed the fullscreen window under its bar. The view and tag paths had the same shape through focustop.

What changes:

  • covered(c, m): with a fullscreen window on the monitor, a window in any other layer is hidden below it. focustop and both walks of focusstack skip covered windows, so the focus keys reach only the fullscreen window and what shares its layer (zone 0's child above its own fullscreen parent, as dwl has it). Nothing else about dwl's early return changes.
  • A zone's child ends its parent's fullscreen when it maps (the w != p exemption in mapnotify no longer applies to a zone's window), since the child cannot be drawn above the bar; both are then shown tiled. Zone 0's child still follows its parent into the fullscreen layer.
  • wlprobe child SECONDS [late]: a window and a child of it; with late, the child only once the parent's configure was fullscreen.
  • Desktop suite: zone-child-mapped, parent-focused (Alt+j from the child), parent-fullscreen (Alt+e), fullscreen-keeps-focus (Alt+j with the parent fullscreen leaves the record on it, fullscreen=1), parent-windowed-again, and child-ends-fullscreen (the late child: the parent's next configure is not fullscreen and the record says fullscreen=0).
  • docs/architecture.md: one sentence.

Run 37571470780 on this head, on the branch's own base; the merge with main (#196, #201) follows.

After a non-author read

The read (linux-distro-a2, against the exact dwl.c this builds) found that the first repair left the keyboard where the record did not say:

  • A chrome window mapped over a fullscreen zone window got the record but not the keyboard: setmon chose the focus while the zone window still covered the new one, the loop then ended the fullscreen, and nothing refocused. A passphrase prompt opened over a fullscreen zone window would have typed into the zone. Now the loop notes what it ended and focusclient(focustop(selmon), 1) follows it.
  • zoom (Alt+Return) walked the keyboard under the fullscreen window. focusclient now redirects a covered window to focustop, which closes every direct path, and zoom's search skips covered windows as well.
  • covered() tested the layer alone, so zone 0's child left in the fullscreen layer after its parent went windowed counted everything else as covered. It now needs a fullscreen window above.
  • fullscreennotify granted zone 0's own request unfocused, covering the focused window. Granted only while that window has the focus.

The record kryptik-chrome writes names the window the compositor believes on top, which by construction is never a covered one, so the first checks could not see any of this. wlprobe now binds wl_keyboard for every window it holds and prints keyboard entered|left the window|the child; the checks read that: keyboard-stays-on-fullscreen (Alt+j), zoom-keeps-keyboard (Alt+Return), zone0-over-fullscreen-gets-keyboard (a zone 0 probe mapped over the fullscreen parent is entered, and names the record), zone0-window-ends-fullscreen (the parent's next configure is not fullscreen).

Run 37593373061 on the first repair was green; the run on this head follows.

…ur that names the zone, and the window's own request never does; the pointer goes to what is drawn on top, not to a window hidden below a bar or border
…efix, which also keeps the compiler from reading past dwl's fallback app_id
DevomB added 5 commits October 6, 2026 21:25
…he focus keys skip what a fullscreen window covers, and a child the zone opens ends its parent's fullscreen, since nothing of the zone's is drawn above the bar
# Conflicts:
#	tools/desktop/kryptik-chrome
#	tools/desktop/wlprobe.c
#	tools/image/gui-test.sh
…from zone 0: a running zone takes one program through kryptik-launch, so the section runs before the untrusted terminal, and Alt+j reaches the newest window first
…w shown by ending a fullscreen takes the focus, focusclient refuses covered windows, zoom skips them, covered() means a fullscreen window above, zone 0's own fullscreen needs the focus; the probe reports wl_keyboard enter and leave, and the checks read that rather than the record
…indow it finds to the front of its list, and only from the front does the old search pass the fullscreen window and reach the hidden child
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant