Make wine-access more generic, not specifically cthulhu pathed.

This commit is contained in:
Storm Dragon committed 2026-10-14 16:19:52 -04:00
1 parent 417ee40dda
commit ed8c8e2467
11 files changed
+58 -50

No files matched your search

+10 -10
View File
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.20)
project(wine_access LANGUAGES C CXX) project(wine_access LANGUAGES C CXX)
include(GNUInstallDirs) 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") "Installation directory for the Wine helper and its Winelib sidecar")
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
@@ -51,14 +51,14 @@ add_custom_command(
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/nvdaController.idl" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/nvdaController.idl"
VERBATIM) 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_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(cthulhu-wine-access wine-access-menu wine-access-menu32) add_dependencies(wine-access wine-access-menu wine-access-menu32)
target_compile_features(cthulhu-wine-access PRIVATE cxx_std_20) target_compile_features(wine-access PRIVATE cxx_std_20)
target_include_directories(cthulhu-wine-access PRIVATE "${generated_dir}") target_include_directories(wine-access PRIVATE "${generated_dir}")
target_link_libraries(cthulhu-wine-access PRIVATE target_link_libraries(wine-access PRIVATE
PkgConfig::GIO PkgConfig::XCB oleacc ole32 oleaut32 rpcrt4 user32 gdi32 shell32) PkgConfig::GIO PkgConfig::XCB oleacc ole32 oleaut32 rpcrt4 user32 gdi32 shell32)
target_link_options(cthulhu-wine-access PRIVATE -mwindows) target_link_options(wine-access PRIVATE -mwindows)
target_compile_options(cthulhu-wine-access PRIVATE target_compile_options(wine-access PRIVATE
$<$<COMPILE_LANGUAGE:C,CXX>:-Wall -Wextra>) $<$<COMPILE_LANGUAGE:C,CXX>:-Wall -Wextra>)
include(CTest) include(CTest)
@@ -115,10 +115,10 @@ endif()
# installation looks for the Linux target name, so install both emitted # installation looks for the Linux target name, so install both emitted
# artifacts explicitly and keep them together for Wine to resolve. # artifacts explicitly and keep them together for Wine to resolve.
install(PROGRAMS install(PROGRAMS
"${CMAKE_CURRENT_BINARY_DIR}/cthulhu-wine-access.exe" "${CMAKE_CURRENT_BINARY_DIR}/wine-access.exe"
DESTINATION "${WINE_ACCESS_INSTALL_DIR}") DESTINATION "${WINE_ACCESS_INSTALL_DIR}")
install(FILES install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/cthulhu-wine-access.exe.so" "${CMAKE_CURRENT_BINARY_DIR}/wine-access.exe.so"
"${menu_hook}" "${menu_hook}"
"${menu_hook32}" "${menu_hook32}"
"${menu_host32}" "${menu_host32}"
+21 -15
View File
@@ -1,7 +1,7 @@
# Wine Access # Wine Access
`wine-access` is the standalone Wine-hosted accessibility helper for Cthulhu `wine-access` is a standalone Wine-hosted accessibility helper for screen
and readers that implement its Wine D-Bus protocol. An Orca endpoint is readers that implement its Wine D-Bus protocol. An Orca endpoint is
available for future Orca-side integration; stock Orca does not implement available for future Orca-side integration; stock Orca does not implement
the required Wine methods. 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 updating Wine Access to load the new hooks. `--no-dialog-reader` disables these
hooks along with standard control reading. hooks along with standard control reading.
The executable is named `cthulhu-wine-access.exe` for compatibility with the The executable is named `wine-access.exe`. Its launcher, Winelib sidecar,
Cthulhu supervisor. and native hooks share a reader-independent installation directory.
## Requirements ## 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. 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 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 `$HOME/.local/libexec/wine-access`; running it as root installs system wide to
`/usr/libexec/cthulhu/wine`: `/usr/libexec/wine-access`:
```sh ```sh
./build.sh ./build.sh
@@ -91,20 +91,26 @@ helper directory:
That installs the helper and its Winelib sidecar as: That installs the helper and its Winelib sidecar as:
```text ```text
$prefix/libexec/cthulhu/wine/cthulhu-wine-access.exe $prefix/libexec/wine-access/wine-access.exe
$prefix/libexec/cthulhu/wine/cthulhu-wine-access.exe.so $prefix/libexec/wine-access/wine-access.exe.so
$prefix/libexec/cthulhu/wine/wine-access-menu.dll $prefix/libexec/wine-access/wine-access-menu.dll
$prefix/libexec/cthulhu/wine/wine-access-menu32.dll $prefix/libexec/wine-access/wine-access-menu32.dll
$prefix/libexec/cthulhu/wine/wine-access-menu-host32.exe $prefix/libexec/wine-access/wine-access-menu-host32.exe
``` ```
For Cthulhu, either set `CTHULHU_WINE_ACCESS_HELPER` to the installed 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 ```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 The helper is started automatically when Cthulhu detects an active Wine
loader for the same user and prefix. It requires the selected reader service loader for the same user and prefix. It requires the selected reader service
to be running; it exits if that service is unavailable. 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: An Orca-side integration can launch the helper in the application's Wine prefix:
```sh ```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 | | 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`: selected reader's defaults. For an extension class named `WineAccess`:
```sh ```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-path /org/gnome/Orca1/Service/WineAccess \
--reader-interface org.gnome.Orca1.WineAccess --reader-interface org.gnome.Orca1.WineAccess
``` ```
+4 -4
View File
@@ -32,8 +32,8 @@ else
defaultPrefix="${HOME}/.local" defaultPrefix="${HOME}/.local"
fi fi
prefix=${2:-"$defaultPrefix"} prefix=${2:-"$defaultPrefix"}
installDir="${prefix%/}/libexec/cthulhu/wine" installDir="${prefix%/}/libexec/wine-access"
installedFiles=(cthulhu-wine-access.exe cthulhu-wine-access.exe.so wine-access-menu.dll installedFiles=(wine-access.exe wine-access.exe.so wine-access-menu.dll
wine-access-menu32.dll wine-access-menu-host32.exe) wine-access-menu32.dll wine-access-menu-host32.exe)
has_installation() { has_installation() {
@@ -53,7 +53,7 @@ if "$removeInstalled"; then
rm -f -- "$installDir/$installedFile" rm -f -- "$installDir/$installedFile"
done done
echo "Removed Wine Access from $installDir" 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 echo "Only a system-wide installation was found. Run: sudo ./build.sh -r" >&2
exit 1 exit 1
else else
@@ -112,6 +112,6 @@ cmake \
-DCMAKE_TOOLCHAIN_FILE="$projectDir/winelib-toolchain.cmake" \ -DCMAKE_TOOLCHAIN_FILE="$projectDir/winelib-toolchain.cmake" \
-DCMAKE_INSTALL_PREFIX="$prefix" \ -DCMAKE_INSTALL_PREFIX="$prefix" \
-DCMAKE_INSTALL_LIBEXECDIR:PATH=libexec \ -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 --build "$buildDir" --parallel
cmake --install "$buildDir" cmake --install "$buildDir"
@@ -1,8 +1,8 @@
# Maintainer: Storm Dragon <storm_dragon@stormux.org> # Maintainer: Storm Dragon <storm_dragon@stormux.org>
pkgname=wine-access-git pkgname=wine-access-git
pkgver=r35.g95cb78d pkgver=r37.g417ee40
pkgrel=1 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') arch=('x86_64')
url='https://git.stormux.org/storm/wine-access' url='https://git.stormux.org/storm/wine-access'
license=('LGPL-2.1-or-later') license=('LGPL-2.1-or-later')
@@ -40,7 +40,7 @@ package() {
DESTDIR="$pkgdir" cmake --install "$srcdir/build" DESTDIR="$pkgdir" cmake --install "$srcdir/build"
# CMake installs these artifacts as files; Wine's launcher must be executable. # 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" \ install -Dm644 "$srcdir/wine-access/README.md" \
"$pkgdir/usr/share/doc/wine-access/README.md" "$pkgdir/usr/share/doc/wine-access/README.md"
} }
@@ -13,7 +13,7 @@ Before the remote exists, build from the committed sources in your local
checkout instead: checkout instead:
```sh ```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 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 The package installs the Winelib launcher, its sidecar, both native menu hook
DLLs, and the 32-bit menu host DLLs, and the 32-bit menu host
under `/usr/libexec/cthulhu/wine/`. It provides and conflicts with the older under `/usr/libexec/wine-access/`. It provides and conflicts with the older
`cthulhu-wine-access` helper, including `cthulhu-wine-access-git`, so pacman `cthulhu-wine-access` helper, so pacman
can replace that package in the installation transaction. can replace that package in the installation transaction.
Use this package for subsequent updates rather than also installing through Use this package for subsequent updates rather than also installing through
`build.sh`. If an earlier local installation exists under `build.sh`. If an earlier local installation exists under
`~/.local/libexec/cthulhu/wine`, remove it with `./build.sh -r` from the project `~/.local/libexec/wine-access`, remove it with `./build.sh -r` from the project
root before using the package: readers may prefer that local copy. Do not 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`. remove package-owned system files with `build.sh -r`.
If your reader does not discover the system If your reader does not discover the system
location automatically, set this in the environment of the reader's service: location automatically, set this in the environment of the reader's service:
```sh ```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.
+2 -2
View File
@@ -83,7 +83,7 @@ with tempfile.TemporaryDirectory(prefix="wine-access-controller-") as temporary:
str(source / "tests/controller_fixture.c"), "-lrpcrt4"], check=True) str(source / "tests/controller_fixture.c"), "-lrpcrt4"], check=True)
helper = None helper = None
client = None client = None
helperCommand = [str(build / "cthulhu-wine-access.exe"), "--no-dialog-reader", helperCommand = [str(build / "wine-access.exe"), "--no-dialog-reader",
*endpointArguments, *endpointArguments,
*(["--reader", args.reader] if args.reader else [])] *(["--reader", args.reader] if args.reader else [])]
try: try:
@@ -98,7 +98,7 @@ with tempfile.TemporaryDirectory(prefix="wine-access-controller-") as temporary:
["--reader-interface"], ["--reader-interface", ""], ["--reader-interface"], ["--reader-interface", ""],
["--reader-interface", "WineAccess"], ["--reader-interface", "WineAccess"],
["--reader-interface", "org.example.Bad-Interface"]): ["--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) env=env, timeout=5)
assert result.returncode == 1, "invalid endpoint argument was accepted" assert result.returncode == 1, "invalid endpoint argument was accepted"
assert name_call("RequestName", busName) == 1 assert name_call("RequestName", busName) == 1
+1 -1
View File
@@ -78,7 +78,7 @@ with tempfile.TemporaryDirectory(prefix="wine-event-stall-") as temporary:
children = [] children = []
try: try:
subprocess.run(["wineboot", "-u"], env=env, check=True, timeout=45) 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) "--reader", args.reader], env=env)
children.append(helper) children.append(helper)
time.sleep(1) time.sleep(1)
+3 -3
View File
@@ -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: while not ready.exists() and app.poll() is None and time.monotonic() < deadline:
time.sleep(0.01) time.sleep(0.01)
assert ready.exists(), "editor did not become ready before helper attachment" 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. # Allow the helper to register its bridge before opening the fixture.
deadline = time.monotonic() + 1 deadline = time.monotonic() + 1
while time.monotonic() < deadline: 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): if args.restart_helper and not restarted and any(e[0].endswith(":text") for e in events):
helper.terminate() helper.terminate()
helper.wait(timeout=5) 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 restarted = True
time.sleep(0.01) time.sleep(0.01)
assert app.poll() == 0, "fixture failed or timed out" 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] == "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" assert any(e[2] == "Application-owned accessibility" and e[3] == "client"
for e in events), "marshaled application MSAA object unavailable" 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"], "--no-dialog-reader", "--no-controller"],
env=env, check=True, timeout=5) env=env, check=True, timeout=5)
print("PASS: native and nested menus, context menus, shortcuts, states, " print("PASS: native and nested menus, context menus, shortcuts, states, "
+1 -1
View File
@@ -67,7 +67,7 @@ with tempfile.TemporaryDirectory(prefix="wine-access-notifications-") as tempora
helper = app = None helper = app = None
try: try:
subprocess.run(["wineboot", "-u"], env=env, check=True, timeout=45) 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) "--reader", args.reader], env=env)
time.sleep(.5) time.sleep(.5)
app = subprocess.Popen(["wine", str(fixture), app = subprocess.Popen(["wine", str(fixture),
+1 -1
View File
@@ -83,7 +83,7 @@ with tempfile.TemporaryDirectory(prefix="wine-reader-stall-") as temporary:
children = [] children = []
try: try:
subprocess.run(["wineboot", "-u"], env=env, check=True, timeout=45) 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) children.append(helper)
time.sleep(1) time.sleep(1)
app = subprocess.Popen(["wine", str(fixture)], env=env) app = subprocess.Popen(["wine", str(fixture)], env=env)
+3 -3
View File
@@ -94,7 +94,7 @@ with tempfile.TemporaryDirectory(prefix='wine-review-wire-') as temporary:
return result[0] return result[0]
try: try:
subprocess.run(['wineboot','-u'],env=env,check=True,timeout=45) 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) app = subprocess.Popen(['wine',str(fixture)],env=env)
pump_until(lambda: any(f[4]=='Wine review fixture' for f in focuses.values()),8) pump_until(lambda: any(f[4]=='Wine review fixture' for f in focuses.values()),8)
reply, elapsed = capture() reply, elapsed = capture()
@@ -187,7 +187,7 @@ with tempfile.TemporaryDirectory(prefix='wine-review-wire-') as temporary:
helper.terminate(); helper.wait(timeout=3) helper.terminate(); helper.wait(timeout=3)
subprocess.run(['wine',str(fixture),'--check-remote'],env=env,check=True,timeout=5) subprocess.run(['wine',str(fixture),'--check-remote'],env=env,check=True,timeout=5)
print('PASS: test_native_buffer_lifetime_after_helper_stop') 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) pump_until(lambda:any(s != sender and f[4]=='Wine review fixture' for s,f in focuses.items()),5)
focuses.pop(sender,None) focuses.pop(sender,None)
configure(7) configure(7)
@@ -215,7 +215,7 @@ with tempfile.TemporaryDirectory(prefix='wine-review-wire-') as temporary:
connection.unregister_object(registration) connection.unregister_object(registration)
registration = connection.register_object(path,Gio.DBusNodeInfo.new_for_xml(interface_xml(False)).interfaces[0],record,None,None) registration = connection.register_object(path,Gio.DBusNodeInfo.new_for_xml(interface_xml(False)).interfaces[0],record,None,None)
events.clear() 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 end=time.monotonic()+1
while time.monotonic()<end: while time.monotonic()<end:
while GLib.MainContext.default().iteration(False): pass while GLib.MainContext.default().iteration(False): pass