Class LwjglBackend

java.lang.Object
limn.backend.lwjgl.LwjglBackend
All Implemented Interfaces:
AutoCloseable, Backend, BackendPeer

public final class LwjglBackend extends Object implements BackendPeer
GLFW + OpenGL 3.3 core implementation of Backend.

Must be constructed on the process main thread (on macOS the JVM needs -XstartOnFirstThread); that thread becomes the Limn UI thread. The event loop is event-driven: it sleeps in glfwWaitEvents() (or glfwWaitEventsTimeout() when a delayed task is scheduled) and is woken by native events or by glfwPostEmptyEvent() whenever another thread posts through Ui.

Waking is not painting: the loop runs the tasks and then renders only the windows something asked a frame of, so an application whose posted task mutates a widget without invalidating it will not see the change.

On macOS a process runs as an agent, with no icon in the Dock, no menu bar of its own and no window that comes in front of what the user is doing, when its package says so (LSUIElement), and also when it is started with -Dlimn.macos.agent=true or with the environment variable LIMN_MACOS_AGENT set to 1 or true. The last two are for runs whose windows nobody looks at, such as tests, and the variable is inherited: an application started by a process that has it set starts as an agent too.

  • Field Details

    • PLATFORM_PROPERTY

      public static final String PLATFORM_PROPERTY
      The windowing platform to ask GLFW for, which is only a question on Linux.

      Values: x11, wayland, any. Unset means the default below.

      See Also:
    • FORCE_IN_SCENE_POPUPS_PROPERTY

      public static final String FORCE_IN_SCENE_POPUPS_PROPERTY
      Set this to true to make every window report that it cannot be positioned, which puts menus and dropdowns into the owner scene on a platform that would otherwise place them in windows.

      It exists so the fallback can be looked at. Wayland is the only platform that really needs it, and a presentation that can only be seen on one desktop is one that gets broken on the other three and noticed a release later. With this the demo renders it anywhere, including into a --screenshot. It changes no behaviour the application chooses and none that a user can reach.

      See Also:
  • Constructor Details

    • LwjglBackend

      public LwjglBackend()
      Starts the backend on the calling thread, which becomes the UI thread: loads the native libraries, initializes GLFW and installs the toolkit's services. On macOS the calling thread must be the process's first, which is what -XstartOnFirstThread arranges.
      Throws:
      IllegalStateException - when the native libraries do not load or GLFW cannot start; the message says why and what to try
    • LwjglBackend

      public LwjglBackend(@Nullable String applicationName)
      Starts the backend as LwjglBackend() does, for an application with a name.

      The name is what macOS writes in bold in its menu bar and in the items of the application's menu there, for an application that is not packaged: a packaged one is named by its package, and an unpackaged one given no name here is shown under the name of the program that launched it. It has to be given here because the system reads it once, as the windowing library starts. -Dlimn.application.name gives it to a launch that calls the other constructor. On every system it is also what setApplicationName(java.lang.String) would set.

      Parameters:
      applicationName - the application's name, or null for none
      Throws:
      IllegalStateException - as LwjglBackend()
  • Method Details

    • startupFailure

      public static GraphicsInfo startupFailure(String failure)
      The graphics report for a machine where this backend could not be constructed at all, which graphicsInfo() cannot answer because there is no instance to ask it of.

      It carries the one thing that is knowable before glfwInit: the version string of the GLFW that is loaded, which lists the platforms that libglfw was BUILT with. On the failure this exists for that is exactly the useful contrast — a library naming Wayland and X11 next to a machine running neither is a headless machine, not a broken library. The platform is reported as none, because failing to select one is what happened.

      Parameters:
      failure - why the backend could not be constructed; becomes GraphicsInfo.failure()
    • uiRuntime

      public UiRuntime uiRuntime()
      Specified by:
      uiRuntime in interface Backend
      Returns:
      the concurrency runtime owned by this backend
    • setApplicationName

      public void setApplicationName(String name)
      Names this application where the desktop's accessibility tree lists applications by name.

      On Linux, AT-SPI2 shows one application object per process with every window beneath it, and a screen reader says that name when the user moves into the application; left unset, a backend uses the title of the first window it created, which is right for a one-window program and wrong for one whose first window is a splash or a login. Windows names an application from the process itself and reads nothing here. Call it before the first window for the name to be there from the start; a later call renames the application for the next client that asks.

      On macOS the name is also what the toolkit writes in the items of the application's menu (About, Hide, Quit). It is not what the system writes in bold at the head of its menu bar: the system reads that once, as the windowing library starts, from the application's package, and for an application that is not packaged from the name the backend was made with. A backend that takes a name at its construction says so there.

      Handed to every window's accessibility bridge as it opens, and to the process's AT-SPI application at once when windows already have one.

      Specified by:
      setApplicationName in interface Backend
      Parameters:
      name - what the desktop should call this application; never null
    • createWindow

      public WindowPeer createWindow(WindowConfig config)
      Description copied from interface: BackendPeer
      Creates (but does not necessarily show) a native window, as its peer. UI thread only.
      Specified by:
      createWindow in interface Backend
      Specified by:
      createWindow in interface BackendPeer
    • compositorShadowsPopups

      public boolean compositorShadowsPopups()
      Read from each system's screen (2026-10-10) with a list, a menu, a calendar and an undecorated dialog open: macOS casts a shadow around such a window; Windows 11, GNOME under X11 and KDE under Wayland cast none. Under Wayland only the dialog is a window of its own, the other three being drawn in the owner's scene.
      Specified by:
      compositorShadowsPopups in interface Backend
      Returns:
      true (the default) where the compositor casts it, and for a backend with no desktop under it, which then draws nothing extra
    • graphicsInfo

      public GraphicsInfo graphicsInfo()
      Specified by:
      graphicsInfo in interface Backend
      Returns:
      which graphics context this backend obtained and which optional capabilities it has: the report a bug about a machine that will not start, or that renders slowly, has to carry. The strings live on the context, so this is only answerable once Backend.createWindow(limn.backend.WindowConfig) has succeeded at least once; before that, and on a machine where it never does, the result carries the windowing platform and a GraphicsInfo.failure() instead. Default: GraphicsInfo.NONE. UI thread only.
    • runEventLoop

      public LoopEnd runEventLoop()
      Description copied from interface: Backend
      Runs the event/render loop on the calling (UI) thread. Returns when the last window closes (under LoopLifetime.UNTIL_LAST_WINDOW), when a Backend.requestQuit() was agreed to and every window has closed, or when Backend.stop() is invoked.
      Specified by:
      runEventLoop in interface Backend
      Returns:
      why it returned
    • setLoopLifetime

      public void setLoopLifetime(LoopLifetime newLifetime)
      Description copied from interface: Backend
      Sets how long Backend.runEventLoop() runs: until the last window closes (the default) or until the application ends it, which lets an application live with no window open. UI thread only.
      Specified by:
      setLoopLifetime in interface Backend
      Parameters:
      newLifetime - the lifetime; never null
    • loopLifetime

      public LoopLifetime loopLifetime()
      Specified by:
      loopLifetime in interface Backend
      Returns:
      how long Backend.runEventLoop() runs; LoopLifetime.UNTIL_LAST_WINDOW unless set
    • requestQuit

      public void requestQuit()
      Description copied from interface: Backend
      Asks to end the application. The quit handler is asked first, then every open top-level window's handler, front to back (the window used last first), one at a time; a window with no handler agrees. A refusal anywhere ends the request and every window stays open. When all have agreed, every window closes, owned ones included, and Backend.runEventLoop() returns LoopEnd.QUIT.

      A request made while one is being answered joins it. On macOS the system's Quit command for the application (Cmd-Q, the application menu, the Dock) makes this request. UI thread only.

      Specified by:
      requestQuit in interface Backend
    • setQuitHandler

      public void setQuitHandler(@Nullable QuitHandler handler)
      Description copied from interface: Backend
      Sets the handler Backend.requestQuit() asks before any window, for what belongs to no window. null clears. UI thread only.
      Specified by:
      setQuitHandler in interface Backend
      Parameters:
      handler - the handler, or null for none
    • pushModal

      public void pushModal(NativeWindow modal, @Nullable NativeWindow parent)
      Description copied from interface: BackendPeer
      Registers modal as an active modal window and pushes it on the modal stack. Only the topmost modal receives input; every window it locks ignores input until it closes.

      Modality scope: a non-null parent makes it window-modal, so it locks only parent (and parent's owned popups), leaving unrelated windows interactive. A null parent makes it toolkit-modal, so it locks every other window. Modals stack: with several open, only the top one is usable and the non-modal windows are released only after the whole modal stack closes. UI thread only.

      Specified by:
      pushModal in interface BackendPeer
    • popModal

      public void popModal(NativeWindow modal)
      Description copied from interface: BackendPeer
      Removes modal from the modal stack, releasing what it locked. UI thread only.
      Specified by:
      popModal in interface BackendPeer
    • pushSceneModal

      public BackendPeer.SceneModalHandle pushSceneModal(NativeWindow owner, boolean toolkitScope)
      Description copied from interface: BackendPeer
      Registers an in-scene (overlay) modal hosted by owner. Unlike BackendPeer.pushModal(limn.backend.NativeWindow, limn.backend.NativeWindow), there is no separate modal window: the overlay blocks owner's own content, so owner stays interactive, while this call blocks the same sibling windows a native modal would. toolkitScope true locks every other window; false locks only owner's owned popups. Release the returned handle when the overlay closes. UI thread only.
      Specified by:
      pushSceneModal in interface BackendPeer
    • signalModalBlocked

      public void signalModalBlocked()
      Description copied from interface: BackendPeer
      Gives the modal-blocked feedback (the alert sound plus a re-raise of the top modal) for an interaction the active modal ignores. The backend already does this for clicks on blocked native windows; call it for an in-scene modal's scrim so internal and native modals feel identical. UI thread only.
      Specified by:
      signalModalBlocked in interface BackendPeer
    • renderStats

      public RenderStats renderStats()
      Specified by:
      renderStats in interface Backend
      Returns:
      aggregate GPU resource usage across all windows (texture count + estimated bytes), for diagnostics. Default: RenderStats.EMPTY. UI thread only.
    • render3DStats

      public Render3DStats render3DStats()
      Specified by:
      render3DStats in interface Backend
      Returns:
      aggregate 3D-subsystem GPU usage across all windows (meshes, textures, render targets, bytes, and last-frame draw calls/triangles), for diagnostics. Default: Render3DStats.EMPTY. UI thread only.
    • displays

      public List<Display> displays()
      Specified by:
      displays in interface Backend
      Returns:
      every connected Display, in the platform's order (index 0 is usually the primary). Empty when headless/embedded. UI thread only.
    • primaryDisplay

      public @Nullable Display primaryDisplay()
      Specified by:
      primaryDisplay in interface Backend
      Returns:
      the primary Display, or null when headless. Default: the display that reports Display.isPrimary(), else the first of Backend.displays(). UI thread only.
    • stop

      public void stop()
      Description copied from interface: Backend
      Asks the loop to exit. Safe to call from any thread.
      Specified by:
      stop in interface Backend
    • systemMenuBar

      public @Nullable SystemMenuBar systemMenuBar()
      Description copied from interface: BackendPeer
      The menu bar the system keeps outside the windows, where it keeps one and the application may have it.

      The default is the answer of every system but one: null, and a menu bar is drawn in its window.

      Specified by:
      systemMenuBar in interface BackendPeer
    • createTray

      public TrayPeer createTray(String id, TrayHost host)
      Description copied from interface: BackendPeer
      Makes the peer of a tray icon. Nothing is shown until its first TrayPeer.update(limn.backend.spi.TrayState). UI thread only.

      The default is the answer of a backend with no desktop under it: a peer that shows nothing and is never available.

      Specified by:
      createTray in interface BackendPeer
      Parameters:
      id - the application's identifier for this icon: ASCII letters, digits, a dot, a hyphen and an underscore, already checked, and no other tray of this backend has it
      host - what the peer asks the menu of and tells of a click
      Returns:
      the peer
    • close

      public void close()
      Description copied from interface: Backend
      Destroys all windows and releases native resources. UI thread only.
      Specified by:
      close in interface AutoCloseable
      Specified by:
      close in interface Backend