-
Notifications
You must be signed in to change notification settings - Fork 41
example window lifecycle
The shell fires a hook at every meaningful window state change — open, focus, minimize, maximize, drag-end, close, detach, fullscreen. Plugins can subscribe to any of them to drive their own UI or send analytics.
Every event goes through window.wp.hooks (the @wordpress/hooks API). The shell aliases it at wp.os.hooks for convenience; either works. All window actions include at minimum { windowId: string }; the richer payloads are documented in javascript-reference.md.
// my-plugin.js
( function () {
// whenReady fires immediately if the shell has already booted, or
// subscribes to `os.init` otherwise. Either way, your
// subscribers land after `window.wp.os` is populated.
wp.os.whenReady( function () {
wp.os.hooks.addAction(
'os.window.opened',
'my-plugin/track-open',
function ( payload ) {
// payload: { windowId, page, title, url }
console.log( 'Opened', payload.title, '→', payload.url );
}
);
wp.os.hooks.addAction(
'os.window.closed',
'my-plugin/track-close',
function ( payload ) {
// payload: { windowId }
console.log( 'Closed', payload.windowId );
}
);
} );
} )();Use the HOOKS enum so a renamed hook fails at typecheck instead of silently disconnecting:
import { HOOKS } from 'openstation';
wp.os.whenReady( () => {
wp.os.hooks.addAction(
HOOKS.WINDOW_MAXIMIZED,
'my-plugin/maximize-fanfare',
( e: { windowId: string } ) => {
console.log( 'Maximized', e.windowId );
}
);
} );| Event | Payload | When |
|---|---|---|
os.window.opened |
{ windowId, page, title, url } |
After mount, before the opening animation completes |
os.window.focused |
{ windowId } |
Every focus change (click, keyboard, iframe bridge) |
os.window.closed |
{ windowId } |
After the close animation starts |
os.window.minimized |
{ windowId } |
User clicks minimize or hits a dock shortcut |
os.window.restored |
{ windowId } |
From minimized back to whichever state preceded the minimize (maximized / fullscreen / snapped / normal) |
os.window.maximized |
{ windowId } |
Full desktop-area fill |
os.window.unmaximized |
{ windowId } |
Back to floating (e.g. drag-restore) |
os.window.fullscreen-entered |
{ windowId } |
Covers the entire viewport |
os.window.fullscreen-exited |
{ windowId } |
Back to whichever state preceded |
os.window.moved |
{ windowId, x, y } |
Fires with drag-end
|
os.window.resized |
{ windowId, width, height } |
Fires with resize-end
|
os.window.title-changed |
{ windowId, title } |
Iframe-sourced title updates |
os.window.detached |
{ windowId, url } |
Open-in-new-tab via the detach button |
os.window.restored is the only action that fires when a window comes back from minimized. Even if the window was maximized / fullscreen / snapped at the moment it was minimized — and therefore returns to that same state on restore — os.window.maximized / os.window.fullscreen-entered / etc. do not re-fire. From the framework's perspective the window never left those states; minimize only hid it.
If your subscriber cares about "the window is now visible AND in state X," combine the events:
wp.os.hooks.addAction(
'os.window.restored',
'my-plugin/visible-in-state-x',
( { windowId } ) => {
const win = wp.os.windowManager.getById( windowId );
if ( win?.isMaximized() ) {
// Treat this like a fresh maximize for your UI purposes.
}
}
);@wordpress/hooks subscribers stay registered until the page unloads or you explicitly remove them:
wp.os.hooks.removeAction(
'os.window.opened',
'my-plugin/track-open'
);- JavaScript reference: window lifecycle — full payload shapes.
- Dock badges react to window counts — worked example using these events.
This wiki is generated from the docs/ directory — edits made here are overwritten by the next sync.
To change a page, open a pull request against docs/.
Guides
- Development guide
- Releasing openstation
- Agents security model
- API Index
- Architecture
- Bridge protocol — wiring overview
- <os-*> component reference
- Native Desktop Host — Experimental
- Desktop themes
- Dock customization — two registries, one mental model
- The event-driven framework
- Files on the Desktop
- Folder sharing
- Getting Started
- Hooks Reference
- Icons
- JavaScript Reference
- The Living Tree — algorithm definition
- Mio
- Native Windows & Framework Interop
- Plugin compatibility layer
- Progressive Web App (PWA)
- Station Home
- Using openstation from your own plugin
Migration notes
- Migration: built-in activity channels move to the os/ namespace
- Migration: window, wallpaper and widget bundles load on demand
- Migration — the navigation model
- Migration: a native window's tabs move to the window chrome
All examples
- AI Agents — extend and invoke from a plugin
- wp.os.ai.ask() — programmatic AI Copilot
- Tune the AI model config
- Custom arrange-menu action
- Open a child window its owner can't cover
- Style a specific admin page inside the iframe
- Code Blue — register your plugin's log file
- Open a file in the Code editor (deep-link from any window)
- Connect to a window — title-bar button + iframe pub/sub
- Content changes — live-refresh every window listing your type
- Custom window chrome (Experimental)
- Register a custom unfocused-window effect
- Example: render a data table
- Real file storage — react to uploads, gate policy, share from PHP
- React to a window being set free onto the real desktop
- Cross-window devtools — instrumentation primitives
- Add a dock item with a badge
- Decorate the dock without forking the renderer
- Replace the dock rail entirely
- Retune the Drafts widget's AI writing assistant
- Gate OpenStation by role
- Iframe-initiated window opens
- Build a feed reader without the bookkeeping
- Inject data into openStationConfig
- Render a list without losing clicks — renderKeyedList()
- Example: layout primitives (body → panel → row → col)
- Use <os-*> components from a plugin that ships as a zip
- Restyle and drive Mio
- Add an action that works on a whole selection
- WP Explorer — custom post types and their folder
- Add an action button to a WP Explorer preview pane
- Example: native Posts window
- Example: native window with tabs
- Native windows
- Customize note → post conversion
- Send a notification
- OAuth relay — connect to an external service
- OS-file drop
- <os-flyout> — window-scoped sliding card
- Plugins window — extras
- Track who's around — wp.os.presence
- Example: progress bar
- PWA install — surface your own button
- React to window events
- Example: extend the Trash
- Register a slash-command
- Register a desktop theme from a plugin
- Register a game
- Example: register a desktop icon (Jorvy)
- Register a wallpaper
- Register a widget
- Related entities — extend the title bar's "Related" menu
- The native-window render ctx
- Programmatic folder sharing
- Share state across multi-bundle plugins — wp.os.createSharedStore()
- Example: loading spinner
- Add an opt-in card to Station Home
- Accept drops on your desktop icon
- Give a tile two icons, one per state
- Add a row to a window's ⋯ menu
- Example: window activity & the status ring
- Window controls
- Subscribe to window lifecycle events
- Window links — relate windows and restyle the ties (Experimental)
- Window loading state — spinner overlay & ready signal
- Show a banner at the top of a window
- Pulse a window's icon — Window.requestAttention()
- Register a custom window reveal
- Window slots
- Window themes
- Native window with bundle-bound config