6 Window Systems and Windows
dxtr edited this page 2026-10-18 16:01:10 +02:00

Window Systems and Windows

Opening a window system

(win:open-window-system &rest options &key backend &allow-other-keys)
=> window-system

open-window-system connects to the platform's window system and returns a window-system. Close it with close-window-system, or use the macro:

(win:with-window-system (window-system :backend :wayland)
  ...)

with-window-system closes the window system however its body is left, unless it was closed already.

Choosing a backend

With :backend, the window system uses that backend: a keyword such as :wayland or :win32. Without it, the window system uses the platform's backend: :win32 on Windows and :wayland elsewhere.

The backend's system must be loaded, or open-window-system signals no-backend-error, which names the system to load and the backends that are loaded:

The window system backend :WAYLAND is not loaded.  Load the system
cl-windowing/wayland first.  Loaded backends: none.

Backend options

The other options go to the backend. A backend ignores options it does not know. The Wayland backend takes:

Option Meaning
:display-name The compositor's socket, such as "wayland-1". By default $WAYLAND_DISPLAY.
:connection A cl-wl:display you connected already. The window system uses it and does not disconnect it when it closes.

See Wayland Backend. The Win32 backend takes no options; see Win32 Backend.

Failure

If the window system cannot be reached, open-window-system signals window-system-error, and its message says what to check:

Cannot connect to the Wayland compositor "no-such-socket": Could not
connect to the Wayland display "no-such-socket".  Is a compositor running,
and is $WAYLAND_DISPLAY or :DISPLAY-NAME right?

What a window system tells you

Function Returns
(window-system-backend ws) The backend's keyword, such as :wayland.
(window-system-open-p ws) True until close-window-system.
(window-system-windows ws) A fresh list of its windows that are alive, popups included.
(window-system-capabilities ws) What it can do beyond the basics; see below.

Capabilities

window-system-capabilities returns a list of keywords:

Capability Meaning
:server-side-decorations The window system can draw title bars and borders for windows.
:fractional-scale Windows may have scales between whole numbers, such as 3/2.
:clipboard clipboard-text can read and set the clipboard. See Clipboard.
:pointer-capture window-pointer-mode can confine and capture the pointer. See Cursors and Pointer Modes.
:keyboard A keyboard is attached now.
:pointer A pointer is attached now.

Ask instead of assuming: capabilities differ between backends, between compositors and between machines. :keyboard and :pointer come and go as devices do, and they appear only after process-events has read the compositor's announcement of them. Right after open-window-system they are usually missing. A headless compositor may have neither.

Creating a window

(win:create-window window-system &key (title "") (width 800) (height 600) app-id parent modal)
=> window

create-window creates a top-level window and asks for a size of width by height units. With parent, the window is a dialog of that window, and with modal too, a modal one: see Dialogs. For popups, see Popups. Destroy it with destroy-window, or use the macro:

(win:with-window (window window-system :title "Editor" :width 1280 :height 720
                                       :app-id "org.example.Editor")
  ...)

app-id names the application to the window system, which uses it to group the application's windows and find its icon and .desktop file. Use a reverse domain name, such as "org.example.Editor". Windows does not use it: it groups the windows of a process itself.

Before the window is drawn

On Wayland, a new window is not on screen yet. Two things happen first:

  1. The window system proposes a first size. window-configured-p becomes true, and a :resize event reports the size. This first size is taken at once, with no handshake.
  2. Something is drawn into the window. Only then does it appear.

On Windows, the first size is proposed before create-window returns, so window-configured-p is true at once, and the window is on screen before anything is drawn.

Nothing may be drawn before the first size: on Wayland, a frame presented before it is a protocol error, and the compositor disconnects the program. So until then window-pixel-size is 0 by 0, and a renderer sized by it has nothing to draw into. cl-gfx surfaces return nil from acquire-surface-texture meanwhile, as for a minimised window, so a cl-gfx program needs to do nothing.

If you present with Vulkan directly, present nothing before window-configured-p is true. To wait for it, bound the wait:

(loop repeat 100
      until (win:window-configured-p window)
      do (win:process-events window-system :timeout 0.05))
(unless (win:window-configured-p window)
  (error "The window system did not configure the window within 5 seconds."))

The first size may differ from the size asked for. A tiling compositor, for example, chooses sizes itself.

What a window tells you

Function Returns
(window-window-system window) The window system it belongs to.
(window-alive-p window) True until destroy-window.
(window-title window) Its title. setf it to change the title.
(window-configured-p window) True once the window system has proposed its first size.
(window-size window) Its width and height in units, as last adopted, or as asked for until configured.
(window-scale window) Its scale, as last adopted.
(window-pixel-size window) The width and height of its frames in pixels, or 0 and 0 until configured.
(window-pending-size window) The width, height and scale proposed and not yet adopted, or nil, nil, nil.
(window-pending-pixel-size window) The same in pixels, or nil, nil.
(window-decorations window) :server-side or :none; see below.
(window-fullscreen-p window) True while it is fullscreen; see below.
(window-cursor window) The pointer's look over it, :default at first. See Cursors and Pointer Modes.
(window-pointer-mode window) How the pointer is held over it, :free at first.
(window-popups window) Its popups that are alive, oldest first.
(window-dialogs window) Its dialogs that are alive, oldest first.
(window-parent window) The window it was made on, for a dialog or a popup; nil for a window of its own.
(window-modal-p window) True for a modal dialog.

Size and scale are covered on Resizing and Scaling.

Titles

(setf (win:window-title window) "Untitled - Editor")

The title is sent to the window system at once.

Decorations

Title bars and borders are decorations. window-decorations says who draws them:

  • :server-side: the window system does.
  • :none: nobody does yet. The engine will draw its own.

On Wayland, cl-windowing asks for server-side decorations through xdg-decoration wherever the compositor offers it, as KDE Plasma and Sway do. Some compositors, such as GNOME's Mutter and Weston, do not offer it, and windows are undecorated there. A window's decorations start as :none and change to :server-side once the compositor agrees, which happens during process-events. On Windows, windows have the system's title bars and borders: :server-side. Popups have none.

Fullscreen

(setf (win:window-fullscreen-p window) t)     ; on F11, say
(setf (win:window-fullscreen-p window) nil)   ; and back

A fullscreen window covers the display it is on, without decorations, and the window system sizes it: its size comes as a :resize event, as any other, and set-window-size asks nothing while it lasts. The window system decides: window-fullscreen-p says what it did, once it has. Back from fullscreen, the window is as it was. A popup is never fullscreen: setting it signals popup-error.

  • On Wayland, the compositor makes the window fullscreen on the output it chooses, and says so in a configure, so window-fullscreen-p changes as events are processed.
  • On Windows, a fullscreen window is a window without a frame covering its display, at once. Leaving fullscreen puts it back where it was, maximised if it was.

Destroying

(win:destroy-window window)
(win:close-window-system window-system)

Destroy what draws into a window first, such as its cl-gfx surface or Vulkan surface. destroy-window destroys a window's popups and dialogs first, the newest first. close-window-system destroys the windows still alive, then disconnects. Both succeed even when the connection to the window system has failed.

Events about a window may still be queued after it is destroyed. event-window then returns a window whose window-alive-p is false. A window that is used after it is destroyed signals closed-error, and so does a window system after it is closed. See Errors.