diff --git a/CMakeLists.txt b/CMakeLists.txt index ea28825..90073db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.20) project(wine_access LANGUAGES C CXX) include(GNUInstallDirs) -set(WINE_ACCESS_INSTALL_DIR "${CMAKE_INSTALL_LIBEXECDIR}/cthulhu/wine" CACHE PATH +set(WINE_ACCESS_INSTALL_DIR "${CMAKE_INSTALL_LIBEXECDIR}/wine-access" CACHE PATH "Installation directory for the Wine helper and its Winelib sidecar") find_package(PkgConfig REQUIRED) pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) @@ -51,14 +51,14 @@ add_custom_command( DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/nvdaController.idl" VERBATIM) -add_executable(cthulhu-wine-access reader_events.cpp msaa_events.cpp main.cpp foreground_focus.cpp list_view.cpp native_items.cpp review_capture.cpp review_x11.cpp review_service.cpp "${generated_server}") -add_dependencies(cthulhu-wine-access wine-access-menu wine-access-menu32) -target_compile_features(cthulhu-wine-access PRIVATE cxx_std_20) -target_include_directories(cthulhu-wine-access PRIVATE "${generated_dir}") -target_link_libraries(cthulhu-wine-access PRIVATE +add_executable(wine-access reader_events.cpp msaa_events.cpp main.cpp foreground_focus.cpp list_view.cpp native_items.cpp review_capture.cpp review_x11.cpp review_service.cpp "${generated_server}") +add_dependencies(wine-access wine-access-menu wine-access-menu32) +target_compile_features(wine-access PRIVATE cxx_std_20) +target_include_directories(wine-access PRIVATE "${generated_dir}") +target_link_libraries(wine-access PRIVATE PkgConfig::GIO PkgConfig::XCB oleacc ole32 oleaut32 rpcrt4 user32 gdi32 shell32) -target_link_options(cthulhu-wine-access PRIVATE -mwindows) -target_compile_options(cthulhu-wine-access PRIVATE +target_link_options(wine-access PRIVATE -mwindows) +target_compile_options(wine-access PRIVATE $<$:-Wall -Wextra>) include(CTest) @@ -115,10 +115,10 @@ endif() # installation looks for the Linux target name, so install both emitted # artifacts explicitly and keep them together for Wine to resolve. install(PROGRAMS - "${CMAKE_CURRENT_BINARY_DIR}/cthulhu-wine-access.exe" + "${CMAKE_CURRENT_BINARY_DIR}/wine-access.exe" DESTINATION "${WINE_ACCESS_INSTALL_DIR}") install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/cthulhu-wine-access.exe.so" + "${CMAKE_CURRENT_BINARY_DIR}/wine-access.exe.so" "${menu_hook}" "${menu_hook32}" "${menu_host32}" diff --git a/README.md b/README.md index 22bdb1a..abac7ce 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Wine Access -`wine-access` is the standalone Wine-hosted accessibility helper for Cthulhu -and readers that implement its Wine D-Bus protocol. An Orca endpoint is +`wine-access` is a standalone Wine-hosted accessibility helper for screen +readers that implement its Wine D-Bus protocol. An Orca endpoint is available for future Orca-side integration; stock Orca does not implement the required Wine methods. @@ -34,8 +34,8 @@ imports remain valid across reader restarts. Close and reopen applications after updating Wine Access to load the new hooks. `--no-dialog-reader` disables these hooks along with standard control reading. -The executable is named `cthulhu-wine-access.exe` for compatibility with the -Cthulhu supervisor. +The executable is named `wine-access.exe`. Its launcher, Winelib sidecar, +and native hooks share a reader-independent installation directory. ## Requirements @@ -60,8 +60,8 @@ provides package-managed installation and upgrades. Choose one installation method to avoid a local copy taking precedence over the system package. The convenience script builds in `./build`. Running it as a user installs to -`$HOME/.local/libexec/cthulhu/wine`; running it as root installs system wide to -`/usr/libexec/cthulhu/wine`: +`$HOME/.local/libexec/wine-access`; running it as root installs system wide to +`/usr/libexec/wine-access`: ```sh ./build.sh @@ -91,20 +91,26 @@ helper directory: That installs the helper and its Winelib sidecar as: ```text -$prefix/libexec/cthulhu/wine/cthulhu-wine-access.exe -$prefix/libexec/cthulhu/wine/cthulhu-wine-access.exe.so -$prefix/libexec/cthulhu/wine/wine-access-menu.dll -$prefix/libexec/cthulhu/wine/wine-access-menu32.dll -$prefix/libexec/cthulhu/wine/wine-access-menu-host32.exe +$prefix/libexec/wine-access/wine-access.exe +$prefix/libexec/wine-access/wine-access.exe.so +$prefix/libexec/wine-access/wine-access-menu.dll +$prefix/libexec/wine-access/wine-access-menu32.dll +$prefix/libexec/wine-access/wine-access-menu-host32.exe ``` For Cthulhu, either set `CTHULHU_WINE_ACCESS_HELPER` to the installed -executable or place it at: +executable or install it under one of these prefixes: ```text -$HOME/.local/libexec/cthulhu/wine/cthulhu-wine-access.exe +$HOME/.local/libexec/wine-access/wine-access.exe +/usr/local/libexec/wine-access/wine-access.exe +/usr/libexec/wine-access/wine-access.exe ``` +Cthulhu checks the environment override first, then the user installation, +`/usr/local`, `/usr`, and finally `PATH`. Its existing Cthulhu-specific user +and system paths remain supported; avoid leaving stale user copies installed. + The helper is started automatically when Cthulhu detects an active Wine loader for the same user and prefix. It requires the selected reader service to be running; it exits if that service is unavailable. @@ -115,7 +121,7 @@ The default invocation and `--reader cthulhu` use the existing Cthulhu endpoint. An Orca-side integration can launch the helper in the application's Wine prefix: ```sh -WINEPREFIX=/path/to/prefix /path/to/cthulhu-wine-access.exe --reader orca +WINEPREFIX=/path/to/prefix /path/to/wine-access.exe --reader orca ``` | Reader | Session bus name and interface | Object path | @@ -129,7 +135,7 @@ with `--reader-path` and `--reader-interface`; omitted fields retain the selected reader's defaults. For an extension class named `WineAccess`: ```sh -WINEPREFIX=/path/to/prefix /path/to/cthulhu-wine-access.exe --reader orca \ +WINEPREFIX=/path/to/prefix /path/to/wine-access.exe --reader orca \ --reader-path /org/gnome/Orca1/Service/WineAccess \ --reader-interface org.gnome.Orca1.WineAccess ``` diff --git a/build.sh b/build.sh index 43381b7..5ad7b82 100755 --- a/build.sh +++ b/build.sh @@ -32,8 +32,8 @@ else defaultPrefix="${HOME}/.local" fi prefix=${2:-"$defaultPrefix"} -installDir="${prefix%/}/libexec/cthulhu/wine" -installedFiles=(cthulhu-wine-access.exe cthulhu-wine-access.exe.so wine-access-menu.dll +installDir="${prefix%/}/libexec/wine-access" +installedFiles=(wine-access.exe wine-access.exe.so wine-access-menu.dll wine-access-menu32.dll wine-access-menu-host32.exe) has_installation() { @@ -53,7 +53,7 @@ if "$removeInstalled"; then rm -f -- "$installDir/$installedFile" done echo "Removed Wine Access from $installDir" - elif (( EUID != 0 && $# < 2 )) && has_installation "$systemPrefix/libexec/cthulhu/wine"; then + elif (( EUID != 0 && $# < 2 )) && has_installation "$systemPrefix/libexec/wine-access"; then echo "Only a system-wide installation was found. Run: sudo ./build.sh -r" >&2 exit 1 else @@ -112,6 +112,6 @@ cmake \ -DCMAKE_TOOLCHAIN_FILE="$projectDir/winelib-toolchain.cmake" \ -DCMAKE_INSTALL_PREFIX="$prefix" \ -DCMAKE_INSTALL_LIBEXECDIR:PATH=libexec \ - -DWINE_ACCESS_INSTALL_DIR:PATH=libexec/cthulhu/wine + -DWINE_ACCESS_INSTALL_DIR:PATH=libexec/wine-access cmake --build "$buildDir" --parallel cmake --install "$buildDir" diff --git a/distro-packages/ArchLinux/wine-access-git/PKGBUILD b/distro-packages/ArchLinux/wine-access-git/PKGBUILD index 1f2aaf7..40d52fb 100644 --- a/distro-packages/ArchLinux/wine-access-git/PKGBUILD +++ b/distro-packages/ArchLinux/wine-access-git/PKGBUILD @@ -1,8 +1,8 @@ # Maintainer: Storm Dragon pkgname=wine-access-git -pkgver=r35.g95cb78d +pkgver=r37.g417ee40 pkgrel=1 -pkgdesc='Wine accessibility helper with MSAA, NVDA Controller, and Tolk compatibility for Cthulhu' +pkgdesc='Wine accessibility helper with MSAA, NVDA Controller, and Tolk compatibility for screen readers' arch=('x86_64') url='https://git.stormux.org/storm/wine-access' license=('LGPL-2.1-or-later') @@ -40,7 +40,7 @@ package() { DESTDIR="$pkgdir" cmake --install "$srcdir/build" # CMake installs these artifacts as files; Wine's launcher must be executable. - chmod 755 "$pkgdir/usr/libexec/cthulhu/wine/cthulhu-wine-access.exe" + chmod 755 "$pkgdir/usr/libexec/wine-access/wine-access.exe" install -Dm644 "$srcdir/wine-access/README.md" \ "$pkgdir/usr/share/doc/wine-access/README.md" } diff --git a/distro-packages/ArchLinux/wine-access-git/README.md b/distro-packages/ArchLinux/wine-access-git/README.md index e8908e5..818ff06 100644 --- a/distro-packages/ArchLinux/wine-access-git/README.md +++ b/distro-packages/ArchLinux/wine-access-git/README.md @@ -13,7 +13,7 @@ Before the remote exists, build from the committed sources in your local checkout instead: ```sh -WINE_ACCESS_GIT_URL=file:///home/storm/git/wine-access makepkg -si +WINE_ACCESS_GIT_URL=file:///path/to/wine-access makepkg -si ``` Git sources include committed files only. Adjust that path if your checkout is @@ -25,21 +25,23 @@ WINE_ACCESS_GIT_URL=https://git.stormux.org/storm/wine-access.git makepkg -si The package installs the Winelib launcher, its sidecar, both native menu hook DLLs, and the 32-bit menu host -under `/usr/libexec/cthulhu/wine/`. It provides and conflicts with the older -`cthulhu-wine-access` helper, including `cthulhu-wine-access-git`, so pacman +under `/usr/libexec/wine-access/`. It provides and conflicts with the older +`cthulhu-wine-access` helper, so pacman can replace that package in the installation transaction. Use this package for subsequent updates rather than also installing through `build.sh`. If an earlier local installation exists under -`~/.local/libexec/cthulhu/wine`, remove it with `./build.sh -r` from the project -root before using the package: readers may prefer that local copy. Do not +`~/.local/libexec/wine-access`, remove it with `./build.sh -r` from the project +root before using the package: readers may prefer that local copy. For the older +`~/.local/libexec/cthulhu/wine` layout, use the old version of `build.sh -r`. Do not remove package-owned system files with `build.sh -r`. If your reader does not discover the system location automatically, set this in the environment of the reader's service: ```sh -export CTHULHU_WINE_ACCESS_HELPER=/usr/libexec/cthulhu/wine/cthulhu-wine-access.exe +export CTHULHU_WINE_ACCESS_HELPER=/usr/libexec/wine-access/wine-access.exe ``` -The helper requires a running reader implementing the Cthulhu D-Bus service. +The helper requires a running reader implementing its Wine D-Bus protocol; +see the project README for reader selection and endpoint overrides. diff --git a/tests/controller_integration.py b/tests/controller_integration.py index e5c73ca..a4f46b1 100644 --- a/tests/controller_integration.py +++ b/tests/controller_integration.py @@ -83,7 +83,7 @@ with tempfile.TemporaryDirectory(prefix="wine-access-controller-") as temporary: str(source / "tests/controller_fixture.c"), "-lrpcrt4"], check=True) helper = None client = None - helperCommand = [str(build / "cthulhu-wine-access.exe"), "--no-dialog-reader", + helperCommand = [str(build / "wine-access.exe"), "--no-dialog-reader", *endpointArguments, *(["--reader", args.reader] if args.reader else [])] try: @@ -98,7 +98,7 @@ with tempfile.TemporaryDirectory(prefix="wine-access-controller-") as temporary: ["--reader-interface"], ["--reader-interface", ""], ["--reader-interface", "WineAccess"], ["--reader-interface", "org.example.Bad-Interface"]): - result = subprocess.run([str(build / "cthulhu-wine-access.exe"), *readerArgs], + result = subprocess.run([str(build / "wine-access.exe"), *readerArgs], env=env, timeout=5) assert result.returncode == 1, "invalid endpoint argument was accepted" assert name_call("RequestName", busName) == 1 diff --git a/tests/event_stall_integration.py b/tests/event_stall_integration.py index b30727e..d9d6a28 100644 --- a/tests/event_stall_integration.py +++ b/tests/event_stall_integration.py @@ -78,7 +78,7 @@ with tempfile.TemporaryDirectory(prefix="wine-event-stall-") as temporary: children = [] try: subprocess.run(["wineboot", "-u"], env=env, check=True, timeout=45) - helper = subprocess.Popen([str(build / "cthulhu-wine-access.exe"), "--no-controller", + helper = subprocess.Popen([str(build / "wine-access.exe"), "--no-controller", "--reader", args.reader], env=env) children.append(helper) time.sleep(1) diff --git a/tests/menu_integration.py b/tests/menu_integration.py index 9c6064e..5fc9a47 100644 --- a/tests/menu_integration.py +++ b/tests/menu_integration.py @@ -115,7 +115,7 @@ with tempfile.TemporaryDirectory(prefix="wine-access-menus-") as temporary: while not ready.exists() and app.poll() is None and time.monotonic() < deadline: time.sleep(0.01) assert ready.exists(), "editor did not become ready before helper attachment" - helper = subprocess.Popen([str(build / "cthulhu-wine-access.exe"), "--no-controller", *readerArguments], env=env) + helper = subprocess.Popen([str(build / "wine-access.exe"), "--no-controller", *readerArguments], env=env) # Allow the helper to register its bridge before opening the fixture. deadline = time.monotonic() + 1 while time.monotonic() < deadline: @@ -133,7 +133,7 @@ with tempfile.TemporaryDirectory(prefix="wine-access-menus-") as temporary: if args.restart_helper and not restarted and any(e[0].endswith(":text") for e in events): helper.terminate() helper.wait(timeout=5) - helper = subprocess.Popen([str(build / "cthulhu-wine-access.exe"), "--no-controller", *readerArguments], env=env) + helper = subprocess.Popen([str(build / "wine-access.exe"), "--no-controller", *readerArguments], env=env) restarted = True time.sleep(0.01) assert app.poll() == 0, "fixture failed or timed out" @@ -337,7 +337,7 @@ with tempfile.TemporaryDirectory(prefix="wine-access-menus-") as temporary: assert any(e[2] == "Return to control" and e[3] == "button" for e in events), "control focus missing" assert any(e[2] == "Application-owned accessibility" and e[3] == "client" for e in events), "marshaled application MSAA object unavailable" - subprocess.run([str(build / "cthulhu-wine-access.exe"), + subprocess.run([str(build / "wine-access.exe"), "--no-dialog-reader", "--no-controller"], env=env, check=True, timeout=5) print("PASS: native and nested menus, context menus, shortcuts, states, " diff --git a/tests/notification_integration.py b/tests/notification_integration.py index ab1d03a..c696ff1 100644 --- a/tests/notification_integration.py +++ b/tests/notification_integration.py @@ -67,7 +67,7 @@ with tempfile.TemporaryDirectory(prefix="wine-access-notifications-") as tempora helper = app = None try: subprocess.run(["wineboot", "-u"], env=env, check=True, timeout=45) - helper = subprocess.Popen([str(build / "cthulhu-wine-access.exe"), "--no-controller", + helper = subprocess.Popen([str(build / "wine-access.exe"), "--no-controller", "--reader", args.reader], env=env) time.sleep(.5) app = subprocess.Popen(["wine", str(fixture), diff --git a/tests/reader_stall_integration.py b/tests/reader_stall_integration.py index a889355..8e860da 100644 --- a/tests/reader_stall_integration.py +++ b/tests/reader_stall_integration.py @@ -83,7 +83,7 @@ with tempfile.TemporaryDirectory(prefix="wine-reader-stall-") as temporary: children = [] try: subprocess.run(["wineboot", "-u"], env=env, check=True, timeout=45) - helper = subprocess.Popen([str(build / "cthulhu-wine-access.exe"), "--no-controller"], env=env) + helper = subprocess.Popen([str(build / "wine-access.exe"), "--no-controller"], env=env) children.append(helper) time.sleep(1) app = subprocess.Popen(["wine", str(fixture)], env=env) diff --git a/tests/review_integration.py b/tests/review_integration.py index 905868c..ff42b6d 100644 --- a/tests/review_integration.py +++ b/tests/review_integration.py @@ -94,7 +94,7 @@ with tempfile.TemporaryDirectory(prefix='wine-review-wire-') as temporary: return result[0] try: subprocess.run(['wineboot','-u'],env=env,check=True,timeout=45) - helper = subprocess.Popen([str(build/'cthulhu-wine-access.exe'),'--no-controller',*readerArguments],env=env) + helper = subprocess.Popen([str(build/'wine-access.exe'),'--no-controller',*readerArguments],env=env) app = subprocess.Popen(['wine',str(fixture)],env=env) pump_until(lambda: any(f[4]=='Wine review fixture' for f in focuses.values()),8) reply, elapsed = capture() @@ -187,7 +187,7 @@ with tempfile.TemporaryDirectory(prefix='wine-review-wire-') as temporary: helper.terminate(); helper.wait(timeout=3) subprocess.run(['wine',str(fixture),'--check-remote'],env=env,check=True,timeout=5) print('PASS: test_native_buffer_lifetime_after_helper_stop') - helper=subprocess.Popen([str(build/'cthulhu-wine-access.exe'),'--no-controller',*readerArguments],env=env) + helper=subprocess.Popen([str(build/'wine-access.exe'),'--no-controller',*readerArguments],env=env) pump_until(lambda:any(s != sender and f[4]=='Wine review fixture' for s,f in focuses.items()),5) focuses.pop(sender,None) configure(7) @@ -215,7 +215,7 @@ with tempfile.TemporaryDirectory(prefix='wine-review-wire-') as temporary: connection.unregister_object(registration) registration = connection.register_object(path,Gio.DBusNodeInfo.new_for_xml(interface_xml(False)).interfaces[0],record,None,None) events.clear() - helper = subprocess.Popen([str(build/'cthulhu-wine-access.exe'),'--no-controller',*readerArguments],env=env) + helper = subprocess.Popen([str(build/'wine-access.exe'),'--no-controller',*readerArguments],env=env) end=time.monotonic()+1 while time.monotonic()