nanoleaf-kde-sync 1.9.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nanoleaf_kde_sync-1.9.3/LICENSE +27 -0
- nanoleaf_kde_sync-1.9.3/MANIFEST.in +3 -0
- nanoleaf_kde_sync-1.9.3/PKG-INFO +167 -0
- nanoleaf_kde_sync-1.9.3/README.md +139 -0
- nanoleaf_kde_sync-1.9.3/VERSION +1 -0
- nanoleaf_kde_sync-1.9.3/assets/icons/hicolor/128x128/apps/nanoleaf-kde-sync.png +0 -0
- nanoleaf_kde_sync-1.9.3/assets/icons/hicolor/48x48/apps/nanoleaf-kde-sync.png +0 -0
- nanoleaf_kde_sync-1.9.3/assets/icons/hicolor/scalable/apps/nanoleaf-kde-sync.svg +21 -0
- nanoleaf_kde_sync-1.9.3/assets/udev/60-nanoleaf-kde-sync.rules +7 -0
- nanoleaf_kde_sync-1.9.3/pyproject.toml +129 -0
- nanoleaf_kde_sync-1.9.3/setup.cfg +4 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_kde_sync.egg-info/PKG-INFO +167 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_kde_sync.egg-info/SOURCES.txt +275 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_kde_sync.egg-info/dependency_links.txt +1 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_kde_sync.egg-info/entry_points.txt +8 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_kde_sync.egg-info/requires.txt +21 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_kde_sync.egg-info/top_level.txt +1 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/VERSION +1 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/__init__.py +20 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/assets/icons/hicolor/128x128/apps/nanoleaf-kde-sync.png +0 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/assets/icons/hicolor/48x48/apps/nanoleaf-kde-sync.png +0 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/assets/icons/hicolor/scalable/apps/nanoleaf-kde-sync.svg +21 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/assets/udev/60-nanoleaf-kde-sync.rules +7 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/__init__.py +27 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/_drm_helper_bridge.py +249 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/_drm_master_fd.py +58 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/_drm_zone_sampler.py +1356 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/_utils.py +69 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/auto_probe.py +253 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/backend_normalization.py +14 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/backend_selection.py +34 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/dimensions.py +137 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/errors.py +14 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/factory.py +625 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/interfaces.py +33 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/kmsgrab.py +426 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/kwin_dbus.py +1138 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/latency_probe.py +209 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/mock_capture.py +48 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/nanoleaf_drm_helper +0 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/portal_helpers.py +15 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/probe_models.py +64 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/probe_timing.py +56 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/replay_capture.py +72 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/source_context.py +239 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/source_identity.py +142 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/capture/xdg_portal.py +1020 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/color/__init__.py +22 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/color/_types.py +6 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/color/capture_metadata.py +332 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/color/hdr.py +335 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/color/metadata_hysteresis.py +57 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/color/primaries.py +480 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/color/zone_mapper.py +61 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/compat/__init__.py +61 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/compat/kde_version.py +157 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/compat/kwin_probe.py +182 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/compat/portal_probe.py +146 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/compat/update_checker.py +344 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/compat/version_snapshot.py +115 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/config/__init__.py +4 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/config/model.py +305 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/config/normalize.py +819 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/config/presets.py +364 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/config/serialization.py +42 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/config/store.py +267 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/desktop_entry.py +261 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/device/__init__.py +9 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/device/hid_transport.py +674 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/device/interfaces.py +31 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/device/protocol.py +128 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/device/send_policy.py +139 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/device/transport_profiler.py +84 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/device/usb_driver.py +650 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/doc_paths.py +36 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/__init__.py +0 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/anchor_calibration.py +143 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/blending.py +695 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/calibration_resolver.py +267 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/color_accuracy_diagnostics.py +115 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/color_context.py +111 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/color_domain.py +44 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/color_pipeline.py +737 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/color_processing.py +646 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/colour_path_diagnostics.py +416 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/compositor.py +119 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/content_bounds.py +162 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/diagnostics_exports.py +782 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/edge_locality_diagnostics.py +78 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/engine.py +1968 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/errors.py +219 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/fps_governor.py +145 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/frame_context.py +140 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/output_session.py +66 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/palette_adaptive.py +434 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/palette_temporal.py +361 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/predictive_sync.py +248 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/processing.py +79 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/readiness_check.py +363 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/ring_buf.py +197 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/srgb.py +64 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/startup.py +370 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/state.py +572 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/status_warnings.py +45 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/zone_derivation.py +205 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/zone_presets.py +149 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/runtime/zones.py +1015 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/service.py +1327 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/tools/__init__.py +3 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/tools/autostart.py +83 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/tools/color_kmeans.py +76 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/tools/colour_path_probe.py +44 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/tools/config_init.py +61 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/tools/diagnostic_bundle.py +188 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/tools/doctor.py +715 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/tools/flicker_lab.py +205 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/tools/output_format.py +34 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/tools/portal_tools.py +116 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/tools/reset.py +60 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/tools/setcap_helper.py +133 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/tools/smoke_test.py +165 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/ui/__init__.py +11 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/ui/calibration_flow.py +78 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/ui/calibration_preview.py +186 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/ui/calibration_state.py +482 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/ui/calibration_widget.py +151 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/ui/command_results_dialog.py +68 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/ui/diagnostic_hub_dialog.py +493 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/ui/display_configurator.py +1564 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/ui/layout_helpers.py +99 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/ui/led_color_calibration_dialog.py +114 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/ui/live_diagnostics.py +437 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/ui/preset_ui.py +92 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/ui/qt_lazy.py +69 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/ui/settings_dialog.py +2932 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/ui/style.qss +209 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/ui/tray_app.py +1570 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/ui/zone_calibration.py +189 -0
- nanoleaf_kde_sync-1.9.3/src/nanoleaf_sync/ui/zone_presets.py +15 -0
- nanoleaf_kde_sync-1.9.3/tests/test_4d_speed_path.py +248 -0
- nanoleaf_kde_sync-1.9.3/tests/test_adaptive_smoothing.py +156 -0
- nanoleaf_kde_sync-1.9.3/tests/test_anchor_calibration.py +122 -0
- nanoleaf_kde_sync-1.9.3/tests/test_audit_fixes.py +137 -0
- nanoleaf_kde_sync-1.9.3/tests/test_audit_gaps_extended.py +70 -0
- nanoleaf_kde_sync-1.9.3/tests/test_audit_stage1.py +304 -0
- nanoleaf_kde_sync-1.9.3/tests/test_auto_probe.py +173 -0
- nanoleaf_kde_sync-1.9.3/tests/test_auto_probe_extended.py +188 -0
- nanoleaf_kde_sync-1.9.3/tests/test_autostart_tool.py +29 -0
- nanoleaf_kde_sync-1.9.3/tests/test_backend_diagnostics_reporting.py +35 -0
- nanoleaf_kde_sync-1.9.3/tests/test_calibration_flow.py +22 -0
- nanoleaf_kde_sync-1.9.3/tests/test_calibration_state.py +46 -0
- nanoleaf_kde_sync-1.9.3/tests/test_calibration_surface_consistency.py +7 -0
- nanoleaf_kde_sync-1.9.3/tests/test_calibration_widget.py +87 -0
- nanoleaf_kde_sync-1.9.3/tests/test_capture_factory_threading.py +218 -0
- nanoleaf_kde_sync-1.9.3/tests/test_capture_metadata.py +48 -0
- nanoleaf_kde_sync-1.9.3/tests/test_capture_utils.py +114 -0
- nanoleaf_kde_sync-1.9.3/tests/test_check_calibration_guardrails.py +87 -0
- nanoleaf_kde_sync-1.9.3/tests/test_check_release_versions.py +147 -0
- nanoleaf_kde_sync-1.9.3/tests/test_cleanup_qol_pass.py +133 -0
- nanoleaf_kde_sync-1.9.3/tests/test_color_accuracy_diagnostics.py +104 -0
- nanoleaf_kde_sync-1.9.3/tests/test_color_accuracy_pipeline.py +75 -0
- nanoleaf_kde_sync-1.9.3/tests/test_color_analyzer.py +213 -0
- nanoleaf_kde_sync-1.9.3/tests/test_color_golden_matrix.py +135 -0
- nanoleaf_kde_sync-1.9.3/tests/test_color_pipeline_overhaul.py +291 -0
- nanoleaf_kde_sync-1.9.3/tests/test_color_processing_extended.py +264 -0
- nanoleaf_kde_sync-1.9.3/tests/test_colour_path_diagnostics.py +164 -0
- nanoleaf_kde_sync-1.9.3/tests/test_compat_doctor.py +17 -0
- nanoleaf_kde_sync-1.9.3/tests/test_compat_errors.py +50 -0
- nanoleaf_kde_sync-1.9.3/tests/test_compat_kde_version.py +32 -0
- nanoleaf_kde_sync-1.9.3/tests/test_compat_kwin_probe.py +94 -0
- nanoleaf_kde_sync-1.9.3/tests/test_compat_portal_probe.py +103 -0
- nanoleaf_kde_sync-1.9.3/tests/test_compat_report_upstream.py +122 -0
- nanoleaf_kde_sync-1.9.3/tests/test_compat_update_checker.py +215 -0
- nanoleaf_kde_sync-1.9.3/tests/test_compat_version_snapshot.py +125 -0
- nanoleaf_kde_sync-1.9.3/tests/test_compositor.py +105 -0
- nanoleaf_kde_sync-1.9.3/tests/test_config.py +217 -0
- nanoleaf_kde_sync-1.9.3/tests/test_config_init.py +101 -0
- nanoleaf_kde_sync-1.9.3/tests/test_config_store.py +282 -0
- nanoleaf_kde_sync-1.9.3/tests/test_corner_anchor_calibration.py +51 -0
- nanoleaf_kde_sync-1.9.3/tests/test_dark_output_stability.py +313 -0
- nanoleaf_kde_sync-1.9.3/tests/test_desktop_entry.py +160 -0
- nanoleaf_kde_sync-1.9.3/tests/test_desktop_entry_extended.py +242 -0
- nanoleaf_kde_sync-1.9.3/tests/test_diagnostic_hub_service.py +35 -0
- nanoleaf_kde_sync-1.9.3/tests/test_diagnostic_hub_tools.py +37 -0
- nanoleaf_kde_sync-1.9.3/tests/test_diagnostics_exports_extended.py +436 -0
- nanoleaf_kde_sync-1.9.3/tests/test_dimensions.py +90 -0
- nanoleaf_kde_sync-1.9.3/tests/test_display_configurator.py +46 -0
- nanoleaf_kde_sync-1.9.3/tests/test_doc_paths.py +36 -0
- nanoleaf_kde_sync-1.9.3/tests/test_doctor.py +305 -0
- nanoleaf_kde_sync-1.9.3/tests/test_doctor_extended.py +596 -0
- nanoleaf_kde_sync-1.9.3/tests/test_drm_helper_bridge.py +90 -0
- nanoleaf_kde_sync-1.9.3/tests/test_errors_extended.py +106 -0
- nanoleaf_kde_sync-1.9.3/tests/test_factory_extended.py +324 -0
- nanoleaf_kde_sync-1.9.3/tests/test_first_run_onboarding.py +16 -0
- nanoleaf_kde_sync-1.9.3/tests/test_fps_governor.py +213 -0
- nanoleaf_kde_sync-1.9.3/tests/test_guided_calibration_preview.py +20 -0
- nanoleaf_kde_sync-1.9.3/tests/test_guided_led_calibration_workflow.py +129 -0
- nanoleaf_kde_sync-1.9.3/tests/test_hdr.py +169 -0
- nanoleaf_kde_sync-1.9.3/tests/test_hid_transport_extended.py +161 -0
- nanoleaf_kde_sync-1.9.3/tests/test_import_smoke_exports.py +83 -0
- nanoleaf_kde_sync-1.9.3/tests/test_install_helpers.py +74 -0
- nanoleaf_kde_sync-1.9.3/tests/test_kwin_capture_bounds.py +42 -0
- nanoleaf_kde_sync-1.9.3/tests/test_kwin_dbus_capture.py +751 -0
- nanoleaf_kde_sync-1.9.3/tests/test_kwin_probe_cache.py +63 -0
- nanoleaf_kde_sync-1.9.3/tests/test_latency_probe.py +72 -0
- nanoleaf_kde_sync-1.9.3/tests/test_led_calibration_and_spread.py +94 -0
- nanoleaf_kde_sync-1.9.3/tests/test_live_fps_diagnostics.py +330 -0
- nanoleaf_kde_sync-1.9.3/tests/test_live_sampling_mode.py +78 -0
- nanoleaf_kde_sync-1.9.3/tests/test_misc_coverage.py +270 -0
- nanoleaf_kde_sync-1.9.3/tests/test_mixed_content_sampling.py +146 -0
- nanoleaf_kde_sync-1.9.3/tests/test_neighbor_blend.py +46 -0
- nanoleaf_kde_sync-1.9.3/tests/test_normalize.py +230 -0
- nanoleaf_kde_sync-1.9.3/tests/test_normalize_extended.py +251 -0
- nanoleaf_kde_sync-1.9.3/tests/test_output_session.py +13 -0
- nanoleaf_kde_sync-1.9.3/tests/test_palette_adaptive_sampling.py +137 -0
- nanoleaf_kde_sync-1.9.3/tests/test_palette_temporal_stability.py +186 -0
- nanoleaf_kde_sync-1.9.3/tests/test_pipeline_integration.py +51 -0
- nanoleaf_kde_sync-1.9.3/tests/test_pixel_sampling_pipeline.py +212 -0
- nanoleaf_kde_sync-1.9.3/tests/test_predictive_sync.py +255 -0
- nanoleaf_kde_sync-1.9.3/tests/test_predictive_sync_pipeline.py +158 -0
- nanoleaf_kde_sync-1.9.3/tests/test_primaries.py +257 -0
- nanoleaf_kde_sync-1.9.3/tests/test_primaries_extended.py +494 -0
- nanoleaf_kde_sync-1.9.3/tests/test_priority_sampling_and_hid_diagnostics.py +425 -0
- nanoleaf_kde_sync-1.9.3/tests/test_probe_timing.py +37 -0
- nanoleaf_kde_sync-1.9.3/tests/test_processing.py +23 -0
- nanoleaf_kde_sync-1.9.3/tests/test_protocol_extended.py +121 -0
- nanoleaf_kde_sync-1.9.3/tests/test_readiness_check.py +476 -0
- nanoleaf_kde_sync-1.9.3/tests/test_readiness_check_extended.py +181 -0
- nanoleaf_kde_sync-1.9.3/tests/test_reference_ambient_neutral_model.py +160 -0
- nanoleaf_kde_sync-1.9.3/tests/test_reset_tool.py +67 -0
- nanoleaf_kde_sync-1.9.3/tests/test_runtime_engine.py +515 -0
- nanoleaf_kde_sync-1.9.3/tests/test_runtime_error_translation.py +56 -0
- nanoleaf_kde_sync-1.9.3/tests/test_runtime_real_driver_flow.py +158 -0
- nanoleaf_kde_sync-1.9.3/tests/test_runtime_startup.py +170 -0
- nanoleaf_kde_sync-1.9.3/tests/test_runtime_state.py +34 -0
- nanoleaf_kde_sync-1.9.3/tests/test_runtime_zone_presets.py +23 -0
- nanoleaf_kde_sync-1.9.3/tests/test_runtime_zones.py +68 -0
- nanoleaf_kde_sync-1.9.3/tests/test_sampling_diagnostics.py +303 -0
- nanoleaf_kde_sync-1.9.3/tests/test_screen_capture.py +571 -0
- nanoleaf_kde_sync-1.9.3/tests/test_secondary_audit_completion.py +222 -0
- nanoleaf_kde_sync-1.9.3/tests/test_security_regressions.py +36 -0
- nanoleaf_kde_sync-1.9.3/tests/test_security_regressions_extended.py +51 -0
- nanoleaf_kde_sync-1.9.3/tests/test_send_policy_periodic_ack.py +19 -0
- nanoleaf_kde_sync-1.9.3/tests/test_serialization.py +100 -0
- nanoleaf_kde_sync-1.9.3/tests/test_service_capture_dims.py +117 -0
- nanoleaf_kde_sync-1.9.3/tests/test_service_robustness.py +351 -0
- nanoleaf_kde_sync-1.9.3/tests/test_service_status.py +244 -0
- nanoleaf_kde_sync-1.9.3/tests/test_service_status_modes.py +648 -0
- nanoleaf_kde_sync-1.9.3/tests/test_settings_dialog.py +203 -0
- nanoleaf_kde_sync-1.9.3/tests/test_smoke_test.py +115 -0
- nanoleaf_kde_sync-1.9.3/tests/test_srgb.py +137 -0
- nanoleaf_kde_sync-1.9.3/tests/test_stage2_frame_context.py +75 -0
- nanoleaf_kde_sync-1.9.3/tests/test_stage3_color_context.py +75 -0
- nanoleaf_kde_sync-1.9.3/tests/test_stage4_send_policy.py +97 -0
- nanoleaf_kde_sync-1.9.3/tests/test_stage5_architecture.py +116 -0
- nanoleaf_kde_sync-1.9.3/tests/test_stage5_bundle.py +40 -0
- nanoleaf_kde_sync-1.9.3/tests/test_stages_3_5_completion.py +158 -0
- nanoleaf_kde_sync-1.9.3/tests/test_synthetic_clips.py +78 -0
- nanoleaf_kde_sync-1.9.3/tests/test_tools_autostart.py +22 -0
- nanoleaf_kde_sync-1.9.3/tests/test_tray_async_tools.py +26 -0
- nanoleaf_kde_sync-1.9.3/tests/test_tray_menu_structure.py +63 -0
- nanoleaf_kde_sync-1.9.3/tests/test_tray_mode_labels.py +24 -0
- nanoleaf_kde_sync-1.9.3/tests/test_tray_preview_recovery.py +215 -0
- nanoleaf_kde_sync-1.9.3/tests/test_tray_preview_resume.py +87 -0
- nanoleaf_kde_sync-1.9.3/tests/test_tray_quit_async.py +308 -0
- nanoleaf_kde_sync-1.9.3/tests/test_tray_restart_output_guard.py +126 -0
- nanoleaf_kde_sync-1.9.3/tests/test_tray_self_check.py +52 -0
- nanoleaf_kde_sync-1.9.3/tests/test_tray_settings_apply.py +394 -0
- nanoleaf_kde_sync-1.9.3/tests/test_tray_start_robustness.py +182 -0
- nanoleaf_kde_sync-1.9.3/tests/test_ui_headless.py +131 -0
- nanoleaf_kde_sync-1.9.3/tests/test_wizard_and_settings_structure.py +78 -0
- nanoleaf_kde_sync-1.9.3/tests/test_xdg_portal_colour_path.py +263 -0
- nanoleaf_kde_sync-1.9.3/tests/test_xdg_portal_robustness.py +426 -0
- nanoleaf_kde_sync-1.9.3/tests/test_zone_calibration.py +27 -0
- nanoleaf_kde_sync-1.9.3/tests/test_zone_derivation.py +87 -0
- nanoleaf_kde_sync-1.9.3/tests/test_zone_mapper.py +37 -0
- nanoleaf_kde_sync-1.9.3/tests/test_zone_presets.py +49 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Nanoleaf Source-Available Non-Commercial License
|
|
2
|
+
Copyright (c) 2026 SpinGiantCRM
|
|
3
|
+
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
of this software and associated documentation files (the "Software"), to use,
|
|
6
|
+
copy, modify, merge, and distribute the Software, subject to the following
|
|
7
|
+
conditions:
|
|
8
|
+
|
|
9
|
+
1. The above copyright notice and this permission notice shall be included in all
|
|
10
|
+
copies or substantial portions of the Software.
|
|
11
|
+
|
|
12
|
+
2. Redistribution of the Software must be at no charge.
|
|
13
|
+
|
|
14
|
+
3. Any use, distribution, sublicensing, hosting, bundling, sale, or other
|
|
15
|
+
activity involving the Software that is intended for or directed toward
|
|
16
|
+
commercial advantage or monetary compensation is prohibited without prior
|
|
17
|
+
written permission from the copyright holder.
|
|
18
|
+
|
|
19
|
+
4. All commercial rights are reserved to the copyright holder.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
SOFTWARE.
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nanoleaf-kde-sync
|
|
3
|
+
Version: 1.9.3
|
|
4
|
+
Summary: Nanoleaf screen mirroring for KDE Plasma on Linux.
|
|
5
|
+
License-Expression: LicenseRef-Nanoleaf-Source-Available-Non-Commercial
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: numpy<3,>=1.21
|
|
10
|
+
Requires-Dist: PyQt6<7,>=6.0
|
|
11
|
+
Requires-Dist: dbus-next<1,>=0.2.0
|
|
12
|
+
Requires-Dist: hidapi<1,>=0.14.0
|
|
13
|
+
Requires-Dist: dacite<2,>=1.8.1
|
|
14
|
+
Requires-Dist: tomli-w<2,>=1.0.0
|
|
15
|
+
Requires-Dist: packaging<26,>=24.0
|
|
16
|
+
Provides-Extra: test
|
|
17
|
+
Requires-Dist: pytest>=8; extra == "test"
|
|
18
|
+
Requires-Dist: pytest-cov>=5; extra == "test"
|
|
19
|
+
Requires-Dist: pytest-timeout>=2.3; extra == "test"
|
|
20
|
+
Requires-Dist: ruff>=0.6; extra == "test"
|
|
21
|
+
Requires-Dist: mypy>=1.0; extra == "test"
|
|
22
|
+
Requires-Dist: pre-commit>=4.0; extra == "test"
|
|
23
|
+
Provides-Extra: portal
|
|
24
|
+
Requires-Dist: pipewire; extra == "portal"
|
|
25
|
+
Provides-Extra: gstreamer
|
|
26
|
+
Requires-Dist: pygobject; extra == "gstreamer"
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
# Nanoleaf Screen Mirror for KDE
|
|
30
|
+
|
|
31
|
+
Public Nanoleaf USB screen mirroring app for KDE Plasma 6 on Linux (Arch / CachyOS and other distros via source install).
|
|
32
|
+
|
|
33
|
+
Mirrors your display edge colors to supported Nanoleaf USB strips in real time, with a tray app, setup wizard, calibration, and diagnostics.
|
|
34
|
+
|
|
35
|
+
## What you need
|
|
36
|
+
|
|
37
|
+
- Linux with KDE Plasma 6 (Wayland recommended)
|
|
38
|
+
- A supported Nanoleaf USB strip: `NL82K1` (`0x37fa:0x8201`) or `NL82K2` (`0x37fa:0x8202`)
|
|
39
|
+
- USB permissions via udev (see [Hardware setup](docs/HARDWARE_SETUP.md))
|
|
40
|
+
|
|
41
|
+
## Install (Arch / CachyOS)
|
|
42
|
+
|
|
43
|
+
**When published on AUR:**
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
paru -S --needed python-dacite nanoleaf-kde-sync
|
|
47
|
+
paru -Syu
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Until AUR account is available — local build from this repo:**
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
paru -S --needed python-dacite
|
|
54
|
+
./scripts/build_arch_package.sh
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Install udev rules after package install:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
./scripts/setup_udev.sh
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Quick start
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
nanoleaf-kde-sync-init-config
|
|
67
|
+
nanoleaf-kde-sync-doctor
|
|
68
|
+
nanoleaf-kde-sync-smoke-test
|
|
69
|
+
nanoleaf-kde-sync
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Service-only mode:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
nanoleaf-kde-sync-service
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Core commands
|
|
79
|
+
|
|
80
|
+
- `nanoleaf-kde-sync` — tray app (recommended)
|
|
81
|
+
- `nanoleaf-kde-sync-service` — headless runtime service
|
|
82
|
+
- `nanoleaf-kde-sync-init-config` — generate default config
|
|
83
|
+
- `nanoleaf-kde-sync-doctor` — environment/device diagnostics
|
|
84
|
+
- `nanoleaf-kde-sync-smoke-test` — quick functional sanity check
|
|
85
|
+
- `nanoleaf-kde-sync-autostart` — manage KDE autostart integration
|
|
86
|
+
- `nanoleaf-kde-sync-reset` — reset config/calibration/diagnostic cache safely
|
|
87
|
+
|
|
88
|
+
## First-run setup
|
|
89
|
+
|
|
90
|
+
1. Start the tray app (`nanoleaf-kde-sync`).
|
|
91
|
+
2. Complete the setup wizard.
|
|
92
|
+
3. Keep **manual strip zone count** set to your real hardware value.
|
|
93
|
+
4. Run a calibration test pattern and assign TL/TR/BR/BL anchors.
|
|
94
|
+
|
|
95
|
+
Manual strip count is authoritative for runtime, mapping, and calibration. Device-reported count is diagnostics-only unless you explicitly apply a new value.
|
|
96
|
+
|
|
97
|
+
See the [User guide](docs/USER_GUIDE.md) for a full walkthrough.
|
|
98
|
+
|
|
99
|
+
## HDR / SDR notes
|
|
100
|
+
|
|
101
|
+
- `Display preset = SDR`: SDR-safe defaults.
|
|
102
|
+
- `Display preset = HDR`: HDR-first defaults.
|
|
103
|
+
- `Display preset = Auto`: follows compositor capability.
|
|
104
|
+
|
|
105
|
+
On Plasma HDR desktops, verify SDR white reference and compositor HDR settings in app diagnostics before tuning brightness.
|
|
106
|
+
|
|
107
|
+
## Fresh install / reinstall / uninstall helpers
|
|
108
|
+
|
|
109
|
+
Pacman-managed reinstall from a local checkout:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
./scripts/reinstall_local.sh
|
|
113
|
+
./scripts/uninstall_local.sh
|
|
114
|
+
# optional full purge:
|
|
115
|
+
./scripts/uninstall_local.sh --purge-config
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
See [Arch / AUR packaging](docs/PACKAGING_AUR.md) for maintainer and AUR publish steps.
|
|
119
|
+
|
|
120
|
+
## Reset commands
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
nanoleaf-kde-sync-reset app-config --stop-runtime
|
|
124
|
+
nanoleaf-kde-sync-reset calibration --stop-runtime
|
|
125
|
+
nanoleaf-kde-sync-reset diagnostics --stop-runtime
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Documentation
|
|
129
|
+
|
|
130
|
+
- [User guide](docs/USER_GUIDE.md)
|
|
131
|
+
- [Hardware setup](docs/HARDWARE_SETUP.md)
|
|
132
|
+
- [Troubleshooting](docs/TROUBLESHOOTING.md)
|
|
133
|
+
- [Smoke test](docs/SMOKE_TEST.md)
|
|
134
|
+
- [Security](docs/SECURITY.md)
|
|
135
|
+
- [Contributing](CONTRIBUTING.md)
|
|
136
|
+
|
|
137
|
+
Installed packages also ship docs under `/usr/share/doc/nanoleaf-kde-sync/`.
|
|
138
|
+
|
|
139
|
+
## Release gate
|
|
140
|
+
|
|
141
|
+
Run `./scripts/release_gate.sh` before tagging a release. CI must be green on `main`.
|
|
142
|
+
|
|
143
|
+
## Developer setup
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
python -m venv .venv
|
|
147
|
+
source .venv/bin/activate
|
|
148
|
+
pip install -e .[test]
|
|
149
|
+
pre-commit install
|
|
150
|
+
pre-commit run --all-files
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Supported environment
|
|
154
|
+
|
|
155
|
+
- Linux
|
|
156
|
+
- KDE Plasma 6 (Wayland recommended)
|
|
157
|
+
- Supported Nanoleaf USB strips: `NL82K1` (`0x37fa:0x8201`), `NL82K2` (`0x37fa:0x8202`)
|
|
158
|
+
|
|
159
|
+
## Known limitations
|
|
160
|
+
|
|
161
|
+
- Single-monitor flow only (no multi-monitor support).
|
|
162
|
+
- Device strip count auto-detection is diagnostics-only; not auto-applied.
|
|
163
|
+
- Desktop-entry launch context is still preferred for reliable KWin authorization.
|
|
164
|
+
|
|
165
|
+
## License
|
|
166
|
+
|
|
167
|
+
Source-available non-commercial license — see [LICENSE](LICENSE). Redistribution terms apply; read before packaging or mirroring.
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Nanoleaf Screen Mirror for KDE
|
|
2
|
+
|
|
3
|
+
Public Nanoleaf USB screen mirroring app for KDE Plasma 6 on Linux (Arch / CachyOS and other distros via source install).
|
|
4
|
+
|
|
5
|
+
Mirrors your display edge colors to supported Nanoleaf USB strips in real time, with a tray app, setup wizard, calibration, and diagnostics.
|
|
6
|
+
|
|
7
|
+
## What you need
|
|
8
|
+
|
|
9
|
+
- Linux with KDE Plasma 6 (Wayland recommended)
|
|
10
|
+
- A supported Nanoleaf USB strip: `NL82K1` (`0x37fa:0x8201`) or `NL82K2` (`0x37fa:0x8202`)
|
|
11
|
+
- USB permissions via udev (see [Hardware setup](docs/HARDWARE_SETUP.md))
|
|
12
|
+
|
|
13
|
+
## Install (Arch / CachyOS)
|
|
14
|
+
|
|
15
|
+
**When published on AUR:**
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
paru -S --needed python-dacite nanoleaf-kde-sync
|
|
19
|
+
paru -Syu
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Until AUR account is available — local build from this repo:**
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
paru -S --needed python-dacite
|
|
26
|
+
./scripts/build_arch_package.sh
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Install udev rules after package install:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
./scripts/setup_udev.sh
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Quick start
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
nanoleaf-kde-sync-init-config
|
|
39
|
+
nanoleaf-kde-sync-doctor
|
|
40
|
+
nanoleaf-kde-sync-smoke-test
|
|
41
|
+
nanoleaf-kde-sync
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Service-only mode:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
nanoleaf-kde-sync-service
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Core commands
|
|
51
|
+
|
|
52
|
+
- `nanoleaf-kde-sync` — tray app (recommended)
|
|
53
|
+
- `nanoleaf-kde-sync-service` — headless runtime service
|
|
54
|
+
- `nanoleaf-kde-sync-init-config` — generate default config
|
|
55
|
+
- `nanoleaf-kde-sync-doctor` — environment/device diagnostics
|
|
56
|
+
- `nanoleaf-kde-sync-smoke-test` — quick functional sanity check
|
|
57
|
+
- `nanoleaf-kde-sync-autostart` — manage KDE autostart integration
|
|
58
|
+
- `nanoleaf-kde-sync-reset` — reset config/calibration/diagnostic cache safely
|
|
59
|
+
|
|
60
|
+
## First-run setup
|
|
61
|
+
|
|
62
|
+
1. Start the tray app (`nanoleaf-kde-sync`).
|
|
63
|
+
2. Complete the setup wizard.
|
|
64
|
+
3. Keep **manual strip zone count** set to your real hardware value.
|
|
65
|
+
4. Run a calibration test pattern and assign TL/TR/BR/BL anchors.
|
|
66
|
+
|
|
67
|
+
Manual strip count is authoritative for runtime, mapping, and calibration. Device-reported count is diagnostics-only unless you explicitly apply a new value.
|
|
68
|
+
|
|
69
|
+
See the [User guide](docs/USER_GUIDE.md) for a full walkthrough.
|
|
70
|
+
|
|
71
|
+
## HDR / SDR notes
|
|
72
|
+
|
|
73
|
+
- `Display preset = SDR`: SDR-safe defaults.
|
|
74
|
+
- `Display preset = HDR`: HDR-first defaults.
|
|
75
|
+
- `Display preset = Auto`: follows compositor capability.
|
|
76
|
+
|
|
77
|
+
On Plasma HDR desktops, verify SDR white reference and compositor HDR settings in app diagnostics before tuning brightness.
|
|
78
|
+
|
|
79
|
+
## Fresh install / reinstall / uninstall helpers
|
|
80
|
+
|
|
81
|
+
Pacman-managed reinstall from a local checkout:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
./scripts/reinstall_local.sh
|
|
85
|
+
./scripts/uninstall_local.sh
|
|
86
|
+
# optional full purge:
|
|
87
|
+
./scripts/uninstall_local.sh --purge-config
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
See [Arch / AUR packaging](docs/PACKAGING_AUR.md) for maintainer and AUR publish steps.
|
|
91
|
+
|
|
92
|
+
## Reset commands
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
nanoleaf-kde-sync-reset app-config --stop-runtime
|
|
96
|
+
nanoleaf-kde-sync-reset calibration --stop-runtime
|
|
97
|
+
nanoleaf-kde-sync-reset diagnostics --stop-runtime
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Documentation
|
|
101
|
+
|
|
102
|
+
- [User guide](docs/USER_GUIDE.md)
|
|
103
|
+
- [Hardware setup](docs/HARDWARE_SETUP.md)
|
|
104
|
+
- [Troubleshooting](docs/TROUBLESHOOTING.md)
|
|
105
|
+
- [Smoke test](docs/SMOKE_TEST.md)
|
|
106
|
+
- [Security](docs/SECURITY.md)
|
|
107
|
+
- [Contributing](CONTRIBUTING.md)
|
|
108
|
+
|
|
109
|
+
Installed packages also ship docs under `/usr/share/doc/nanoleaf-kde-sync/`.
|
|
110
|
+
|
|
111
|
+
## Release gate
|
|
112
|
+
|
|
113
|
+
Run `./scripts/release_gate.sh` before tagging a release. CI must be green on `main`.
|
|
114
|
+
|
|
115
|
+
## Developer setup
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
python -m venv .venv
|
|
119
|
+
source .venv/bin/activate
|
|
120
|
+
pip install -e .[test]
|
|
121
|
+
pre-commit install
|
|
122
|
+
pre-commit run --all-files
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Supported environment
|
|
126
|
+
|
|
127
|
+
- Linux
|
|
128
|
+
- KDE Plasma 6 (Wayland recommended)
|
|
129
|
+
- Supported Nanoleaf USB strips: `NL82K1` (`0x37fa:0x8201`), `NL82K2` (`0x37fa:0x8202`)
|
|
130
|
+
|
|
131
|
+
## Known limitations
|
|
132
|
+
|
|
133
|
+
- Single-monitor flow only (no multi-monitor support).
|
|
134
|
+
- Device strip count auto-detection is diagnostics-only; not auto-applied.
|
|
135
|
+
- Desktop-entry launch context is still preferred for reliable KWin authorization.
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
|
|
139
|
+
Source-available non-commercial license — see [LICENSE](LICENSE). Redistribution terms apply; read before packaging or mirroring.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.9.3
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" role="img" aria-label="nanoleaf-kde-sync">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="brand" x1="0" y1="0" x2="1" y2="1">
|
|
4
|
+
<stop offset="0" stop-color="#3ddc97"/>
|
|
5
|
+
<stop offset="1" stop-color="#30a7ff"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
<linearGradient id="screen" x1="0" y1="0" x2="1" y2="0">
|
|
8
|
+
<stop offset="0" stop-color="#e05c5c" stop-opacity="0.82"/>
|
|
9
|
+
<stop offset="0.5" stop-color="#3ddc97" stop-opacity="0.82"/>
|
|
10
|
+
<stop offset="1" stop-color="#30a7ff" stop-opacity="0.82"/>
|
|
11
|
+
</linearGradient>
|
|
12
|
+
</defs>
|
|
13
|
+
<rect x="4" y="4" width="120" height="120" rx="22" fill="#1c202e"/>
|
|
14
|
+
<rect x="12" y="14" width="104" height="70" rx="9" fill="none" stroke="url(#brand)" stroke-width="4.5"/>
|
|
15
|
+
<rect x="19" y="21" width="90" height="56" rx="5" fill="url(#screen)"/>
|
|
16
|
+
<rect x="55" y="84" width="18" height="9" rx="4" fill="#3ddc97" opacity="0.75"/>
|
|
17
|
+
<rect x="40" y="93" width="48" height="7" rx="3.5" fill="#3ddc97" opacity="0.6"/>
|
|
18
|
+
<rect x="12" y="109" width="28" height="14" rx="7" fill="#e05c5c" opacity="0.92"/>
|
|
19
|
+
<rect x="50" y="109" width="28" height="14" rx="7" fill="#3ddc97" opacity="0.92"/>
|
|
20
|
+
<rect x="88" y="109" width="28" height="14" rx="7" fill="#30a7ff" opacity="0.92"/>
|
|
21
|
+
</svg>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Nanoleaf USB Screen Mirror Light Strip and Pegboard Desk Dock
|
|
2
|
+
# Gives local users access via the `plugdev` group.
|
|
3
|
+
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="37fa", ATTRS{idProduct}=="8201", MODE="0660", GROUP="plugdev", TAG+="uaccess"
|
|
4
|
+
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="37fa", ATTRS{idProduct}=="8202", MODE="0660", GROUP="plugdev", TAG+="uaccess"
|
|
5
|
+
|
|
6
|
+
# Disable USB autosuspend so HID resume latency does not drop frames at 60 FPS.
|
|
7
|
+
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="37fa", ATTR{idProduct}=="8201|8202", ATTR{power/control}="on"
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77.0.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "nanoleaf-kde-sync"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Nanoleaf screen mirroring for KDE Plasma on Linux."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "LicenseRef-Nanoleaf-Source-Available-Non-Commercial"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
requires-python = ">=3.11"
|
|
13
|
+
dependencies = [
|
|
14
|
+
"numpy>=1.21,<3",
|
|
15
|
+
"PyQt6>=6.0,<7",
|
|
16
|
+
"dbus-next>=0.2.0,<1",
|
|
17
|
+
"hidapi>=0.14.0,<1",
|
|
18
|
+
"dacite>=1.8.1,<2",
|
|
19
|
+
"tomli-w>=1.0.0,<2",
|
|
20
|
+
"packaging>=24.0,<26",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[project.optional-dependencies]
|
|
24
|
+
test = [
|
|
25
|
+
"pytest>=8",
|
|
26
|
+
"pytest-cov>=5",
|
|
27
|
+
"pytest-timeout>=2.3",
|
|
28
|
+
"ruff>=0.6",
|
|
29
|
+
"mypy>=1.0",
|
|
30
|
+
"pre-commit>=4.0",
|
|
31
|
+
]
|
|
32
|
+
portal = [
|
|
33
|
+
"pipewire",
|
|
34
|
+
]
|
|
35
|
+
gstreamer = [
|
|
36
|
+
"pygobject",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
[project.scripts]
|
|
40
|
+
nanoleaf-kde-sync = "nanoleaf_sync.ui.tray_app:main"
|
|
41
|
+
nanoleaf-kde-sync-service = "nanoleaf_sync.service:main"
|
|
42
|
+
nanoleaf-kde-sync-doctor = "nanoleaf_sync.tools.doctor:main"
|
|
43
|
+
nanoleaf-kde-sync-smoke-test = "nanoleaf_sync.tools.smoke_test:main"
|
|
44
|
+
nanoleaf-kde-sync-init-config = "nanoleaf_sync.tools.config_init:main"
|
|
45
|
+
nanoleaf-kde-sync-autostart = "nanoleaf_sync.tools.autostart:main"
|
|
46
|
+
nanoleaf-kde-sync-reset = "nanoleaf_sync.tools.reset:main"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
[tool.setuptools.dynamic]
|
|
50
|
+
version = {file = ["VERSION"]}
|
|
51
|
+
[tool.setuptools]
|
|
52
|
+
package-dir = {"" = "src"}
|
|
53
|
+
|
|
54
|
+
[tool.setuptools.packages.find]
|
|
55
|
+
where = ["src"]
|
|
56
|
+
include = ["nanoleaf_sync*"]
|
|
57
|
+
|
|
58
|
+
[tool.setuptools.package-data]
|
|
59
|
+
nanoleaf_sync = [
|
|
60
|
+
"VERSION",
|
|
61
|
+
"ui/style.qss",
|
|
62
|
+
"assets/icons/**/*",
|
|
63
|
+
"assets/udev/60-nanoleaf-kde-sync.rules",
|
|
64
|
+
"capture/nanoleaf_drm_helper",
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
[tool.pytest.ini_options]
|
|
68
|
+
testpaths = ["tests"]
|
|
69
|
+
pythonpath = ["src"]
|
|
70
|
+
|
|
71
|
+
[tool.coverage.run]
|
|
72
|
+
omit = [
|
|
73
|
+
"src/nanoleaf_sync/ui/settings_dialog.py",
|
|
74
|
+
"src/nanoleaf_sync/ui/display_configurator.py",
|
|
75
|
+
"src/nanoleaf_sync/ui/live_diagnostics.py",
|
|
76
|
+
"src/nanoleaf_sync/ui/led_color_calibration_dialog.py",
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
[tool.ruff]
|
|
80
|
+
line-length = 100
|
|
81
|
+
target-version = "py311"
|
|
82
|
+
|
|
83
|
+
[tool.ruff.lint]
|
|
84
|
+
select = ["E", "F", "I", "N", "W", "UP", "B", "SIM"]
|
|
85
|
+
|
|
86
|
+
[tool.ruff.lint.per-file-ignores]
|
|
87
|
+
"tests/**" = ["N802", "N803", "N806"]
|
|
88
|
+
"src/nanoleaf_sync/tools/doctor.py" = ["E402"]
|
|
89
|
+
"src/nanoleaf_sync/tools/smoke_test.py" = ["E402"]
|
|
90
|
+
"src/nanoleaf_sync/tools/autostart.py" = ["E402"]
|
|
91
|
+
"src/nanoleaf_sync/capture/kwin_dbus.py" = ["E402"]
|
|
92
|
+
"src/nanoleaf_sync/config/store.py" = ["E402"]
|
|
93
|
+
"src/nanoleaf_sync/device/hid_transport.py" = ["E402"]
|
|
94
|
+
"src/nanoleaf_sync/ui/settings_dialog.py" = ["E402", "N802", "N803", "N806"]
|
|
95
|
+
"src/nanoleaf_sync/ui/display_configurator.py" = ["N802", "N803", "N806"]
|
|
96
|
+
"src/nanoleaf_sync/ui/calibration_widget.py" = ["N806"]
|
|
97
|
+
"src/nanoleaf_sync/ui/led_color_calibration_dialog.py" = ["N806"]
|
|
98
|
+
"src/nanoleaf_sync/capture/_drm_zone_sampler.py" = ["N802", "N806"]
|
|
99
|
+
"src/nanoleaf_sync/color/hdr.py" = ["N806"]
|
|
100
|
+
"src/nanoleaf_sync/color/primaries.py" = ["N806"]
|
|
101
|
+
|
|
102
|
+
[tool.ruff.format]
|
|
103
|
+
line-ending = "lf"
|
|
104
|
+
|
|
105
|
+
[tool.mypy]
|
|
106
|
+
python_version = "3.12"
|
|
107
|
+
ignore_missing_imports = true
|
|
108
|
+
warn_redundant_casts = true
|
|
109
|
+
warn_unused_ignores = true
|
|
110
|
+
exclude = ["src/nanoleaf_sync/ui/"]
|
|
111
|
+
files = ["src/nanoleaf_sync"]
|
|
112
|
+
|
|
113
|
+
[[tool.mypy.overrides]]
|
|
114
|
+
module = [
|
|
115
|
+
"nanoleaf_sync.capture.*",
|
|
116
|
+
"nanoleaf_sync.runtime.*",
|
|
117
|
+
"nanoleaf_sync.device.*",
|
|
118
|
+
"nanoleaf_sync.service",
|
|
119
|
+
"nanoleaf_sync.desktop_entry",
|
|
120
|
+
"nanoleaf_sync.color.hdr",
|
|
121
|
+
"nanoleaf_sync.color.zone_mapper",
|
|
122
|
+
"nanoleaf_sync.tools.portal_tools",
|
|
123
|
+
"nanoleaf_sync.tools.color_kmeans",
|
|
124
|
+
]
|
|
125
|
+
ignore_errors = true
|
|
126
|
+
|
|
127
|
+
[tool.bandit]
|
|
128
|
+
exclude_dirs = ["tests", "build", "dist", ".venv"]
|
|
129
|
+
skips = ["B101", "B108", "B110", "B311", "B324", "B404", "B603", "B607", "B608"]
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nanoleaf-kde-sync
|
|
3
|
+
Version: 1.9.3
|
|
4
|
+
Summary: Nanoleaf screen mirroring for KDE Plasma on Linux.
|
|
5
|
+
License-Expression: LicenseRef-Nanoleaf-Source-Available-Non-Commercial
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: numpy<3,>=1.21
|
|
10
|
+
Requires-Dist: PyQt6<7,>=6.0
|
|
11
|
+
Requires-Dist: dbus-next<1,>=0.2.0
|
|
12
|
+
Requires-Dist: hidapi<1,>=0.14.0
|
|
13
|
+
Requires-Dist: dacite<2,>=1.8.1
|
|
14
|
+
Requires-Dist: tomli-w<2,>=1.0.0
|
|
15
|
+
Requires-Dist: packaging<26,>=24.0
|
|
16
|
+
Provides-Extra: test
|
|
17
|
+
Requires-Dist: pytest>=8; extra == "test"
|
|
18
|
+
Requires-Dist: pytest-cov>=5; extra == "test"
|
|
19
|
+
Requires-Dist: pytest-timeout>=2.3; extra == "test"
|
|
20
|
+
Requires-Dist: ruff>=0.6; extra == "test"
|
|
21
|
+
Requires-Dist: mypy>=1.0; extra == "test"
|
|
22
|
+
Requires-Dist: pre-commit>=4.0; extra == "test"
|
|
23
|
+
Provides-Extra: portal
|
|
24
|
+
Requires-Dist: pipewire; extra == "portal"
|
|
25
|
+
Provides-Extra: gstreamer
|
|
26
|
+
Requires-Dist: pygobject; extra == "gstreamer"
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
# Nanoleaf Screen Mirror for KDE
|
|
30
|
+
|
|
31
|
+
Public Nanoleaf USB screen mirroring app for KDE Plasma 6 on Linux (Arch / CachyOS and other distros via source install).
|
|
32
|
+
|
|
33
|
+
Mirrors your display edge colors to supported Nanoleaf USB strips in real time, with a tray app, setup wizard, calibration, and diagnostics.
|
|
34
|
+
|
|
35
|
+
## What you need
|
|
36
|
+
|
|
37
|
+
- Linux with KDE Plasma 6 (Wayland recommended)
|
|
38
|
+
- A supported Nanoleaf USB strip: `NL82K1` (`0x37fa:0x8201`) or `NL82K2` (`0x37fa:0x8202`)
|
|
39
|
+
- USB permissions via udev (see [Hardware setup](docs/HARDWARE_SETUP.md))
|
|
40
|
+
|
|
41
|
+
## Install (Arch / CachyOS)
|
|
42
|
+
|
|
43
|
+
**When published on AUR:**
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
paru -S --needed python-dacite nanoleaf-kde-sync
|
|
47
|
+
paru -Syu
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Until AUR account is available — local build from this repo:**
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
paru -S --needed python-dacite
|
|
54
|
+
./scripts/build_arch_package.sh
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Install udev rules after package install:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
./scripts/setup_udev.sh
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Quick start
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
nanoleaf-kde-sync-init-config
|
|
67
|
+
nanoleaf-kde-sync-doctor
|
|
68
|
+
nanoleaf-kde-sync-smoke-test
|
|
69
|
+
nanoleaf-kde-sync
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Service-only mode:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
nanoleaf-kde-sync-service
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Core commands
|
|
79
|
+
|
|
80
|
+
- `nanoleaf-kde-sync` — tray app (recommended)
|
|
81
|
+
- `nanoleaf-kde-sync-service` — headless runtime service
|
|
82
|
+
- `nanoleaf-kde-sync-init-config` — generate default config
|
|
83
|
+
- `nanoleaf-kde-sync-doctor` — environment/device diagnostics
|
|
84
|
+
- `nanoleaf-kde-sync-smoke-test` — quick functional sanity check
|
|
85
|
+
- `nanoleaf-kde-sync-autostart` — manage KDE autostart integration
|
|
86
|
+
- `nanoleaf-kde-sync-reset` — reset config/calibration/diagnostic cache safely
|
|
87
|
+
|
|
88
|
+
## First-run setup
|
|
89
|
+
|
|
90
|
+
1. Start the tray app (`nanoleaf-kde-sync`).
|
|
91
|
+
2. Complete the setup wizard.
|
|
92
|
+
3. Keep **manual strip zone count** set to your real hardware value.
|
|
93
|
+
4. Run a calibration test pattern and assign TL/TR/BR/BL anchors.
|
|
94
|
+
|
|
95
|
+
Manual strip count is authoritative for runtime, mapping, and calibration. Device-reported count is diagnostics-only unless you explicitly apply a new value.
|
|
96
|
+
|
|
97
|
+
See the [User guide](docs/USER_GUIDE.md) for a full walkthrough.
|
|
98
|
+
|
|
99
|
+
## HDR / SDR notes
|
|
100
|
+
|
|
101
|
+
- `Display preset = SDR`: SDR-safe defaults.
|
|
102
|
+
- `Display preset = HDR`: HDR-first defaults.
|
|
103
|
+
- `Display preset = Auto`: follows compositor capability.
|
|
104
|
+
|
|
105
|
+
On Plasma HDR desktops, verify SDR white reference and compositor HDR settings in app diagnostics before tuning brightness.
|
|
106
|
+
|
|
107
|
+
## Fresh install / reinstall / uninstall helpers
|
|
108
|
+
|
|
109
|
+
Pacman-managed reinstall from a local checkout:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
./scripts/reinstall_local.sh
|
|
113
|
+
./scripts/uninstall_local.sh
|
|
114
|
+
# optional full purge:
|
|
115
|
+
./scripts/uninstall_local.sh --purge-config
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
See [Arch / AUR packaging](docs/PACKAGING_AUR.md) for maintainer and AUR publish steps.
|
|
119
|
+
|
|
120
|
+
## Reset commands
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
nanoleaf-kde-sync-reset app-config --stop-runtime
|
|
124
|
+
nanoleaf-kde-sync-reset calibration --stop-runtime
|
|
125
|
+
nanoleaf-kde-sync-reset diagnostics --stop-runtime
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Documentation
|
|
129
|
+
|
|
130
|
+
- [User guide](docs/USER_GUIDE.md)
|
|
131
|
+
- [Hardware setup](docs/HARDWARE_SETUP.md)
|
|
132
|
+
- [Troubleshooting](docs/TROUBLESHOOTING.md)
|
|
133
|
+
- [Smoke test](docs/SMOKE_TEST.md)
|
|
134
|
+
- [Security](docs/SECURITY.md)
|
|
135
|
+
- [Contributing](CONTRIBUTING.md)
|
|
136
|
+
|
|
137
|
+
Installed packages also ship docs under `/usr/share/doc/nanoleaf-kde-sync/`.
|
|
138
|
+
|
|
139
|
+
## Release gate
|
|
140
|
+
|
|
141
|
+
Run `./scripts/release_gate.sh` before tagging a release. CI must be green on `main`.
|
|
142
|
+
|
|
143
|
+
## Developer setup
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
python -m venv .venv
|
|
147
|
+
source .venv/bin/activate
|
|
148
|
+
pip install -e .[test]
|
|
149
|
+
pre-commit install
|
|
150
|
+
pre-commit run --all-files
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Supported environment
|
|
154
|
+
|
|
155
|
+
- Linux
|
|
156
|
+
- KDE Plasma 6 (Wayland recommended)
|
|
157
|
+
- Supported Nanoleaf USB strips: `NL82K1` (`0x37fa:0x8201`), `NL82K2` (`0x37fa:0x8202`)
|
|
158
|
+
|
|
159
|
+
## Known limitations
|
|
160
|
+
|
|
161
|
+
- Single-monitor flow only (no multi-monitor support).
|
|
162
|
+
- Device strip count auto-detection is diagnostics-only; not auto-applied.
|
|
163
|
+
- Desktop-entry launch context is still preferred for reliable KWin authorization.
|
|
164
|
+
|
|
165
|
+
## License
|
|
166
|
+
|
|
167
|
+
Source-available non-commercial license — see [LICENSE](LICENSE). Redistribution terms apply; read before packaging or mirroring.
|