Files
cthulhu/CLAUDE.md
Storm Dragon 4d2561a293 Implement sleep mode functionality for Cthulhu
Add application-specific sleep mode that disables speech and events while preserving the ability to toggle back to normal operation.

Features:
- Keybinding: Cthulhu+Ctrl+Alt+Shift+Q (matches Orca)
- Per-application scope (only affects focused app)
- Suppresses all speech, braille, and event processing
- Preserves sleep mode toggle keybinding for exit
- Status messages on enter/exit

Implementation:
- New sleepmode script module in src/cthulhu/scripts/sleepmode/
- Toggle handler in default.py using script manager
- Proper autotools integration with correct installation paths
- Build system fixes for module discovery

Files modified:
- src/cthulhu/common_keyboardmap.py: Add sleep mode keybinding
- src/cthulhu/scripts/default.py: Add toggleSleepMode handler
- src/cthulhu/scripts/sleepmode/: Complete sleep mode implementation
- CLAUDE.md: Documentation for build system and sleep mode
- Fix sleepmode/Makefile.am installation path

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 14:03:10 -04:00

15 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

Cthulhu is a fork of the Orca screen reader, providing access to the graphical desktop via speech and/or braille. It's designed as a supplemental screen reader for advanced users, particularly useful for older Qt applications and specific window managers like i3.

Build System and Commands

# Build and install locally to ~/.local (no system overwrite)
./build-local.sh

# Test local installation
./test-local.sh

# Run local version
~/.local/bin/cthulhu

# Clean build artifacts and local installation
./clean-local.sh

System Build (Autotools)

# Configure and build for system installation
./autogen.sh --prefix=/usr
make
make install

# Or use CI script
ci/build_and_install.sh

Alternative Build (Python packaging)

# Using pip/hatchling
pip install -e .

Testing

# Run all regression tests
test/harness/runall.sh

# Run single test
test/harness/runone.sh <test.py> <app-name>

# Run specific app tests
test/harness/runall.sh -a /path/to/app/tests

# Coverage analysis
test/harness/runall.sh -c

# Profile mode
test/harness/runall.sh -p

Core Architecture

Main Components

  • Event System: event_manager.py, signal_manager.py - Central event handling
  • Accessibility Layer: ax_object.py, ax_utilities.py - AT-SPI object management
  • Output Systems: speech.py, braille.py - Speech and braille generation
  • Navigation: structural_navigation.py, flat_review.py - Document and screen navigation
  • Plugin System: plugin_system_manager.py - Extensible plugin architecture using pluggy

Application Scripts

Scripts in src/cthulhu/scripts/ provide application-specific behavior:

  • scripts/apps/ - Specific applications (Firefox, Thunderbird, LibreOffice)
  • scripts/toolkits/ - Toolkit support (GTK, Qt, Gecko, WebKit)
  • scripts/web/ - Web browsing enhancements

Plugin Development

System plugins in src/cthulhu/plugins/, user plugins in ~/.local/share/cthulhu/plugins/:

Basic Plugin Structure

src/cthulhu/plugins/MyPlugin/
├── __init__.py          # Package import: from .plugin import MyPlugin
├── plugin.py            # Main implementation
├── plugin.info          # Metadata
└── Makefile.am          # Build system integration

Minimal Plugin Template

from cthulhu.plugin import Plugin, cthulhu_hookimpl

class MyPlugin(Plugin):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._enabled = True
        
    @cthulhu_hookimpl
    def activate(self, plugin=None):
        if plugin is not None and plugin is not self:
            return
        # Plugin activation logic
        return True
        
    @cthulhu_hookimpl  
    def deactivate(self, plugin=None):
        if plugin is not None and plugin is not self:
            return
        # Cleanup logic
        return True

Plugin Integration Patterns

1. Keybinding Registration:

def _register_keybinding(self):
    if not self.app:
        return
    api_helper = self.app.getAPIHelper()
    self._kb_binding = api_helper.registerGestureByString(
        "Cthulhu+key", self._handler_method, "Description"
    )

2. Accessing Cthulhu APIs:

# Get current active script
state = self.app.getDynamicApiManager().getAPI('CthulhuState')
active_script = state.activeScript

# Access speech/messages
speech = self.app.getDynamicApiManager().getAPI('Speech')
messages = self.app.getDynamicApiManager().getAPI('Messages')

3. Sound Generation:

from cthulhu import sound
from cthulhu.sound_generator import Tone

# Initialize player
self._player = sound.getPlayer()

# Create and play tone
tone = Tone(duration=0.15, frequency=400, volumeMultiplier=0.7)
self._player.play(tone, interrupt=False)

4. Script Method Monkey-Patching:

def _monkey_patch_script_methods(self):
    state = self.app.getDynamicApiManager().getAPI('CthulhuState')
    if state and state.activeScript:
        script = state.activeScript
        self._original_method = script.methodName
        
        def wrapped_method(*args, **kwargs):
            result = self._original_method(*args, **kwargs)
            # Add custom logic here
            return result
            
        script.methodName = wrapped_method

Plugin Files

plugin.info format:

[Core]
Name = PluginName
Module = PluginName

[Documentation]
Description = Plugin description
Author = Author Name
Version = 1.0.0
Website = https://example.com

Makefile.am template:

pluginname_PYTHON = \
	__init__.py \
	plugin.py

pluginnamedir = $(pkgdatadir)/cthulhu/plugins/PluginName

pluginname_DATA = \
	plugin.info

EXTRA_DIST = $(pluginname_DATA)

Build Integration: Add plugin to src/cthulhu/plugins/Makefile.am SUBDIRS line.

Advanced Plugin Features

Event System Integration:

  • Register with Dynamic API: api_manager.registerAPI('MyPlugin', self)
  • Hook into script changes via monkey-patching
  • Access event manager for custom event handling

Text Analysis:

  • Use script.getTextLineAtCaret(obj) for current line
  • Access text attributes via script.utilities.getTextAttributes()
  • Leverage existing utilities like indentationDescription()

Settings Integration:

  • Access settings manager: settings_manager.getManager()
  • Create plugin-specific settings with prefixes
  • Integrate with preferences GUI if needed

Development Workflow

Contributing

Key Dependencies

  • Python 3.3+, pygobject-3.0, pluggy, gtk+-3.0
  • AT-SPI2, ATK for accessibility
  • Optional: BrlTTY/BrlAPI (braille), Speech Dispatcher, liblouis, GStreamer

Version Information

Current version in src/cthulhu/cthulhuVersion.py, codename "plugins"

Self-voicing Feature

Direct speech output via Unix socket:

echo "Hello world." | socat - UNIX-CLIENT:/tmp/cthulhu.sock
echo "<!#APPEND#!>Hello world." | socat - UNIX-CLIENT:/tmp/cthulhu.sock  # No interrupt
echo "Hello world.<#APPEND#>" | socat - UNIX-CLIENT:/tmp/cthulhu.sock    # Persistent braille

Key Directories

  • src/cthulhu/ - Core source code
  • test/ - Regression test framework with keystroke-based testing
  • po/ - Internationalization files (extensive i18n support)
  • help/ - Multi-language user documentation
  • ci/ - Continuous integration scripts

Testing Notes

The test system uses keystroke recording/playback with speech and braille output comparison. Tests are organized by application and toolkit. The testing framework automatically handles application launching and result comparison for regression testing.


ORCA vs CTHULHU COMPARISON & INTEGRATION CONSIDERATIONS

Fork History & Strategic Decisions

  • Cthulhu Origin: Forked from Orca 45 (GNOME-45 release) - git log shows initial commit a523205
  • Strategic Goals:
    • Supplemental screen reader for advanced users
    • Better support for older Qt applications
    • Enhanced window manager support (i3, etc.)
    • Plugin system with pluggy framework
    • Community-driven development

Major Architectural Differences

Build Systems

  • Cthulhu: Autotools (102 Makefile.am files) - mature, stable build system
  • Orca: Meson/Ninja (33 meson.build files, 84 legacy makefiles) - modern, faster builds
  • Integration Consideration: Should Cthulhu migrate to Meson for faster builds and better dependencies?

Plugin Architecture

  • Cthulhu: Extensive pluggy-based plugin system with 9 core plugins
  • Orca: No comparable plugin system - features are integrated directly into core
  • Strategic Value: Plugin system is Cthulhu's key differentiator - maintain this advantage

New Orca Features (v49.alpha)

  1. D-Bus Remote Controller (dbus_service.py)

    • Service: org.gnome.Orca.Service
    • Remote command execution, module access
    • Requires: dasbus library
    • Integration Value: HIGH - would enable external control of Cthulhu
  2. Spiel TTS Support (spiel.py)

    • Alternative to speech-dispatcher
    • Multi-synthesizer support (eSpeak, Piper)
    • Flatpak-based providers
    • Integration Value: MEDIUM - broader TTS options
  3. Enhanced Module Architecture

    • focus_manager.py, input_event_manager.py
    • Better separation of concerns
    • Integration Value: LOW - architectural improvement but not user-facing

Current Bug Investigation: Plugin Keybindings

[Previous debugging section remains valid - plugin keybinding integration is working but needs refinement]

Integration Recommendations

HIGH Priority - D-Bus Remote Controller

  • Benefit: External application control, automation, integration with other tools
  • Risk: LOW - self-contained feature, minimal core impact
  • Files to Port: dbus_service.py, related D-Bus infrastructure
  • Dependencies: Add dasbus to Cthulhu's requirements

MEDIUM Priority - Build System Migration

  • Benefit: Faster builds, better dependency management, alignment with GNOME ecosystem
  • Risk: MEDIUM - significant build system changes, potential disruption
  • Approach: Gradual migration, maintain autotools compatibility initially

LOW Priority - Spiel Integration

  • Benefit: More TTS options, potentially better voice quality
  • Risk: MEDIUM - additional complexity, Flatpak dependencies
  • Approach: Optional feature, don't replace speech-dispatcher by default

Files Requiring Attention for Integration

D-Bus Remote Controller Integration:

# Core files to review and potentially port:
src/orca/dbus_service.py           # Main D-Bus service implementation
README-REMOTE-CONTROLLER.md       # API documentation and examples

Build System Files:

# Modern build configuration to consider:
meson.build                        # Root build configuration
meson_options.txt                  # Build options
subprojects/spiel.wrap            # Subproject integration

Strategic Questions for Decision

  1. Build System: Should Cthulhu migrate to Meson for better GNOME ecosystem alignment?
  2. D-Bus Interface: High value feature - should this be priority #1 for integration?
  3. Plugin System: How to maintain Cthulhu's plugin advantage while integrating Orca improvements?
  4. Version Strategy: Selective feature backporting vs. major version sync?

D-Bus Remote Controller Integration

NEW FEATURE: D-Bus Service for Remote Control

Cthulhu now includes a D-Bus service (ported from Orca v49.alpha) for external control and automation:

  • Service Name: org.stormux.Cthulhu.Service
  • Object Path: /org/stormux/Cthulhu/Service
  • Dependency: dasbus library (automatically detected)

Testing D-Bus Functionality

# Start Cthulhu with D-Bus service
~/.local/bin/cthulhu

# Test service availability
busctl --user list | grep Cthulhu

# Get Cthulhu version via D-Bus
busctl --user call org.stormux.Cthulhu.Service /org/stormux/Cthulhu/Service org.stormux.Cthulhu.Service GetVersion

# Present message to user via D-Bus
busctl --user call org.stormux.Cthulhu.Service /org/stormux/Cthulhu/Service org.stormux.Cthulhu.Service PresentMessage s "Hello from D-Bus"

# List available modules and commands
busctl --user call org.stormux.Cthulhu.Service /org/stormux/Cthulhu/Service org.stormux.Cthulhu.Service ListModules

Integration Status

  • Core D-Bus service: Fully ported and integrated
  • Service lifecycle: Automatic start/shutdown with Cthulhu
  • Message presentation: PresentMessage() method working - FULLY FUNCTIONAL
  • Version info: GetVersion() method working - FULLY FUNCTIONAL
  • Circular import issues: All resolved - Cthulhu imports work correctly
  • GDK version conflicts: Fixed with proper gi.require_version calls
  • Presenter singleton patterns: Fixed with lazy initialization
  • Settings manager backend: Fixed with proper activation sequence
  • ATSPI registry startup: Fixed with deferred D-Bus service initialization
  • API naming conventions: All Orca→Cthulhu API differences resolved
  • 🔄 Module registration: Ready for individual managers to register D-Bus commands
  • 🔄 Plugin integration: Plugins can expose D-Bus commands using decorators

COMPLETED - D-Bus Remote Controller Integration

The D-Bus Remote Controller from Orca v49.alpha has been successfully integrated into Cthulhu and is fully functional.

Root Cause of Issues: D-Bus service startup timing conflicts with ATSPI registry initialization.

Solution Implemented:

  • Deferred D-Bus service startup using GObject.idle_add() after ATSPI event loop is running
  • Fixed all API naming convention differences between Orca and Cthulhu

Files Modified for D-Bus Integration:

  • src/cthulhu/dbus_service.py (NEW FILE) - Complete D-Bus service port with Cthulhu API fixes
  • src/cthulhu/input_event.py - Added RemoteControllerEvent + GDK version fix
  • src/cthulhu/cthulhu.py - D-Bus integration + lazy BrailleEvent import + settings manager activation + deferred startup
  • src/cthulhu/Makefile.am - Added dbus_service.py to build
  • Multiple presenter files - Converted to lazy initialization pattern
  • src/cthulhu/keybindings.py - Fixed GDK version requirement
  • README-REMOTE-CONTROLLER.md (NEW FILE) - Complete documentation with examples

API Fixes Applied:

  • debug.print_messagedebug.printMessage
  • script_manager.get_manager()script_manager.getManager()
  • get_active_script()cthulhu_state.activeScript
  • get_default_script()getDefaultScript()

Bug Fixes Applied

  • Fixed circular imports in presenter modules (learn_mode_presenter, notification_presenter, etc.)
  • Added lazy imports for BrailleEvent to break cthulhu.py ↔ input_event.py cycle
  • Fixed GDK version conflicts by adding gi.require_version("Gdk", "3.0") to input_event.py
  • Changed all presenter singleton patterns to lazy initialization to prevent import-time issues
  • Added settings manager activation before loadUserSettings() to fix backend initialization

Commands for Analysis

# Compare specific features between projects
diff -r /home/storm/devel/cthulhu/src/cthulhu /home/storm/devel/orca/src/orca

# Test Orca's new features
cd /home/storm/devel/orca && meson setup _build && meson compile -C _build

# Test D-Bus interface
# (requires running Orca instance with D-Bus support)