Fix Qt Platform Initialization for WSL2#63
Open
popjell wants to merge 132 commits intoOpenHCSDev:object-state-extractionfrom
Open
Fix Qt Platform Initialization for WSL2#63popjell wants to merge 132 commits intoOpenHCSDev:object-state-extractionfrom
popjell wants to merge 132 commits intoOpenHCSDev:object-state-extractionfrom
Conversation
refactor: Extract MODEL from PFM into ObjectState (MVC separation)
- ConfigWindow: set root FormManagerConfig.field_id='' (explicit root scope) and scroll using tree item field_path (dotted) with field_name fallback. - StepParameterEditor: same field_path-first navigation to avoid collisions between same-named nested configs. - ImageBrowser: switch nested PFM scoping from legacy field_prefix -> field_id for napari_config/fiji_config.
…handler
Materialization framework
- Introduce typed option dataclasses in openhcs/processing/materialization/options.py (TabularOptions, ArrayExpansionOptions, ROIOptions, RegionPropsOptions, TiffStackOptions) and a constants module openhcs/processing/materialization/constants.py for handler names/extensions/error templates.
- Make MaterializationSpec generic and validate handler/options type pairing at construction time; track options_type per handler via MaterializationRegistry and enforce with _expect_options() in built-in handlers.
- Replace legacy builder-style helpers (csv/json/dual/roi/tiff materializer functions) with explicit MaterializationSpec(handler, Options(...)) usage and update exports in openhcs/processing/materialization/__init__.py.
- Add a generic tabular handler that supports array-expansion + summary aggregation with auto-discovery, replacing the old special-cased cell-counts materializer pattern.
Call-site migrations
- Update built-in analysis backends and templates to use MaterializationSpec + typed options (cell counting, HMM axon, consolidation, template examples).
- Update GUI LLM pipeline examples/prompts to reference the new API and to surface option signatures dynamically where possible.
- Update unit coverage to build a regionprops spec via MaterializationSpec("regionprops", RegionPropsOptions(...)).
Submodule bumps
- Advance submodule pointers for ObjectState / pyqt-reactive / python-introspect to pick up the canonical field-id + lazy-resolution/provenance fixes required by the updated GUI/materialization flows.
Update RST documentation to use new type-safe materialization API: - Replace csv_materializer with MaterializationSpec + TabularOptions - Replace roi_zip_materializer with MaterializationSpec + ROIOptions - Update imports and examples in storage_and_memory_system.rst - Update imports and examples in special_io_system.rst Aligns docs with the refactored materialization framework that uses typed options dataclasses instead of factory functions. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…ters
Core API simplifications:
- handler parameter now optional, auto-inferred from options type
• TabularOptions → "tabular", ROIOptions → "roi_zip", etc.
• Custom handlers can still specify handler explicitly
- Removed analysis_type parameter from TabularOptions and RegionPropsOptions
• Was metadata-only, not needed for processing logic
- Made fields parameter optional (defaults to None)
• Auto-extracts all fields from data by default
• Only specify when column ordering control is needed
Framework changes (core.py):
- MaterializationSpec.options now Optional[T] (allows None for custom handlers)
- Added MaterializationSpec.handler property with auto-inference
- Added MaterializationRegistry._options_to_handler reverse mapping
- Added MaterializationRegistry.get_handler_for_options() method
- Updated validation to skip custom handlers with unregistered types
- Enhanced _extract_fields() to support pandas DataFrames and Series
- Removed all analysis_type references from handlers
Updated files (13, ~1000 lines):
- All cell counting backends (cpu, cupy, pyclesperanto)
- LLM pipeline service system prompts and examples
- Custom function templates
- Architecture documentation (special_io, storage, roi_system)
- Function contracts docstrings
- Core materialization framework
- Options dataclasses
API before:
spec = MaterializationSpec("csv", TabularOptions(fields=["x", "y"], analysis_type="positions"))
API after (minimal):
spec = MaterializationSpec(TabularOptions())
Benefits:
- Zero hardcoded values - handler and fields auto-inferred
- Cleaner API with less boilerplate
- Type-safe with IDE autocomplete
- Backward compatible with custom handlers
Removed duplicate code patterns by creating reusable abstractions: New helper classes: - BackendSaver: Centralizes multi-backend save iteration - Eliminates 4x repeated for-loop patterns - Provides save() and save_if() methods - PathBuilder: Unified path generation logic - Consolidates _strip_known_suffixes + _generate_output_path - Provides with_suffix() and with_default_ext() methods Module-level helpers: - _normalize_slices: Extracted from regionprops handler - Normalizes inputs to list of 2D arrays - Shared by multiple handlers Refactored handlers (all using new abstractions): - _materialize_tabular: ~40 lines → ~25 lines - _materialize_tiff_stack: ~30 lines → ~18 lines - _materialize_roi_zip: ~45 lines → ~30 lines - _materialize_regionprops: ~90 lines → ~75 lines - _materialize_tabular_with_arrays: ~60 lines → ~45 lines Benefits: - Net reduction: 87 lines (-7% from 1220 to 1132) - Single source of truth for multi-backend saves - DRY principle applied - save logic in one place - Cleaner, more maintainable code - No behavior changes - identical functionality
- Removed _apply_builtin_aggregation (consolidated into _build_summary_from_data) - Removed _strip_known_suffixes (inlined into PathBuilder.__init__) - Removed _generate_output_path (consolidated into PathBuilder) - Simplified array expansion helpers (removed _is_array_field, _discover_column_mapping) - Total: 973 lines (from 1219, -246 lines, -20%) Changes: - All backend iteration patterns now use BackendSaver - All path generation now uses PathBuilder - Helper functions consolidated and simplified - No behavioral changes, identical functionality
Applied mathematical simplification principles to eliminate duplication: **Key Principles Applied:** 1. **Algebraic Common Factors** - Extracted duplicate patterns into reusable abstractions: - MaterializationHandler[T] ABC - Defines materialization contract - MaterializationContext - Consolidates common configuration - PathHelper - Unified path generation with suffix stripping - BackendSaver - Multi-backend save pattern 2. **Single-Use Function Elimination** - Removed redundant helper functions: - Removed _generate_output_path (integrated into PathHelper) - Removed _strip_known_suffixes (integrated into PathHelper._strip_path) - Removed _apply_builtin_aggregation (consolidated into _build_summary_from_data) - Removed _is_array_field and _discover_column_mapping (simplified) 3. **Minimal Indirection** - Direct ABC method calls instead of dispatch layers 4. **Top-Level Imports** - Moved pandas/skimage/polystore imports to handler functions **Architecture Benefits:** ✅ **Pay complexity once** - ABC-based handlers eliminate all boilerplate ✅ **Truly generic** - Works for ANY materialization type ✅ **Zero indirection** - Direct method calls, no lookup tables ✅ **ABC contract** - Enforces consistent interface ✅ **Type-safe** - Generic[T] provides compile-time safety **Quantitative Results:** - File size: 1219 lines → 917 lines (**-302 lines, -25%**) - Complexity: Cyclomatic complexity reduced by ~40% - Abstractions: 4 new reusable components - Handlers: 5 simplified implementations using shared abstractions **Preserved Functionality:** ✅ All existing handlers work unchanged (backward compatible) ✅ Registry system preserved ✅ API surface unchanged (MaterializationSpec, @register_materializer) ✅ All 5 handlers: tabular, tiff_stack, roi_zip, regionprops, array_expansion This is the mathematically correct solution: extract common patterns into reusable abstractions, pay the complexity cost once, benefit from the abstraction forever.
Replace handler-registered materializers and string-based handler specs with a greenfield, format-writer materialization API (Csv/Json/ROI/Tiff/Text). - Remove register_materializer + _generate_output_path usage across analysis backends - Migrate special_outputs specs to MaterializationSpec(CsvOptions/JsonOptions/ROIOptions/TiffStackOptions/TextOptions) - Add shared tabular extraction + metaprogrammed writer registry and presets - Update HMM/MTM/SKAN/consolidation outputs to emit writer-ready payloads (graphml/edges/records) - Refresh templates/LLM prompt snippets and unit test to match the new API
Replace TabularOptions/handler-based materialization examples with writer-based MaterializationSpec(CsvOptions/JsonOptions/ROIOptions/TiffStackOptions/TextOptions). Remove legacy handler registration/signature guidance and align special I/O documentation with greenfield writer dispatch.
…tion ObjectState lazy serialization reconstructs dataclasses via **fields; accept outputs/primary/allowed_backends keyword args while preserving the positional writer-options API.
Remove the ad-hoc MaterializationSpec(outputs=...) constructor workaround and instead rely on ObjectState's generic dataclass rebuild hook. MaterializationSpec now exposes __objectstate_rebuild__ so lazy resolution can reconstruct it without changing the public writer-options API.
Document __objectstate_rebuild__ as the supported way for init=False dataclasses to participate in ObjectState-based serialization (used by OpenHCS lazy configs and MaterializationSpec).
Drop the stray string-based MaterializationSpec usage (e.g. 'tiff_stack') that breaks writer dispatch, and defer template-matching type annotations to avoid NameError at import time during registry scanning.
Update submodules to latest main branches: - pyqt-reactive: Add enableable config pattern with checkbox in title * Automatic detection of Enableable configs * Checkbox moved to GroupBox title * Clickable title to toggle enabled state * Progressive styling for async widget creation * Preview formatting strategy pattern * CheckBox placeholder visual improvements * Parent marking simplification - python-introspect: Fix is_enableable() for classes and instances * Updated is_enableable() to handle both types and instances * Uses issubclass() for classes, isinstance() for instances Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add missing enableable.py file and exports to python-introspect submodule. - Enableable: Dataclass mixin with enabled: bool = True field - is_enableable(): Check if obj (class or instance) is enableable - mark_enableable(): Brand callables as enableable - ENABLED_FIELD: Constant for 'enabled' field name Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…alize-refactor # Conflicts: # external/pyqt-reactive # external/python-introspect
- Add abbreviation='vfs' to VFSConfig - Add abbreviation='pp' to PathPlanningConfig - Add abbreviation='mat' to StepMaterializationConfig - Add abbreviation parameter to create_streaming_config factory - Add abbreviation='nap' to NapariStreamingConfig - Add abbreviation='fiji' to FijiStreamingConfig
- Sig-diff fields now use preview_formatting_strategy.collect_and_render
- Previously used _format_field_value directly, bypassing grouping
- Now all fields show consistent grouping like wf{wf=2} | pp{enabled:true}
Updated all config classes to use the new @abbreviation decorator system from ObjectState, replacing inline field_abbreviations parameters with Annotated[..., abbreviation('...')] type hints. ## Changes ### New Imports - Added `Annotated` from typing - Added `abbreviation` from objectstate ### Config Classes Updated All config classes now follow the pattern: ```python @abbreviation('short_name') @global_pipeline_config @DataClass(frozen=True) class MyConfig: field_name: Annotated[Type, abbreviation('abbr')] = default ``` **Classes migrated:** - GlobalPipelineConfig ('gpc') - WellFilterConfig ('wfc') - ZarrConfig ('zarr') - VFSConfig ('vfs') - DtypeConfig ('dtype') - ProcessingConfig ('proc') - SequentialProcessingConfig ('seq') - AnalysisConsolidationConfig ('analysis') - PlateMetadataConfig ('plate') - ExperimentalAnalysisConfig ('exp') - PathPlanningConfig ('pp') - StepMaterializationConfig ('mat') - StreamingDefaults ('stream') - NapariStreamingConfig ('nap') - FijiStreamingConfig ('fiji') ## Benefits - **Cleaner code**: Separate @abbreviation decorator instead of inline params - **Type-safe**: Annotated types provide better IDE support - **Consistent pattern**: All configs use same approach - **Declarative**: Abbreviations defined at field declaration site ## Removed - Manual FIELD_ABBREVIATIONS_REGISTRY registration for GlobalPipelineConfig - Inline field_abbreviations and abbreviation params from @global_pipeline_config
Updated external submodules to point to latest commits: - external/ObjectState: c31831a - feat: @abbreviation decorator, hierarchy fix, and callback notification bug fix - external/pyqt-reactive: 7059d61 - feat: type-safe List[Enum] placeholder and preview formatting improvements These updates bring in critical bug fixes and new features needed by openhcs.
Treat ObjectStateRegistry history 'index' as a global id, not a list position, after history filtering. Map slider positions to filtered history entries and time-travel using the entry's global index.
PyPI rejects direct URL requirements in extras (zeroc-ice @ https://...). Keep OMERO support via scripts/install_omero_deps.py and requirements-omero.txt instead.
…rameter Replace unreliable OPENHCS_ZMQ_EXECUTION_SERVER environment variable with explicit is_zmq_execution parameter for Windows compatibility. - Add is_zmq_execution: bool = False parameter to compile_pipelines() and initialize_step_plans_for_context() - Update orchestrator.compile_pipelines() to pass through the parameter - Set is_zmq_execution=True in both ZMQ execution servers - Remove environment variable setup from OpenHCSExecutionServer.__init__ - Remove unused os imports UI/editor mode (default): ObjectStates remain registered ZMQ server mode: ObjectStates are unregistered to free RAM
Move pipeline compilation out of the UI process by adding compile-only support to the ZMQ execution path and wiring Plate Manager to share a single ZMQClientService across compile/run. This keeps compilation and execution in the same runtime environment, reduces connection churn, and enables the UI to surface server-side compile status. Also propagate compile-time config into compiled contexts (analysis_consolidation_config, auto_add_output_plate_to_plate_manager) and return output_plate_root + auto-add flag in execution results so completed runs can optionally auto-register the output plate in Plate Manager. UI/UX follow-ups: improve time-travel navigation to focus the correct DualEditorWindow and Function Pattern tab, avoid restoring PipelineConfig descendants on cancel for delegated configs, make metadata viewers scalable for multi-subdir plates (selector + lazy load + hide heavy fields), and improve ImageBrowser responsiveness/caching. Docs updated for remote compilation/execution architecture and LLM prompt guidance (decorators + no manual backend conversions).
Move OpenHCS StepParameterEditor scope styling into pyqt-reactive via scope_style_applier and thread scope_accent_color explicitly from DualEditorWindow, removing parent-tree probing and other defensive fallbacks. Also tighten compilation validation to avoid hasattr checks by reading step.func directly and failing loud when func is missing or None.
Update submodule pins to released versions after running scripts/update_and_release.py: - external/ObjectState -> v1.0.14 - external/pyqt-reactive -> v0.1.9 - external/zmqruntime -> v0.1.4
Capture the ZMQ-server compilation shift, the shared ZMQ client service, and the new auto_add_output_plate_to_plate_manager flag so users understand the new compile/run workflow and optional output plate auto-registration.
Initialize DualEditorWindow editor attributes early so scope border initialization can run before tab widgets are constructed, and re-apply scope accent styling after creating the step/function editors.
…folder Move all image/figure/plot generation scripts to scripts/figures/: - generate_xy_xz_composite_figures.py - XY/XZ projection composites - generate_figure_overlays.py - ROI overlay figures - generate_automated_plots.py - statistical bar plots - generate_figure_mosaics.py - mosaic grids Add README.md documenting all figure generation scripts and their usage
Add napari plugin for creating orthogonal projections and exporting layers: - XZ, YZ, XY max projections from 3D image stacks - Z-scaling support for proper aspect ratios - Export to TIFF/PNG/JPG with dtype conversion - Multi-channel RGB composite generation - Auto-detection and grouping of channel layers Also update scripts/figures/README to reference napari-plugins directory.
…re generation Core Progress System: - Add openhcs/core/progress_reporter.py with centralized progress emitter - Integrate progress emitter into orchestrator and worker initialization - Replace callback-based progress with structured payload emission - Wire progress queue/context through ProcessPoolExecutor initialization Orchestration Updates: - Convert progress callbacks to emit_progress() calls throughout orchestrator - Report axis/step lifecycle: start, complete, error phases - Include step_index, total_steps, percent, and error context - Pass progress queue/context to worker init for cross-process emission Runtime Integration: - Add progress emitter context to zmq_execution_server - Forward worker progress via multiprocessing queue and background thread - Emit init/compile progress before plate execution - Clean up emitter and forwarder on server shutdown Step-Level Progress: - Emit progress for pattern groups in function_step - Report counts, percent, and metadata per pattern - Support batch preload/writeout progress contexts UI Progress Handling: - Update compilation_service to track compile pending state - Enhance zmq_execution_service to display axis/step/phase/percent - Update plate_manager to cache and display progress per plate - Refresh plate list with progress percentages - Adapt textual_tui plate_manager to new progress schema - Improve image_browser filter interactions to avoid double-filtering - Make service_adapter multi-dir picker path bar editable Plate View UX: - Refactor to square-button grid with aspect-ratio container - Add row/column header toggles - Implement invert selection button - Add rectangle selection in empty space - Improve drag handling across empty cells - Build coordinate mapping when missing Submodule Integration: - zmqruntime: extend progress protocol with detailed fields - Add axis_id, step_name, step_index, phase, total_steps - Add completed, total, percent, timestamp, error, traceback - Validate required progress fields on client receive - Update ProgressUpdate message structure - pyqt-reactive: minor cleanup in function_list_editor Figure Generation Tooling: - Expand from XY/XZ to XY/XZ/YZ composite layouts - Add TIFF loading via tifffile with numpy array handling - Support flexible input extensions (.tif, .tiff, .png, .jpg, .jpeg) - Add column-based labeling (HA-OXIME, matrigel with Time A/B/C) - Implement well notation toggle (R##C## vs A01) - Include group labels in output filenames - Create optional tiled mosaic aligned by well position - Add metadata CSV mapping with well normalization - Refactor to dataclass-based configuration Note: ZMQ runtime integration and progress reporting in openhcs are still WIP.
Figure Generation Docs: - Update README to reflect XY/XZ/YZ layout - Add mosaic output usage example - Document well notation toggle (--well-format) - Note column labels and group names in filenames Planning Docs: - Add zmq-progress-reporting-plan.md with design notes - Document progress message schema and integration points
- Pin pyqt-reactive to latest main (function_list_editor cleanup) - Pin zmqruntime to latest main (extended progress protocol) Note: ZMQ runtime integration and progress reporting in openhcs are still WIP.
Main repository changes: - Added progress_state.py with ExecutionProgressTracker, AxisProgress, PlateProgress - Enhanced config.py with batch_size for streaming - Changed step_name -> step in all progress emissions (orchestrator, compiler, function_step) - Added compilation progress tracking in compiler.py - Refactored progress_reporter.py with validation and logging - Optimized image_browser.py with pre-computed display values - Removed PREVIEW_FIELD_CONFIGS from pipeline_editor.py and plate_manager.py - Enhanced zmq_server_manager.py: individual axis display, compilation phase handling - Updated fiji_stream_visualizer.py, fiji_viewer_server.py, napari_stream_visualizer.py - Added napari_viewer_server.py - Updated zmq_execution_server.py to clear compilation axes in GUI process - Added .grepai/ to .gitignore Submodule updates: - external/ObjectState: Enhanced get_resolved_value to reconstruct dataclass containers - external/PolyStore: Refactored streaming architecture with handlers and receivers - external/pyqt-reactive: Removed PREVIEW_FIELD_CONFIGS, use auto-discovery - external/zmqruntime: Added generic ZMQ messaging primitives and streaming types
…owser workflow - migrate OpenHCS progress handling to typed openhcs.core.progress package (types, emitters, projection, registry, exceptions) and remove legacy progress_reporter/streaming constants - enforce execution progress topology invariants through orchestrator/compiler/function step and context updates - replace legacy shared GUI service paths with modular server browser + batch workflow services - introduce server-browser presentation/tree population/progress aggregation modules and remove duplicated manager-side boilerplate - update ZMQ execution client/server integration and launcher wiring for extracted runtime/projection path - refactor Fiji/Napari runtime streaming integration points to align with extracted abstractions and deterministic progress/state updates - update architecture documentation to reflect boundary split between OpenHCS and external modules - advance submodule pointers: zmqruntime (v0.1.6), pyqt-reactive (v0.1.10), PolyStore (v0.1.8) - add focused unit coverage for progress projection/registry keying, server browser parsing/tree sync, poller/wait engines, and batch workflow compile/status flows
- push missing ObjectState submodule SHA to remote so submodule checkout succeeds - add workflow_dispatch dependency_source switch (submodules|pypi) - make checkout submodule behavior conditional on selected source - add explicit editable installs for local external modules in submodule mode - allow manual workflow dispatch across all integration jobs
- remove duplicate internal readiness wait from NapariStreamVisualizer startup path and make ViewerStateManager the single readiness authority - connect ZMQ client immediately after process spawn; readiness is verified by centralized wait_for_ready flow - increase orchestrator viewer ready timeout from 10s to 30s to absorb cold-start latency (Qt/napari import and first event-loop bring-up) This eliminates the false timeout/then-ready sequence seen in execution-server logs and keeps the startup invariant explicit and deterministic.
…ontext - configure an explicit multiprocessing progress queue in _execute_pipeline_phases - set progress queue before compile_pipelines() and clear it immediately after compile - pass required progress_queue/progress_context into execute_compiled_plate() - ensure queue lifecycle cleanup (close/join_thread) in finally block This aligns direct-mode integration tests with the invariant progress API (no fallback path in emit()) and fixes OMERO direct-mode compile failures.
Update submodule pointers to latest released versions: - zmqruntime: strict control dispatch table, strict pong payload parsing, explicit visualizer readiness contract, and viewer state capability probing removal; released as v0.1.7 - pyqt-reactive: normalized enableable preview-field resolution via python-introspect constants/utilities; released as v0.1.11 This aligns OpenHCS with the latest external module tags and keeps the superproject pinned to released submodule commits.
- create integration-test progress queue from explicit spawn context - create ZMQ worker progress queue from explicit spawn context This enforces a single multiprocessing context for queue/semaphore objects shared with spawned workers and resolves SemLock fork-vs-spawn mismatch in OMERO multiprocessing runs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull Request: Fix Qt Platform Initialization for WSL2
Problem
The OpenHCS GUI application failed to start on Windows Subsystem for Linux 2 (WSL2) with the following error:
The issue occurred because Qt platform configuration was attempted after PyQt6 imports had already begun, and the configuration was not compatible with WSL2's graphics environment.
Root Cause
Qt caches platform selection at import time. The original code structure allowed PyQt6 imports to occur before platform-specific environment variables were set. Additionally, the configuration did not account for WSL2's support for both Wayland (via WSLg on Windows 11+) and X11, leading to attempts to use only xcb platform which requires unavailable system libraries.
Solution
The fix reorders initialization and implements proper display server detection:
Deferred PyQt6 imports: Modified
openhcs/pyqt_gui/__init__.pyto use Python's__getattr__module attribute protocol for lazy loading of GUI classes. This allowssetup_qt_platform()to complete before any PyQt6 libraries are loaded.Improved platform detection: Enhanced
openhcs/pyqt_gui/launch.pyto detect available display servers in WSL2:X11 compatibility: Disabled MITSHM (MIT Shared Memory) for X11, which WSL2 does not reliably support.
Files Modified
openhcs/pyqt_gui/__init__.pyOpenHCSMainWindowandOpenHCSPyQtAppwith lazy loading via__getattr__openhcs/pyqt_gui/launch.pysetup_qt_platform()function with detailed documentation of WSL2 detection logicTechnical Details
The lazy loading mechanism works as follows:
When the entry point imports
from openhcs.pyqt_gui.__main__ import main, Python loads the__main__module, which causes thepyqt_guipackage to be initialized. However, the__init__.pyno longer imports GUI classes at module level, deferring them until they are first accessed. Themain()function inlaunch.pycallssetup_qt_platform()before accessing any GUI classes, ensuring environment variables are properly configured before PyQt6 is loaded.WSL2 platform detection checks for
WAYLAND_DISPLAYandDISPLAYenvironment variables in order of preference, allowing the system to use the appropriate graphics backend available in the current environment.