Omarchy Bar Widget Panels Lifecycle: Summon, Hide, and Toggle Mechanisms
The Omarchy bar widget panels follow a strict three-phase lifecycle where pickPanelSlot() selects the correct monitor instance before delegating to summonPanel(), hidePanel(), or togglePanel() methods in the QML layer.
The Omarchy desktop environment builds its status bar per-monitor using Quickshell, creating independent instances of widget panels like network, clock, and battery for each display. Understanding the lifecycle for summoning, hiding, and toggling Omarchy bar widget panels is essential for customizing interactions and debugging panel behavior. This architecture ensures that panel commands always target the correct visual instance based on current focus and visibility state.
How Panel Instances Are Managed Per Monitor
Omarchy instantiates widget panels as QML components once for every monitor that hosts a bar. When you trigger a panel action, the system must first identify which of these duplicate instances should receive the command.
The Panel Slot Selection Algorithm
Before any visibility change occurs, BarModel.js executes the pickPanelSlot() function to determine the target instance. The selection logic in shell/plugins/bar/BarModel.js (lines 61-78) follows this priority:
- Opened copy wins – If the panel is currently visible on any monitor, that instance receives the command
- Focused monitor fallback – If no copy is open, the instance on the currently focused monitor is selected
- First available fallback – If the focused monitor lacks a bar, the first available copy is used
This guarantees that user interactions consistently affect the panel the user is actually viewing or the one most relevant to their current workspace.
The Core Lifecycle Actions
Once the target slot is identified, the Bar model forwards the request to the QML layer in shell/plugins/bar/Bar.qml (lines 745-770), which exposes three public methods controlling the lifecycle:
Summoning a Panel
The summonPanel(id) method makes a widget panel visible or expands its popup. According to the implementation in Bar.qml, this method sets the panel's visible property to true and optionally shifts focus to the widget. If the panel is already visible, the call is a no-op, preventing redundant animations or state flicker.
Hiding a Panel
Conversely, hidePanel(id) collapses the panel or hides its popup entirely. The method first checks the current visibility state in isPanelVisible(id) and only modifies the DOM when necessary. This conditional check prevents unnecessary layout recalculations when the panel is already hidden.
Toggling Visibility
The togglePanel(id) method provides a single-command interface that internally branches:
if (panelIsVisible(id)) {
hidePanel(id);
} else {
summonPanel(id);
}
This ensures atomic toggle behavior without race conditions, as the visibility check and state transition occur within the same execution context.
Inline Settings Updates Without Rebuilding
When widget configuration changes—such as toggling battery percentage display—the lifecycle avoids full panel reconstruction. The inlineSettingsDelta() function in BarModel.js (lines 68-102) computes a minimal property delta that applies directly to the existing QML instance. This optimization maintains panel state (scroll position, focus) while updating visual elements, eliminating the flicker associated with destroying and recreating components.
CLI and Programmatic Usage
You can trigger these lifecycle methods through generated CLI commands or direct programmatic access.
Shell Commands
# Summon the network panel on the focused monitor
omarchy-toggle-panel network
# Explicitly hide the battery panel instance currently visible
omarchy-hide-panel battery
# Toggle the clock panel visibility
omarchy-toggle-panel clock
QML Programmatic Access
For custom scripts or widget interactions, access the Bar model directly:
// Select the appropriate slot for the current screen context
BarModel.pickPanelSlot(BarModel.candidateSlots(), Shell.currentScreen())
.then(slot => slot.summonPanel("network"));
This pattern mirrors the internal CLI implementation, first resolving the correct monitor instance before invoking the lifecycle method.
Summary
- Instance selection precedes all actions via
pickPanelSlot()inshell/plugins/bar/BarModel.js, prioritizing opened copies over focused monitors - Summon operations use
summonPanel(id)inshell/plugins/bar/Bar.qmlto set visibility flags and handle focus - Hide operations leverage
hidePanel(id)with pre-checks to avoid unnecessary state changes - Toggle combines visibility checks and conditional calls to provide atomic state switching
- Settings updates use
inlineSettingsDelta()to modify panels without destroying their QML instances, preserving user context and preventing flicker
Frequently Asked Questions
How does Omarchy decide which monitor displays a summoned panel?
The system calls pickPanelSlot() which first checks for any panel copy already opened (visible) on any monitor. If found, that instance receives the command. If no panel is currently open, Omarchy selects the copy attached to the monitor with current user focus, falling back to the first available bar if the focused screen lacks one.
What happens if I call toggle on a panel that is already animating?
The togglePanel(id) method checks current visibility state atomically before deciding to summon or hide. If the panel is mid-animation but technically visible, it will trigger hidePanel(); if hidden, it triggers summonPanel(). The underlying QML engine queues these state changes, preventing conflicting transitions.
Can I summon a panel on a specific monitor regardless of focus?
Direct specification requires accessing the candidateSlots() array and selecting a specific index rather than using the automatic picker. The default CLI commands (omarchy-toggle-panel) always route through pickPanelSlot(), which respects the opened-then-focused priority order defined in BarModel.js.
Why don't panel settings changes reset my scroll position or selected items?
Omarchy uses inlineSettingsDelta() to compute minimal property changes rather than destroying and reinstantiating QML components. This preserves transient UI state like scroll position, text selection, and focus because the underlying QML object persists while only specific bound properties update.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →