Skip to content

About

Warp-inspired X11 workspace and window manager for MidnightBSD

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Midnight Workspace

Midnight Workspace is a Warp-inspired X11 desktop shell and window manager for MidnightBSD. The current target is MidnightBSD 4.2 with Clang 19 and C++23.

Build

The build needs CMake, pkg-config, XCB (including icccm, keysyms, XFixes, and RandR, Xinerama), Cairo, Pango, GLib/GIO, GdkPixbuf, Garcon, and SQLite 3. The companion midnightbsd-settings application also needs GTK 3. The separate midnightbsd-system-monitor application uses GTK 3, libutil, and libgeom. The midnightbsd-session launcher and XSMP tests also need libSM and libICE. Install the librsvg GdkPixbuf loader for SVG wallpapers; the mport includes this runtime dependency. PNG, JPEG, and GIF loaders must also be available.

cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build
ctest --test-dir build --output-on-failure
cmake --install build --prefix /usr/local

Select Midnight Workspace from an X11 display manager, or run exec /usr/local/bin/midnight-wm from .xinitrc. Only one window manager can control an X screen at a time. midnight-wm --version prints the version. At startup, Midnight Workspace uses an existing D-Bus session bus when one is reachable. If none is available and dbus-run-session is installed, it starts a bus for the X11 session and stops it when Midnight Workspace exits. Without the D-Bus tools, the desktop still starts, but D-Bus integrations are unavailable. Before starting desktop applications, Midnight Workspace uses the session bus's configured org.freedesktop.secrets provider for password storage, preserving an existing provider such as KWallet or KeePassXC. If no provider is available, it starts GNOME Keyring when installed. A working inherited SSH_AUTH_SOCK is preserved; otherwise GNOME Keyring's SSH component is tried, followed by a session-owned OpenSSH ssh-agent. The fallback agent ends with the session. Keyring unlock at login depends on the display manager's PAM configuration; starting a keyring here may prompt for its password when first used.

AI chat companion

Run midnightbsd-chat or choose Midnight Chat from Programs. This separate GTK 3 application provides plain-text chat with local or LAN OpenAI-compatible servers. Optional tools provide bounded, read-only information for a chat; there is no general-purpose command execution or autonomous agent. Building it requires libsoup-3.0, json-glib-1.0, and SQLite 3 in addition to GTK 3.

Use the Server selector to switch between saved local or LAN servers. Add server creates a named profile; Settings edits the selected profile, and Remove server removes it after confirmation. At least one server remains; up to 32 profiles are supported. Each profile has its own endpoint, optional bearer token, model, context/reply limits, request deadline, and tool settings. New profiles start with authentication and tools disabled. Your existing single-server settings become the first profile without losing their values. Switching keeps the current conversation and draft; subsequent messages and conversation context go to the selected server. Switching is disabled while a request is running. Each server remembers its model; refresh its model list when needed. Removing a server leaves conversations intact.

In Settings, enter a base URL (normally http://localhost/v1) and port: 11434 for Ollama or 8080 for llama.cpp. Port 0 uses the port in the URL or its scheme default. Authentication is off by default; enable it for an optional bearer token. Refresh models fills the editable model dropdown from /v1/models. Select a downloaded chat model, or type its name when discovery is unavailable. The protocol follows the Ollama compatibility API and llama.cpp server API.

Conversations appear on the left. Ctrl+Enter sends; Enter adds a newline. Stop cancels generation. Send / Retry with an empty input retries an unanswered message; replacement text edits that pending message. Replies appear when generation completes. Requests have a configurable deadline and run off the UI thread. You can switch conversations while waiting; drafts stay with their conversation for the lifetime of the application.

Set Context tokens to the server's actual configured context size; this setting does not change the server. The client reserves reply space and uses a conservative UTF-8 byte estimate plus template overhead. When necessary, older complete turns are summarized by the same model in bounded batches. Summaries can lose details; full original transcripts remain visible locally. Reset context excludes previous turns from subsequent requests while preserving the transcript. Very large individual turns produce an error instead of being silently truncated.

The Tools tab in Settings enables each tool separately; all are off by default. A model with tool-calling support is required when tools are enabled. The client executes requests locally and sends the results to the configured model server. Tool names, arguments and result previews appear in the saved transcript. Tool outputs are treated as data and never executed as instructions.

  • File search searches the locate database for literal filename matches and returns up to 20 currently readable paths. It does not read file contents; an absent or stale database can affect results.
  • System information reports OS, architecture, online CPUs and load, plus native BSD CPU model, physical memory and uptime where available. It excludes hostnames, environment variables, usernames and process listings.
  • Mport searches query installed packages or the cached repository index by literal name/description text, using read-only database connections and bound parameters. A dedicated count tool returns exact package totals. Searches report exact totals before their limited previews; * is not an all-packages wildcard. No package installation, removal, index refresh or privilege escalation occurs.
  • Web search supports Brave Search (requires a Brave API key) and a configured SearXNG JSON search endpoint such as http://localhost:8080/search. SearXNG must allow the JSON format. Results contain titles, URLs and snippets; pages are not fetched. Search queries go to the selected provider; the chat-server token is never forwarded to it. Brave keys are sent only to the fixed HTTPS Brave API.

Each reply defaults to 12 tool rounds and 24 calls, executed sequentially. Settings → Tools allows 1–32 rounds and 1–64 calls per reply. Repeated searches with identical JSON argument values reuse the earlier result without executing again; the model is prompted to refine its query or use existing evidence. Skipped repetitions still count toward the limits. Settings → Connection sets the request deadline (60–3600 seconds; default 900 seconds / 15 minutes), including model exchanges and compaction. Stop remains available throughout. At the limit, the model is asked to state its findings and what remains unresolved using the collected results with tools disabled. If the model still requests tools, extra calls are ignored and collected results remain visible, with a notice if no answer was provided. Tools have bounded output and time limits and follow Stop. Long result previews are explicitly truncated to fit the remaining context; compaction includes saved tool results with their conversation turns. Models that do not support tools can still be used with all tool switches disabled.

Server profiles and the selected server (including any tokens) are stored in $XDG_CONFIG_HOME/midnightbsd-chat/settings.json, and transcripts and summaries in $XDG_DATA_HOME/midnightbsd-chat/conversations.json. Defaults are ~/.config and ~/.local/share. Directories are private (0700), files are private (0600), and saves use atomic replacement. Tokens are not encrypted at rest. HTTP is unencrypted; HTTPS verifies certificates. Redirects and environment proxies are disabled. No request is made until you refresh models or send a message. Invalid or insecure files are reported and left intact; repair or move the reported file before restarting. History is bounded to 16 MiB and 1000 threads.

ctest --test-dir build -R chat_protocol_test --output-on-failure verifies local HTTP fixtures, authentication, summaries, storage and error handling. ctest --test-dir build -R chat_tools_protocol --output-on-failure additionally checks tool dispatch, read-only package queries, literal filename searches, web response parsing, credential separation and tool-call limits. python3 tests/chat_smoke.py exercises the GUI in isolated Xvfb/HOME/XDG settings; add --tools to exercise tool results and the Tools settings tab. To test an actual backend sequentially, use python3 tests/chat_smoke.py --live http://HOST:11434/v1 --model mistral:7b.

Window shadows and compositing

Install Picom to enable soft window shadows. Midnight Workspace starts Picom in the foreground with its XRender backend and a fixed shadow preset, excluding the desktop, panel, and fullscreen windows. It does not read or overwrite your separate Picom configuration. A compositor already owning the screen is preserved; only a Picom process started by Midnight Workspace is stopped when disabling shadows or ending the session.

Uncheck Window shadows in Settings → Appearance, or set compositing=false in [Workspace], to disable the session-owned compositor. Changes apply live. This switch leaves an independently started compositor running. Missing Picom or unsupported X11 extensions leave the desktop usable without compositing. If Picom exits unexpectedly, toggle the setting off and on to retry; the session does not repeatedly restart a failing compositor.

Run python3 tests/compositor_smoke.py with Picom installed to check actual window and folder shadows, panel exclusion, live Settings, and shutdown in an isolated Xvfb session. --picom /path/to/picom selects a test build. CTest also checks selection ownership, missing-executable fallback, and process cleanup without requiring Picom to be installed.

Desktop behavior

The top bar contains an application launcher, a lock button immediately to its right, a terminal button, a web browser button, task buttons, a volume control, a system tray, and a clock. The tray accepts legacy XEmbed icons and D-Bus StatusNotifierItem icons from applications. Panel controls, menus, folders, dialogs, and window title bars scale with the primary monitor height: 1× at 720p and 1080p, 1.25× at 1440p (including ultrawide), and 2× at 4K. Set ui_scale in the [Workspace] section of config.ini to a value from 0.75 to 3.0 to override this automatic choice. A resolution change repositions open folders and dialogs within visible monitor bounds. The panel and desktop shortcuts use the primary monitor; the lavender desktop covers all monitors. Scroll the desktop with the mouse wheel or Page Up/Page Down when its icons exceed the available height. Applications draw their own controls and use their toolkit's DPI settings. StatusNotifier items use icon theme names or embedded pixmaps and support left, middle, and right clicks plus mouse wheel actions. A session D-Bus is needed for StatusNotifier items; the legacy XEmbed tray also works without it. StatusNotifier context menus supplied through DBusMenu open in the Warp-style popup, including submenus, disabled items, separators, and toggle marks. When no other notification daemon owns org.freedesktop.Notifications, Midnight Workspace provides notification popups with application action buttons, images, and urgency handling. Critical notifications remain until dismissed; resident notifications can remain after an action. An existing notification daemon keeps control. The lock button asks a running xscreensaver daemon to lock the screen with xscreensaver-command -lock. Midnight Workspace starts that daemon at login when it is installed, unless Start XScreenSaver at login is disabled in Settings → Session. It leaves an existing daemon running. The choice takes effect at the next login. If no daemon is available, the desktop shows a notice. The terminal button opens the terminal selected by an xdg-terminals.list preference, or $TERMINAL if set. It opens xterm when neither is configured. The browser button opens the configured XDG default web browser. If no browser default is configured, it opens MidnightBSD's Raphael browser (www/raphael). If Raphael is unavailable, the desktop shows a notice. When windows exceed the available taskbar space, use the small down-arrow button after the visible tasks to open the remaining window list. The list has pages when needed, and selecting a window raises it. Open Programs in the launcher to browse applications using the freedesktop applications.menu layout (including user overrides, merges, and exclusions). When none is installed, Midnight uses its built-in categories. The menu displays submenus as named categories and paginates long lists. Recent Documents reads the shared recently-used.xbel history; files opened here are recorded there too. The launcher and category menus stay open while you browse, then close when you launch an app or click outside. The launcher also opens Trash directly, just above Exit X11 session…. Launcher icons follow the selected freedesktop icon theme, including inherited themes and the hicolor fallback. Launching an application that supports startup notification shows “Starting…” until its window appears or the launch times out. The XSETTINGS owner publishes the GTK theme, icon theme, font, DPI, and double-click values to X11 clients, while leaving an existing settings owner in control. Click the single speaker icon in the top panel to open the audio popup directly below it; click again, click outside, or press Escape to close it. Drag the volume slider and use Mute below it to mute or restore the previous stereo levels. The mouse wheel changes volume in 5% steps. With the popup open, Left/Right adjust volume and Space or M toggles mute. The control uses MidnightBSD's default OSS /dev/mixer, falling back to PCM when master volume is unavailable. The popup reports when no usable mixer is available. Running programs show their window icon beside the task title, including in the overflow menu. If a program supplies no usable icon, its installed desktop entry is matched by window class, with a generic application icon as fallback. Built-in folders use folder and Trash icons. Window icon changes apply live.

On systems with an ACPI battery, a battery icon and remaining percentage appear next to the speaker button. Charging displays a lightning marker; low battery uses a red fill. Click the indicator for power status and the remaining time estimate when available. Status refreshes every 30 seconds. The indicator is hidden when no battery is present; unavailable capacity is shown as ?. To hide it, uncheck Show battery indicator under Settings → Desktop and panel, or set show_battery=false in [Workspace]. The change applies immediately. Battery status uses MidnightBSD's hw.acpi.battery.* and hw.acpi.acline sysctls, as the base system batt utility does.

Running MPRIS media players appear below the volume controls, with track and artist information and previous, play/pause, and next controls. Click the player name to cycle between multiple players. Unsupported actions are disabled, and player discovery and commands use asynchronous D-Bus calls.

Right-click an application in Programs to see the additional actions from its .desktop entry, such as a new window. Trusted executable desktop launchers also expose their actions in the desktop context menu; their ownership and executable permission are checked again before launching.

Workspaces in the Midnight menu switches between four desktops. Ctrl+Alt+Left and Ctrl+Alt+Right also switch workspaces. Show desktop or Super+D hides application and folder windows temporarily; activating a task restores them. Settings → Keyboard shortcuts edits the four workspace directions, Show Desktop, task switching, and closing the active window. Enter combinations such as Ctrl+Alt+Left, or None to disable an action. Settings rejects invalid or duplicate combinations before saving, and valid changes take effect live. Applications can use standard EWMH workspace and Show Desktop requests. Clients supporting _NET_WM_PING are marked unresponsive after a timeout, and clients supporting _NET_WM_SYNC_REQUEST can acknowledge interactive resize updates. Resize timeouts allow interaction to continue when an application stops responding.

Settings → Session offers optional built-in folder sessions. Enable Save folders on logout to save open folder paths, normal geometry, workspace, and maximized/shaded state when confirming Exit X11 session… or receiving a normal termination signal. Cancelling logout leaves the running session intact. Enable Restore folders at login to reopen the saved folders and select the saved workspace; disable restoration to start fresh independently of saving. Missing folders are skipped, and geometry is adjusted to the current monitors and UI scale so restored windows remain reachable. Double-click a built-in folder's title to maximize/restore it; middle-click to shade/expand it. Activating its task expands a shaded folder. The title-bar minimize button hides a folder while retaining its taskbar entry; click that task to restore it. Minimized folders remain hidden across workspace and Show Desktop changes.

The Session page also offers Restore applications at login and Save application checkpoints, independently of the folder options. Click Apply to save these preferences; application saving uses the new preference at its next checkpoint or logout, while restoration changes take effect at the next login. Disable both restoration options to start fresh without deleting either saved session. Clear saved application session removes only the application checkpoint immediately, leaving running applications and the folder snapshot intact. Enabled saving can create a new checkpoint later. Application restoration requires the session companion and participating applications; applications control which documents and tabs they restore.

The equivalent configuration is [Session] with restore_folders=false and save_on_logout=false by default. Settings apply saving changes live; restoration is checked at startup. Clear saved folder session removes the snapshot without closing open folders. Saving on logout can create another snapshot afterward. State is stored atomically in $XDG_STATE_HOME/midnight-wm/session.ini (normally ~/.local/state/midnight-wm/session.ini), with a private directory and file. Malformed, incomplete, oversized, or unsupported-version snapshots are ignored and preserved until cleared, including on logout. Write failures before atomic replacement retain the existing snapshot; save errors go to the session log.

Participating XSMP applications can now be reopened when application restoration is enabled. Applications control their own document and tab restoration; terminal commands and other process state are not resumed. Participating windows restore their saved placement and supported states. Application save prompts participate in coordinated logout through the session companion. No restart commands, credentials, or bus addresses are stored in the folder snapshot.

The Xsession entry now starts midnightbsd-session, which establishes the session bus and then starts an XSMP manager before launching midnight-wm. For a plain startx/.xinitrc session on MidnightBSD with ConsoleKit installed, use exec ck-launch-session midnightbsd-session so ConsoleKit registers the session before the window manager and its autostart applications begin. A display manager that already registers a ConsoleKit session should launch midnightbsd-session directly. Running midnight-wm directly continues to work without starting a session manager, but a plain .xinitrc must still arrange a ConsoleKit session for graphical Polkit authentication. A nonempty inherited SESSION_MANAGER is preserved, along with its authority configuration, so an existing manager is never replaced. The companion chooses its sibling midnight-wm executable when available, then the configured installation path. midnightbsd-session -- program argument ... can wrap another explicit argument list without shell expansion.

The companion accepts local Unix-domain ICE connections only and uses fresh MIT-MAGIC-COOKIE-1 authentication for ICE and XSMP, with host-based authentication disabled. Its separate private authority file lives in a temporary 0700 directory under the user's private XDG runtime directory (or /tmp when unavailable) and is removed when the companion exits. It does not modify the user's .ICEauthority. It establishes SESSION_MANAGER and ICEAUTHORITY before the WM initializes the keyring and launches XDG autostart applications. An existing reachable D-Bus bus is retained; dbus-run-session owns a new bus when one is needed.

Registered clients receive an initial noninteractive checkpoint. Local/global client checkpoint requests and SIGUSR1 to the companion also request saving; XSMP phase-2 requests are supported. Each checkpoint has a three-second deadline, connections and properties have resource limits, and partial peer reads/writes are bounded in the separate companion process. Applications can checkpoint their own state and supply the restart arguments used on the next login.

Set [Session] save_application_checkpoints=true to persist successful global checkpoints, including requests through SIGUSR1, to $XDG_STATE_HOME/midnight-wm/applications.ini (normally ~/.local/state/midnight-wm/applications.ini). This preference defaults to false, is read for each checkpoint, and is independent of folder saving. Initial and local checkpoints remain memory-only. Confirmed logout takes a final global checkpoint before client shutdown. A normal WM exit outside that flow requests a noninteractive final checkpoint; crashes and termination signals do not save on exit. A request during another save is ignored rather than merging save transactions.

The versioned application snapshot uses a private 0700 directory, a 0600 file, and atomic replacement. Failed or timed-out client saves preserve the previous checkpoint. A timed-out client must reconnect before it can participate in a persisted checkpoint, so a late reply cannot be mistaken for a new save. Malformed, unsupported, or insecure existing files are preserved until explicitly removed. Restart argument bytes and boundaries are retained, including non-UTF-8 filenames, without shell interpretation. Only client IDs, programs, restart argument lists, working directories, and restart styles are stored; environment and discard/shutdown commands are excluded. Restart arguments can contain private document paths, so treat this file as private session data. RestartNever is omitted; disconnected RestartAnyway clients retain their last completed metadata. Other styles require a connected client at checkpoint time; RestartImmediately does not yet trigger an immediate relaunch. Set [Session] restore_applications=true to reopen the last valid application checkpoint through midnightbsd-session. This defaults to false and takes effect at the next login, independently of checkpoint saving and folder restoration. The companion copies a validated checkpoint into its private runtime directory for this login, then the WM launches its applications after establishing the new session bus and keyring services. A running external session manager keeps ownership; Midnight Workspace does not restore its own application snapshot under it. The handoff variables are cleared before starting session services or applications.

Saved clients can reclaim their saved XSMP ID once during the first two minutes of the new companion's lifetime. Unknown, duplicate and expired IDs register as fresh clients. Checkpoint persistence waits until all expected IDs are claimed or that window expires, preserving the source snapshot during startup. Saved commands execute as argument lists with their saved working directories, current session environment and closed internal descriptors. Missing executables, invalid working directories and invalid executable formats are reported without stopping the desktop; executable text without an interpreter is never retried as a shell script. RestartImmediately participates in login restore but does not yet cause an immediate restart after a client exits.

A single successful restore suppresses an eligible XDG autostart entry only when both resolve to one unique direct executable. Failed restores leave autostart eligible. Multiple profiles, multiple restores of the same executable and wrappers are left to normal autostart rather than guessing which application they represent. This conservative matching cannot eliminate duplicates in ambiguous cases. Version 3 application checkpoints retain the version 2 window placement: normal geometry, workspace, maximized axes, fullscreen and shaded state, keyed by XSMP client ID and window role. Version 1 snapshots remain readable without placements; version 2 snapshots retain their placements. Older builds reject version 3 snapshots rather than loading them. The WM reads SM_CLIENT_ID from the window or its WM_CLIENT_LEADER and reads WM_WINDOW_ROLE from the window itself. Missing or malformed identities and ambiguous roles are omitted; a role-less window must be unique for its client. Only windows belonging to successfully checkpointed clients are persisted. Up to 512 placements fit within the existing one-MiB snapshot limit.

The companion requests capture through a private nonblocking inherited socket; the WM replies through a private bounded runtime report, with no XCB dependency in the companion. A 750-ms capture timeout preserves the previous checkpoint, and late replies cannot authorize another request. Normal WM shutdown supplies a final capture before dismantling its windows. Runtime files and descriptors are removed on exit and are not inherited by restored or autostart applications.

New restored windows match by client ID and role once. Identity properties may arrive during the first two seconds after management, within the companion's two-minute restore window. Genuine input on the window cancels pending placement. Normal geometry is recovered into the nearest current work area, excluding panel and frame decorations; maximized/fullscreen state then uses the current monitor. Shading preserves normal client dimensions. Sticky placement and minimized state are not restored, and windows without XSMP identity are not matched by title or class.

Settings → Session also offers Also reopen identified apps without session support, off by default (restore_desktop_applications=false). With application checkpoint saving enabled, this option records installed desktop-entry IDs for managed non-XSMP windows advertising a valid _GTK_APPLICATION_ID. At the next login, both this option and Restore applications at login must be enabled to reopen them. It starts each recognized application once using its current desktop entry through GIO, without copying WM_COMMAND, process arguments, working directories, document paths, window placement, or process state. Multiple windows of the same application collapse into one launch. These apps do not participate in the companion's XSMP save prompts.

The fallback is deliberately limited to visible installed applications with a valid direct executable. Hidden/missing entries, malformed IDs, and windows with an XSMP identity (including a leader identity) are excluded. Relaunch revalidates the registry entry, skips executable identities already represented by XSMP, and omits ambiguous desktop entries sharing one executable. Successful relaunches suppress only a unique autostart entry with the same complete installed command, so wrappers and different profiles sharing an executable remain independent. X11 application IDs are hints, not authenticated process identities; apps lacking a recognized ID are omitted instead of guessing from titles or classes. Registry changes can change which installed entry an ID resolves to. Version 3 snapshots store at most 128 unique desktop-entry IDs within the existing one-MiB private snapshot limit; Clear saved application session clears both kinds of application data.

Confirming Exit X11 session… with midnightbsd-session starts coordinated logout while the desktop continues dispatching input and drawing. Participating applications receive an interactive XSMP save request, with one application allowed to show its save prompt at a time. Cancelling an application's prompt, a failed save, a disconnected client, or a save timeout cancels logout without sending Die; the previous application checkpoint is preserved. The panel shows a notice when logout is waiting or cancelled. Outstanding cancelled saves must settle before another attempt; a timed-out client must reconnect so late replies cannot authorize a later shutdown.

Ordinary application saves have a three-second deadline. Prompt requests queue within a sixty-second overall logout deadline; exceeding it cancels logout. After every participating client saves successfully, the companion captures window placement and, when application checkpoint saving is enabled, writes the final snapshot before sending Die. Capture or snapshot-write failure cancels logout. It waits up to three seconds for clients to disconnect, then lets the WM save its built-in folders and end the desktop. The companion does not signal clients ignoring Die; see the session process cleanup below. Disabling application checkpoint saving still allows save prompts and orderly logout, without replacing the saved application session.

On MidnightBSD the WM is the reaper for the processes it starts: applications launched from the desktop, XDG autostart entries, and anything they leave running in the background. Exited orphans are reaped while the desktop runs. When the WM exits, it sends SIGTERM to every remaining descendant, waits up to three seconds, and then sends SIGKILL, so nothing keeps a stale display, session bus, or runtime directory after logout. Set MIDNIGHT_KEEP_SESSION_PROCESSES=1 in the session environment (for example in .xinitrc) to let tmux, screen, and nohup jobs survive logout instead.

Only the WM's confirmed exit action initiates this flow; application requests to end the desktop remain ignored. Standalone WMs and sessions under an existing external manager retain their previous exit behavior. Crashes and termination signals do not initiate interactive shutdown. The companion watches the WM it launched, propagates that child's exit status, and removes its owned sockets and authority file. A termination signal is forwarded only to its owned child, with a bounded wait; registered applications are not signalled.

The separate XSMP metadata adapter and display-independent application/window model follow the X.Org SMlib property types, with the adapter preserving restart argument boundaries, bounding properties and argument data, handling property deletion and restart-style hints, and excluding environment and discard/shutdown commands from restart metadata. The manager separately retains bounded protocol properties in memory for GetProperties, including unknown properties; these are not written to a checkpoint file. Placement matching requires an unambiguous session client ID and window role. xsmp_properties_test exercises the adapter and window matching in Release builds, including malformed properties and transactional rejection. python3 tests/xsmp_smoke.py exercises real libSM clients, authentication failure, initial/local/global checkpoints, phase-2 saves, unknown properties, deletion, malformed updates, unresponsive clients, partial pre-auth frames, disconnections, inherited managers, bus bootstrapping, argument boundaries, lifecycle cleanup, and opt-in checkpoint persistence with failure/timeout preservation. coordinated_logout_smoke checks interactive cancellation, save failures/timeouts, serialized prompts, responsive workspace switching, checkpoint preservation/write failures, successful phase-2 shutdown, and bounded client exit. application_checkpoint_test covers snapshot validation, exact argument round trips, privacy, malformed-state preservation and interrupted writes. The transport test is registered with CTest when Python 3 and dbus-run-session are available. Run python3 tests/session_smoke.py --binary build/midnightbsd-session to check the real WM lifecycle through the companion, including an XSMP autostart client that verifies the session bus and inherited agent before registering. python3 tests/application_restore_smoke.py tests independent logins with a real XSMP client, saved-ID adoption, autostart deduplication, new bus/agent inheritance, literal arguments, disabled restore, corrupt-state preservation and cleanup. Add --placements for window geometry/workspace/state checks, duplicate and malformed roles, stalled-WM preservation, final shutdown capture and offscreen recovery. Add --matrix to repeat those checks at all five supported resolutions. Add --changed-resolution-matrix to save on a real 3840×2160 Xvfb screen, restart the isolated X server, and restore onto each of the five supported sizes. This checks recovery into the new work area and scale, including normal geometry behind shading, maximization and fullscreen. The default CTest changed-resolution case restores 4K sessions at 1280×720. These are actual screen sizes across logins, not synthetic root resize events; they do not prove live RandR hotplug or offset multi-monitor behavior. See session validation. python3 tests/session_randr_smoke.py --module-path /path/to/private/modules uses a private Xorg dummy 0.4.x server for genuine RandR primary-output changes, offsets, gaps, output disable/re-enable, and restoration with a missing output. See the session validation guide for driver setup and optional CTest registration. application_restore_test checks exact argument bytes, working directories, spawn failures, descriptor/signal isolation and rejection of shell fallback.

Run python3 tests/session_smoke.py --matrix for isolated save/restore cycles at all five supported resolutions, including cancelled logout, window states, missing folders, offscreen geometry recovery, fresh startup, corrupt state, and clearing through Settings. session_test covers parsing, privacy, atomic replacement, interrupted writes, and monitor recovery without X11.

Middle-click an application's title bar to shade it to the title bar, and middle-click again to expand it. The application remains mapped at its original size; shading does not minimize it. Task activation, Alt+Tab selection, maximize, and fullscreen expand shaded windows. EWMH clients can also request _NET_WM_STATE_SHADED; allowed actions reflect whether shading and resizing are currently available.

An external pager can set _NET_DESKTOP_LAYOUT to describe its workspace grid. Ctrl+Alt+Left/Right/Up/Down follows that grid's physical directions, including orientation and starting corner, wrapping within rows or columns and skipping empty cells. Layout updates apply immediately. Missing or malformed layouts use the default four horizontal workspaces; the WM does not overwrite the pager's layout property.

EWMH activation requests use interaction timestamps to reject stale background focus requests. _NET_WM_USER_TIME=0 prevents initial focus; user-time helper windows are supported. Clients without an initial user-time hint retain legacy mapping behavior. Explicit taskbar/pager activation still restores a window and switches to its workspace. This is desktop focus policy, not isolation between X11 clients.

Applications requesting attention through EWMH or the ICCCM urgency hint get an amber task outline and ! marker without being focused. Overflow tasks also carry the marker. Activating the window clears attention and urgency. The WM publishes the read-only focused state and each window's allowed actions. ABOVE and BELOW requests are mutually exclusive and preserve stacking layers when focus changes; modal transients remain above their parent. Focused fullscreen families stay above ordinary windows and docks. SKIP_PAGER is supported independently of SKIP_TASKBAR.

Pagers can restack managed windows with _NET_RESTACK_WINDOW without changing focus; desktop layers and transient ordering still apply. Applications can request fullscreen across selected monitors with _NET_WM_FULLSCREEN_MONITORS. Its four indices follow Xinerama ordering (top, bottom, left, right); servers without active Xinerama expose the root screen as index zero. Requests apply on fullscreen entry or immediately while fullscreen. Invalid indices or empty rectangles are ignored. Monitor configuration changes clear the selection and return windows to ordinary single-monitor fullscreen; applications can then request a new selection.

Optional portal integration uses deskutils/xdg-desktop-portal and x11/xdg-desktop-portal-gtk. The installed MidnightWorkspace portal configuration selects GTK for file/application choosers and Midnight's Settings backend for live dark-mode and accent-color preferences. User portal configuration takes precedence. This adds chooser and appearance integration; screen sharing and remote desktop require additional backend work.

When no other service owns org.freedesktop.ScreenSaver, Midnight handles Inhibit/UnInhibit requests to suppress idle blanking and coordinates with xscreensaver. Inhibitors are removed when their application disconnects. Explicit screen locking remains available while inhibited.

Double-click a desktop or folder object to open it. Right-click to see its actions. Files use their shared MIME type for themed icons. Open With… lets you choose an application and optionally save it as the default for that file type. Images use the shared $XDG_CACHE_HOME/thumbnails/normal preview cache. An application .desktop file placed directly on the Desktop can launch when it is owned by the current user and marked executable. Other .desktop files cannot launch by double-clicking. Folder windows support keyboard copy, cut, and paste. The shell uses the standard X11 CLIPBOARD selection, and file copy/paste uses text/uri-list plus x-special/gnome-copied-files for other file managers. Folder windows have vertical scrollbars: use the arrows, click the track to move a page, or drag the thumb. The mouse wheel and Page Up, Page Down, Home, and End keys also scroll. Other applications draw and control their own scrollbars. In a folder window, File opens the selected item, creates a folder, shows properties, moves an item to Trash, or closes the window. Edit offers copy, cut, and paste. View switches between the icon grid and a list with Name, Size, Type, and Modified columns. Ctrl+1 selects the grid; Ctrl+2 selects the list. List columns hide progressively in narrow windows to keep filenames readable. Use View to sort A–Z, Z–A, last modified (newest first), first modified (oldest first), size (largest first), or type. Folders stay first in each order; unknown sizes or modification times sort after known values. Size sorting uses logical file lengths, without recursively measuring each subfolder. Click list column headers to sort; Name and Modified toggle direction. Selection follows the same item across sorting, refresh, and view changes. Arrow keys navigate items, Enter opens the selection, and scrolling works in either view. Each new folder starts in grid view with A–Z sorting; View → Refresh updates its cached metadata and contents. The bottom status bar keeps the object count on the left and the contents' size on the right. With an item selected it shows only that item's size; selecting a folder measures that folder's contents. Click empty space to return to the total. Sizes use humanize_number with binary IEC units (KiB, MiB, GiB), and represent logical file lengths, including nested contents, rather than allocated blocks. Symbolic links contribute their own length and are not followed; special files contribute no bytes. Calculation runs in the background, showing Calculating… while pending. Unreadable entries or excessive nesting produce a (partial) label; an inaccessible target shows Size unavailable. Directory changes and View → Refresh recalculate the size, and completed results are resampled every 30 seconds to pick up changes inside nested folders. On a session D-Bus, Midnight also offers org.freedesktop.FileManager1, so applications can open folders, reveal selected files, and show file properties. The Midnight Workspace Files application can be selected as the default folder handler in Settings. Its midnightbsd-open-folder launcher sends local paths or file URIs to the running workspace, opening built-in folder windows without starting another window manager. The launcher also works if another file manager owns the shared org.freedesktop.FileManager1 name.

The Home, Downloads, Documents, Pictures, Trash, and Templates shortcuts appear on the desktop by default. Downloads, Documents, Pictures, and Templates use their configured XDG user directories, falling back to the matching folder under the home directory when unset. Music, Videos, and Public Share are available as optional shortcuts. An XDG directory set to the home directory is hidden, as that setting disables the special directory. Physical files appear from the user's XDG Desktop directory. Shell object Icons fill downward from the upper left, then continue in the next column. Overflow scrolls by columns using the wheel or Page Up/Page Down/Home/End. Object metadata is stored in $XDG_DATA_HOME/midnight-wm/workspace.db (normally under ~/.local/share). Files and folders remain in the filesystem. Deleting a file uses the freedesktop Trash mechanism. In an object's Properties dialog, double-click Name or Target to select its text. Use Choose... beside Icon to browse previews from the selected icon theme, search by name, and choose an icon. Default restores the built-in folder or file icon. Existing image paths continue to display.

Drag files between folder windows, the desktop, and other XDND-aware file managers. Drag desktop files or folders onto Trash to move them to recoverable Trash, or onto a folder icon to move them into that folder. Hold Ctrl when starting a drag to copy instead. A preview follows the pointer with the item icon, name, and Move or Copy label. Built-in desktop shortcuts remain in place. The Trash window offers Empty Trash… in its File and right-click menus; confirming permanently deletes all items in Trash. Clipboard and drag operations support file URIs; text selection uses standard X11 selection targets, including incremental transfers for large text. The workspace keeps a text or file clipboard snapshot when its original owner exits. The context menu provides object properties, shadows, templates, and Trash restore actions. Copying or moving files runs in the background.

Open Settings… from the Midnight menu, or run midnightbsd-settings, to change wallpaper, colors, fonts, scaling, panel text, clock format, and desktop shortcuts. Apply saves your preferences and the running window manager updates automatically within about two seconds. Closing without applying discards pending edits. The settings app preserves unrelated INI keys and reports save errors. The Application defaults page selects installed handlers for web links, HTML files (including web page editors), email links, calendar files, folders, text, PNG/JPEG images, and PDFs. It also selects the terminal opened by the panel button. These choices are saved in the user XDG MIME association files and the desktop's xdg-terminals.list preference; they do not require a change to midnight-wm/config.ini. The Startup applications page lists the effective XDG autostart entries, including entries disabled for this desktop. Toggle an available entry to start or skip it at the next login. Disabling a system entry writes a user override under $XDG_CONFIG_HOME/autostart and leaves the system file intact. Add a named desktop entry command, or remove a user entry after confirmation. These changes save immediately and take effect at the next login; the other Settings pages continue to use Apply.

Run midnightbsd-system-monitor, choose System Monitor from the Midnight launcher below Mport Manager, or open it from Programs. Its four tabs list processes; graph CPU, memory, and network activity; show mounted file systems with capacity and available space; and summarize the CPU, physical memory, swap allocation, OS release, and physical drives. Process and resource data refresh every two seconds; mounts refresh every ten seconds. Select a process and choose End Process (SIGTERM) or Force Quit (SIGKILL) from the buttons or the right-click menu; each asks for confirmation and verifies the PID still names the selected process before signalling it. The Hardware tab has a Refresh button for changes to swap or attached drives.

To edit preferences by hand, copy share/midnight-wm/config.ini to $XDG_CONFIG_HOME/midnight-wm/config.ini (normally ~/.config/midnight-wm/config.ini) to change the panel label, clock format, workspace appearance, or desktop shortcuts. In its [Workspace] section, dark_mode defaults to false and selects the dark shell preset when set to true. It applies to the shell, window frames, notifications, and D-Bus menus. It also publishes the portal dark preference and selects Adwaita-dark for GTK X11 apps through XSETTINGS. Disabling it restores gtk-theme-name from gtk-3.0/settings.ini, then the GNOME gtk-theme setting, or Adwaita as a fallback. No GTK configuration files are modified. An existing XSETTINGS manager remains in control, and applications can override system appearance.

At session startup, QT_QPA_PLATFORMTHEME defaults to gtk3 so Qt applications can follow the same GTK theme and live dark-mode changes. Explicit environment overrides (including an empty value) are preserved. The Qt GTK platform-theme plugin must be installed; MidnightBSD's qt6-base includes it. Already running apps need restarting once to pick up the platform-theme selection. Apps with custom palettes or styles may override the system appearance.

Run python3 tests/gtk_theme_smoke.py (requires PyGObject for GTK 3) to check initial dark appearance, live GTK theme switching, and restoration of user theme preferences in an isolated Xvfb session. Run python3 tests/qt_theme_smoke.py with Qt 6 development files installed to check autostart and D-Bus activation inheritance, explicit overrides, and live Qt palette changes through both session entry points.

ui_font and title_font accept Pango family/style descriptions, optionally followed by a point size from 6 to 32. Omitting the size keeps each UI element's default size. desktop_color remains a #RRGGBB desktop background in either mode; panel_color optionally overrides the panel color, and accent_color sets the accent color. The shared ui_scale override is also configured here. Optional window_border_style=two-color draws two nested outlines around managed windows and built-in folders. window_border_outer_color (default #202020) and window_border_inner_color (default #ffffff) set their colors. The default style is classic. These options are available in Settings under Appearance, apply live, and preserve frame sizes and resize areas. By default the desktop shows mnbsd_bg_purple.png from the midnightbsd-backgrounds package over the lavender desktop_color; if that image is not installed, only the color is shown. Set desktop_image to an absolute path, ~/... path, or path relative to this config file to use another wallpaper. If a relative path is not found there, lookup searches the user XDG data backgrounds directory, then system XDG data backgrounds/midnightbsd and backgrounds directories, and the installation prefix share/backgrounds/midnightbsd. The optional midnightbsd-backgrounds port installs into /usr/local/share/backgrounds/midnightbsd, so a filename such as desktop_image=mnbsd_bg_purple.png works directly. PNG, JPEG, GIF, and SVG images are supported through GdkPixbuf; GIF uses its first frame. The wallpaper repeats independently on each monitor. desktop_image_mode can be fill (the default, centered crop) or fit (the whole image centered with desktop_color showing around it). desktop_color also appears if the wallpaper is unset or unreadable and behind transparent parts of an image. Set desktop_image= (empty) to show only desktop_color. Saved changes are reloaded automatically; malformed INI files leave the current settings active. In the [Desktop] section, show_documents and show_pictures default to true; show_music, show_videos, and show_public_share default to false. Set any of these to true or false to show or hide that shortcut. Changes apply automatically after editing the file. Existing shortcut names, icons, and positions remain in the workspace database when a shortcut is hidden.

At startup, Midnight Workspace launches eligible .desktop files from the user and system XDG autostart directories. A user entry takes precedence over a system entry with the same filename. Hidden, OnlyShowIn, NotShowIn, and TryExec are respected. Direct .xinitrc sessions identify themselves as MidnightWorkspace through XDG_CURRENT_DESKTOP when it is not already set.

Alt+Tab switches tasks, and Alt+F4 closes the active window. The title bar provides minimize, maximize, and close buttons; drag the title bar to move a window and its lower frame to resize it. The launcher menu has Exit X11 session…, which asks for confirmation before closing the window manager. When started as the Xsession or from .xinitrc, that also ends the X11 session. X11 clients can supply ICCCM size, focus, and transient-window hints. The window manager also handles EWMH fullscreen, maximize, hidden, skip-taskbar, frame-extents, and application move/resize requests. Interactive move/resize supports pointer drags or arrow keys, with Escape to cancel. The desktop sets an explicit pointer cursor as soon as the window manager starts. The default silver panel follows the OS/2 Warp 4 references, with a lavender desktop. Existing user configuration overrides those defaults. The clickable launcher button uses the MidnightBSD logo from the MidnightBSD website art collection.

The panel network button sits beside the battery indicator and shows Wi-Fi, Ethernet (including unknown link types), or a disconnected cable. Basic status refreshes every 30 seconds without connectivity probes. Click it for active interfaces, IP addresses, observed connection duration, and total received and transmitted bytes. Wi-Fi also shows SSID, negotiated transmit link speed, and 802.11 standard when the driver exposes them. Details refresh every two seconds only while the popup is open; close it with Escape or an outside click. Scroll with the mouse wheel or arrow/Page keys for long interface lists. Connection durations begin when the workspace first observes a link; counters are the interface's totals, not traffic measured since opening the popup. Active lagg members determine whether an aggregated connection is shown as wired or Wi-Fi. When independent wired and wireless links are both active, the panel prefers the wired icon; the popup still lists both.

Design

The shell object model, file operations, and presentation code are separate from X11 window management and selection handling. This keeps the shell available for a later Wayland compositor backend. Wayland will require a new compositor implementation; XCB window IDs and events do not cross that boundary.

The experimental MidnightBSD mport is in packaging/mports/x11-wm/midnight-wm/ and tracks the published 0.1.6 source archive. Unreleased source changes may require additional installed files or dependencies reflected in the bundled port. Generate source distributions with cpack --config build/CPackSourceConfig.cmake -G TGZ.

The magnifying glass beside the panel clock opens Search Files. Enter a file name or path and press Enter or Find to show the first 20 case-insensitive literal substring matches from MidnightBSD's locate database, in database order. Click a result to open it with its default application. Close dismisses the window. Results reflect the system database's last update, so recently created files may be missing and deleted files may still appear. An unavailable database or failed file launch is reported in the search window.

About

Warp-inspired X11 workspace and window manager for MidnightBSD

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages