Package limn.testing

Class HeadlessWindow

java.lang.Object
limn.testing.HeadlessWindow
All Implemented Interfaces:
AutoCloseable, NativeWindow, WindowPeer

public final class HeadlessWindow extends Object implements WindowPeer
A window with no platform behind it, whose accessibility bridge keeps the last tree it was handed: what a scene is bound to so that its accessible tree can be read with no GL, no fonts and no desktop. HeadlessBackend.open(java.lang.String, int, int) makes one; a SceneDriver drives its scene.

A frame here is the scene's own frame callback, the one Scene#bind installs, driven by hand: what a real backend does once per vertical blank this does when a test asks. That is the whole publish path a screen reader would see, and not a shortcut around it.

  • Field Details

    • textInput

      public @Nullable TextInput textInput
      What the scene last asked of this window's input method: composition for a focused text widget, characters otherwise; null before it asked. A test of where a composition goes reads it, as a platform's input method would.
    • preeditCaret

      public @Nullable Rect preeditCaret
      Where the scene last put the input method's candidate window, in this window's points, or null before it said.
    • RULER

      public static final TextRuler RULER
      Ten points per code point, ascent eight, descent two, line twelve: the fixed monospace ruler every headless layout in this repository measures against, so that a transcript taken on one machine is the transcript taken on every other.
  • Method Details

    • supportsAbsolutePositioning

      public boolean supportsAbsolutePositioning()
      Description copied from interface: WindowPeer
      Whether NativeWindow.screenX(), NativeWindow.screenY() and NativeWindow.setScreenPosition(int, int) actually work on this platform. When false the getters report a placeholder and the setter is ignored: a window is placed by the desktop and never learns where it went.

      Ask this before drawing anything outside a window that has to line up with something inside it: a dropdown's list, a menu cascade, a tooltip. Those are not windows in their own right; they are the owner's content, escaping the frame because most desktops offer no other way to overflow it. Where the answer is false there is no such way, and the content has to be drawn in the scene instead, clipped to the owner.

      A window that is genuinely a window (a document, a dialog, a palette) needs no such check. It has no position to agree with, so letting the desktop place it is the right outcome rather than a fallback.

      No default. It answered true until 2026-09-22, which is the unsafe answer: a backend that said nothing claimed a power Wayland does not have, and a popup that trusted it opened wherever the compositor put it. Absolute window position is absent from that protocol by design, so a backend has to say.

      Specified by:
      supportsAbsolutePositioning in interface WindowPeer
    • fileDialogs

      public FileDialogs fileDialogs()
      No chooser here: every dialog answers empty, as if cancelled.
      Specified by:
      fileDialogs in interface NativeWindow
      Returns:
      the platform's file and folder choosers, owned by this window; FileDialogs.NONE for a window with none (headless, embedded). No default: a backend that answered NONE by omission made every "Open…" in an application silently do nothing. UI thread only.
    • launcher

      public Launcher launcher()
      Specified by:
      launcher in interface NativeWindow
      Returns:
      what hands an address or a file to the system this window is on; Launcher.NONE for a window with no desktop under it (headless, embedded). No default, for the reason NativeWindow.fileDialogs() has none: a link that silently opens nothing. UI thread only.
    • printer

      public Printer printer()
      Specified by:
      printer in interface NativeWindow
      Returns:
      what prints a PDF through the system's own print dialog, owned by this window; Printer.NONE for a window with no printing under it (headless, embedded). No default, for the reason NativeWindow.launcher() has none: a "Print…" that silently prints nothing. UI thread only.
    • setTextInput

      public void setTextInput(TextInput input)
      Description copied from interface: WindowPeer
      Says what text this window wants from the platform: none, typed characters with the input method off, or characters and the input method's composition. The scene asks for composition while a text-editing widget holds focus and for characters otherwise, so composition keys never leak into a control that is not text, and a list's type-ahead still hears letters. UI thread only.

      No default, nor for the two IME methods below: a backend that ignored them broke Chinese, Japanese and Korean input without a word. A backend with no input method (headless) implements them as no-ops, on purpose and in writing.

      Specified by:
      setTextInput in interface WindowPeer
      Parameters:
      input - what the window wants; never null
    • setPreeditCaretRect

      public void setPreeditCaretRect(float x, float y, float width, float height)
      Description copied from interface: WindowPeer
      Positions the IME candidate/composition window at the caret, so it follows the text being edited. x/y/width/height are in logical points relative to the window's content area (the scene feeds the focused widget's caretRect). UI thread only.
      Specified by:
      setPreeditCaretRect in interface WindowPeer
    • resetPreedit

      public void resetPreedit()
      Description copied from interface: WindowPeer
      Cancels any in-progress IME composition held by the platform for this window. The scene calls it when focus leaves a text-editing widget, so a composition started there can never commit into whatever is focused next. A no-op when nothing is being composed. UI thread only.
      Specified by:
      resetPreedit in interface WindowPeer
    • frame

      public void frame()
      A turn of the UI queue and a frame of this window: the queue drained, then one frame rendered through the callback the bound scene installed, so that what the toolkit leaves for the next turn (the end of a fade that goes straight there, a dialog's result under less motion) reaches a test that renders frames, as it reaches a user. Input sent with key(int) is dispatched as it is sent, as the loop's input step would.

      Not exactly a turn of a desktop backend's loop, which drains the queue once and then draws every window, a window that drain opened included: framing several windows one after another here drains once for each, so a task posted by a task runs between two windows' frames, and a window opened while the test frames the others is framed when the test frames it.

    • userClose

      public void userClose()
      Closes this window as a user's click on its close button does: its handler is asked, and once it allows, the window does what its policy says. What a desktop backend does when the user closes a window; a program's requestClose() asks nothing.
    • desktopFocus

      public void desktopFocus(boolean focused)
      Tells the bound scene the desktop gave this window the keyboard, or took it away: what a user's click on a window does, and what showing a dialog that takes focus does to both. A window given the keyboard is the front one, the first an ending application asks.
      Parameters:
      focused - whether this window is now the one the keyboard goes to
    • key

      public void key(int key)
      Presses and releases one key in this window, as the desktop delivers a keystroke: the press, the release, and the end of the input batch that dispatches both.
      Parameters:
      key - the key code, from Keys
    • scene

      public @Nullable Scene scene()
      Returns:
      the scene bound to this window — the entry's own, or the one a widget built for a popup, a dialog or a menu it opened as a window of its own — or null before one is bound
    • bridge

      Returns:
      the bridge that kept the newest tree this window's scene published
    • publishesAccessibility

      public boolean publishesAccessibility()
      Whether a scene asked this window for its bridge, which is what opens one on a real backend: a popup grafted into its opener's tree never does, and publishes nothing of its own.
      Returns:
      whether this window has a tree of its own to check
    • accessibility

      public AccessibilityBridge accessibility()
      Specified by:
      accessibility in interface NativeWindow
      Returns:
      the platform accessibility bridge for this window, or AccessibilityBridge.NONE when it has none.

      default on the merits rather than as a compatibility dodge: none is the correct behaviour for a window with no accessibility — a test double, an embedded surface, any future backend on its first day — and getting exactly zero cost by writing nothing is better than getting it by writing the same stub in each.

    • display

      public Display display()
      Specified by:
      display in interface NativeWindow
      Returns:
      the Display this window currently sits on (the monitor containing the window's centre), or null when headless/embedded. Its Display.workArea() is what external popups clamp against to stay on screen. UI thread only.
    • title

      public String title()
      Specified by:
      title in interface NativeWindow
      Returns:
      the current title
    • setTitle

      public void setTitle(String newTitle)
      Description copied from interface: NativeWindow
      Sets the native title bar text.
      Specified by:
      setTitle in interface NativeWindow
    • logicalWidth

      public float logicalWidth()
      Specified by:
      logicalWidth in interface NativeWindow
      Returns:
      width in logical points (framebuffer width ÷ content scale)
    • logicalHeight

      public float logicalHeight()
      Specified by:
      logicalHeight in interface NativeWindow
      Returns:
      height in logical points (framebuffer height ÷ content scale)
    • framebufferWidth

      public int framebufferWidth()
      Specified by:
      framebufferWidth in interface NativeWindow
      Returns:
      framebuffer width in physical pixels
    • framebufferHeight

      public int framebufferHeight()
      Specified by:
      framebufferHeight in interface NativeWindow
      Returns:
      framebuffer height in physical pixels
    • contentScale

      public float contentScale()
      Specified by:
      contentScale in interface NativeWindow
      Returns:
      the content scale in effect for this window: the monitor's, or the forced one. Fractional values (1.25, 1.5, 1.75) are first-class citizens, never assume integer
    • overrideContentScale

      public void overrideContentScale(float scale)
      Description copied from interface: NativeWindow
      Forces the rendering content scale, ignoring the monitor's. Screenshot scenes use it to validate 1.0/1.25/1.5/2.0 rendering on any monitor. Pass 0 to return to the monitor scale.
      Specified by:
      overrideContentScale in interface NativeWindow
    • setSize

      public void setSize(int newWidth, int newHeight)
      Description copied from interface: NativeWindow
      Resizes the window to the given size in logical points.
      Specified by:
      setSize in interface NativeWindow
    • setSizeLimits

      public void setSizeLimits(int minWidth, int minHeight, int maxWidth, int maxHeight)
      Description copied from interface: NativeWindow
      Constrains user resizing to the given bounds in logical points; pass <= 0 for any bound to leave it unconstrained. Only affects interactive resizes; NativeWindow.setSize(int, int) is not clamped. A window made from a WindowConfig with WindowConfig.minSize(int, int) or WindowConfig.maxSize(int, int) starts with those. The default implementation ignores it (headless/embedding). UI thread only.
      Specified by:
      setSizeLimits in interface NativeWindow
    • sizeLimits

      public SizeLimits sizeLimits()
      Specified by:
      sizeLimits in interface NativeWindow
      Returns:
      the bounds the user may resize this window within, as its configuration or the last NativeWindow.setSizeLimits(int, int, int, int) set them; SizeLimits.NONE where the implementation keeps none (headless, embedding)
    • show

      public void show()
      Specified by:
      show in interface NativeWindow
    • hide

      public void hide()
      Specified by:
      hide in interface NativeWindow
    • focus

      public void focus()
      Description copied from interface: NativeWindow
      Brings this window to the front and gives it input focus. UI thread only.
      Specified by:
      focus in interface NativeWindow
    • focusRequests

      public int focusRequests()
      How many times something asked this window for the input focus: a focus() call, and showing a window created with WindowConfig#focusOnShow, as a menu in a window of its own is. Nothing moves it here, as nothing moves a desktop's without its window manager; desktopFocus(boolean) is that.
      Returns:
      the count of focus() calls
    • focusOnShow

      public boolean focusOnShow()
      Returns:
      whether the window was created asking for the keyboard as it is shown (WindowConfig#focusOnShow), as a menu in a window of its own is: the window a desktop sends the next key to, once it is up
    • isVisible

      public boolean isVisible()
      Specified by:
      isVisible in interface NativeWindow
      Returns:
      whether the window is currently visible on screen
    • isClosed

      public boolean isClosed()
      Specified by:
      isClosed in interface NativeWindow
      Returns:
      whether this window has already been closed/destroyed
    • enterFullscreen

      public void enterFullscreen(int w, int h, int refreshRate)
      Description copied from interface: NativeWindow
      Makes the window fullscreen on the monitor it occupies, in one of two ways, chosen by whether the call names a display mode.

      Naming no mode, width, height and refreshRate all ≤ 0 as NativeWindow.enterFullscreen() passes them, leaves the display in the mode it is in, which is the fullscreen a document, a dashboard or any application that is not a game wants:

      • macOS: native fullscreen, what the green button and Control-Command-F do. The window moves to a Space of its own with an animation of most of a second, the menu bar and the title bar slide in when the pointer reaches the top of the screen, and the person can leave it the way they leave any application's. This call returns before the animation ends, and the window reports its new size when AppKit resizes it.
      • Windows and X11: a borderless window covering the monitor at the mode it is in, on X11 through the window manager's fullscreen state where it has one.
      • Wayland: the compositor's fullscreen.

      Naming a mode, a size or a refresh rate or both, is the exclusive fullscreen a game asks for: the display is switched to the mode it lists nearest to the one named, which holds the application for a noticeable moment each way (more than half a second on a Mac), and is switched back by NativeWindow.exitFullscreen(). A dimension ≤ 0 beside a named one is the current one. The size is in screen coordinates, as a Resolution's is: pixels on Windows, X11 and Wayland, points on macOS. On macOS the window covers the menu bar and the Dock and has no Space of its own; the mode a Retina display is in is usually not one it can be switched to, so naming the current mode switches to another. Wayland lets no application change the display's mode, and there the window is fullscreen at the compositor's whatever is named.

      Losing the focus tells the two apart. A window at a named mode is minimized when another window takes the focus, on every platform, and a switched mode is switched back until the window is restored, which is what a game wants when the person switches away from it. A window at the mode the display is in is not: on Windows, X11 and Wayland it stays fullscreen behind the window that took the focus, as a browser's fullscreen does, and the person comes back to it as they left it; on macOS the person moves to another Space and back.

      A window already fullscreen one way and asked for the other leaves the first: a switched mode is switched back before native fullscreen begins, and native fullscreen is left, with its animation, before the mode is switched. The windowed position and size are remembered for NativeWindow.exitFullscreen(). UI thread only.

      Specified by:
      enterFullscreen in interface NativeWindow
      Parameters:
      w - width in screen coordinates, or ≤ 0 to name none
      h - height in screen coordinates, or ≤ 0 to name none
      refreshRate - refresh rate in Hz, or ≤ 0 to name none
    • exitFullscreen

      public void exitFullscreen()
      Description copied from interface: NativeWindow
      Leaves fullscreen of either kind, and does nothing for a window that is not fullscreen. A switched mode is switched back and the windowed position and size asked for before this returns, and given back as the window had them: where the window manager answers later, as on X11, a window it gives back maximized when it was not, or elsewhere or at another size, is asked once more when the answer comes. macOS native fullscreen is left with its animation, after this returns, and is left whether the application or the person entered it. UI thread only.
      Specified by:
      exitFullscreen in interface NativeWindow
    • isFullscreen

      public boolean isFullscreen()
      Description copied from interface: NativeWindow
      Whether the window is fullscreen, of either kind. On macOS that includes native fullscreen the person entered with the green button, Control-Command-F or the menu, and the answer is where the window is going rather than where its animation has got to: true from the moment NativeWindow.enterFullscreen() returns or the person starts the animation, false from the moment NativeWindow.exitFullscreen() returns or the person starts leaving. Elsewhere it is whether this window was made fullscreen and has not been told to leave.

      Each change of this answer is told to the window's input, through WindowInput.windowFullscreenChanged(boolean), including the changes the person makes on macOS. A window that can never be fullscreen never tells it.

      Specified by:
      isFullscreen in interface NativeWindow
      Returns:
      whether the window is, or is going to be, fullscreen
    • isModalBlocked

      public boolean isModalBlocked()
      Specified by:
      isModalBlocked in interface NativeWindow
      Returns:
      whether this window is currently locked by an active modal (its input is ignored); the scene dims it while true
    • isModal

      public boolean isModal()
      Specified by:
      isModal in interface WindowPeer
      Returns:
      whether this window is itself an active modal: one the backend registered through BackendPeer.pushModal(limn.backend.NativeWindow, limn.backend.NativeWindow), blocking the window it was opened over, or every other window when it was opened over none. The other end of NativeWindow.isModalBlocked(): that is the owner's bit and this is the dialog's, and it is this one an accessible tree publishes on the window's own node, because a client asks a window whether it blocks what it owns and never whether something else blocks it
    • registerChildPopup

      public void registerChildPopup(NativeWindow child, WindowPeer.PopupKind kind)
      Description copied from interface: WindowPeer
      Registers a child popup and says what it is; see WindowPeer.PopupKind, which is the whole reason this overload exists.
      Specified by:
      registerChildPopup in interface WindowPeer
    • unregisterChildPopup

      public void unregisterChildPopup(NativeWindow child)
      Description copied from interface: WindowPeer
      Unregisters a child popup that closed on its own.
      Specified by:
      unregisterChildPopup in interface WindowPeer
    • setCloseRequestHandler

      public void setCloseRequestHandler(@Nullable CloseRequestHandler handler)
      Kept, and asked when the user closes this window (userClose()) or the application ends.
      Specified by:
      setCloseRequestHandler in interface NativeWindow
      Parameters:
      handler - the handler, or null for none
    • closeRequestHandler

      public @Nullable CloseRequestHandler closeRequestHandler()
      Specified by:
      closeRequestHandler in interface NativeWindow
      Returns:
      the handler set with NativeWindow.setCloseRequestHandler(limn.backend.CloseRequestHandler), or null for none
    • setClosePolicy

      public void setClosePolicy(ClosePolicy policy)
      Description copied from interface: NativeWindow
      Sets what a user's close does once it is allowed: dispose the window (the default), hide it, or end the application. A program's NativeWindow.requestClose() disposes whatever this says. UI thread only.
      Specified by:
      setClosePolicy in interface NativeWindow
      Parameters:
      policy - the policy; never null
    • closePolicy

      public ClosePolicy closePolicy()
      Specified by:
      closePolicy in interface NativeWindow
      Returns:
      what a user's close does; ClosePolicy.DISPOSE unless set
    • setFrameCallback

      public void setFrameCallback(FrameCallback newCallback)
      Description copied from interface: WindowPeer
      Registers the per-frame render callback.
      Specified by:
      setFrameCallback in interface WindowPeer
    • setInput

      public void setInput(WindowInput newInput)
      Description copied from interface: WindowPeer
      Registers the input sink (usually the scene). See WindowInput.
      Specified by:
      setInput in interface WindowPeer
    • backend

      public Backend backend()
      Specified by:
      backend in interface NativeWindow
      Returns:
      the backend that owns this window (popup creation, shutdown)
    • clipboard

      public Clipboard clipboard()
      The backend's clipboard, which all its windows share; never null, as a window's is not.
      Specified by:
      clipboard in interface NativeWindow
      Returns:
      the system clipboard
    • screenX

      public int screenX()
      Specified by:
      screenX in interface NativeWindow
      Returns:
      window x in native screen coordinates
    • screenY

      public int screenY()
      Specified by:
      screenY in interface NativeWindow
      Returns:
      window y in native screen coordinates
    • setScreenPosition

      public void setScreenPosition(int x, int y)
      Description copied from interface: NativeWindow
      Moves the window (native screen coordinates; see NativeWindow.logicalToScreenFactor()).
      Specified by:
      setScreenPosition in interface NativeWindow
    • screenPositionRequests

      public int screenPositionRequests()
      How many times something asked to place this window on the screen, which a popup does when what it stands against moves. The window itself stays where screenX() says, as a headless window has no screen to move on.
      Returns:
      the requests since the window was made
    • requestedScreenX

      public int requestedScreenX()
      Returns:
      the x of the last setScreenPosition(int, int) asked for, in screen pixels; 0 before any
    • requestedScreenY

      public int requestedScreenY()
      Returns:
      the y of the last setScreenPosition(int, int) asked for, in screen pixels; 0 before any
    • logicalToScreenFactor

      public float logicalToScreenFactor()
      Specified by:
      logicalToScreenFactor in interface NativeWindow
      Returns:
      multiplier from logical points to native screen coordinates (1.0 on macOS, the monitor scale on Windows/X11), for positioning popups relative to widget bounds
    • captureNextFrame

      public void captureNextFrame(Consumer<Image> sink)
      Description copied from interface: NativeWindow
      Captures the next rendered frame (post-flush, pre-swap) and hands the pixels to sink: a per-window screenshot without touching the frame callback, and without a file. Requests a frame, so it works on an idle window. sink runs on the UI thread inside that frame.

      The image is display-referred: it is what the composite produced, not scene-referred content awaiting a display transform. See GpuRenderer.captureFramebuffer(java.util.function.Consumer).

      Specified by:
      captureNextFrame in interface NativeWindow
    • setContentScaleListener

      public void setContentScaleListener(NativeWindow.ContentScaleListener listener)
      Description copied from interface: NativeWindow
      Registers a listener for runtime monitor/content-scale changes.
      Specified by:
      setContentScaleListener in interface NativeWindow
    • requestFrame

      public void requestFrame()
      Description copied from interface: NativeWindow
      Marks the window dirty so the loop renders a frame for it. UI thread only: from a background thread, hop with Ui.post(window::requestFrame).
      Specified by:
      requestFrame in interface NativeWindow
    • takeFrameRequests

      public int takeFrameRequests()
      How many frames the scene has asked this window for since the last call, which also sets the count back to nothing. A scene that is at rest asks for none: a test that shows a screen, lets it settle and then reads zero here has shown that the screen costs nothing while nobody touches it.
      Returns:
      the frames asked for since this was last read
    • requestClose

      public void requestClose()
      Description copied from interface: NativeWindow
      Asks the window to close (processed by the event loop). Any-thread safe.
      Specified by:
      requestClose in interface NativeWindow
    • close

      public void close()
      Closes as a desktop backend does: the windows it owns close first, the bound scene is told, once, and the window is gone.
      Specified by:
      close in interface AutoCloseable
      Specified by:
      close in interface NativeWindow