Compare commits

...

77 Commits
v0.3 ... master

Author SHA1 Message Date
Storm Dragon
d36b664319 Merge branch 'testing'
Plugins are in a much better state now, mostly working. The exception is, plugins that create a keyboard shortcut don't actually bind the shortcut. That one is turning out to be a lot harder to fix than I originally thought.
2025-04-05 16:32:17 -04:00
Storm Dragon
02be96aa69 Try to fix clipboard and simple plugins. 2025-04-04 18:04:58 -04:00
Storm Dragon
48575ab6cd Removed the old plugin manager. It didn't work anyway and needs to be rewritten. 2025-04-04 17:28:31 -04:00
Storm Dragon
2c28021ed4 Removed the old plugin manager. It didn't work anyway and needs to be rewritten. 2025-04-04 17:27:30 -04:00
Storm Dragon
8a79725df8 Update clipboard plugin to new pluggy format. 2025-04-04 17:08:18 -04:00
Storm Dragon
1b4c4916e3 Hopefully fixed an error in simple plugin system. 2025-04-04 16:33:53 -04:00
Storm Dragon
35a83327ac Convert simple plugin plugin to new plugin format. Hmm, gotta get in a couple more... plugin plugin plugin! lol 2025-04-04 16:25:28 -04:00
Storm Dragon
c712bea421 Attempt to fix keybindings not working from plugins. 2025-04-04 16:03:35 -04:00
Storm Dragon
815d39fc3f Remove a couple plugins that were not being used and won't be ported over. If needed, they can be rewritten later. 2025-04-04 14:54:18 -04:00
Storm Dragon
231d74efa0 Try to fix repeating welcome message. 2025-04-04 14:32:03 -04:00
Storm Dragon
7876a18c12 Working on plugin conversion. 2025-04-04 14:19:09 -04:00
Storm Dragon
0b7cf681c3 Forgot to update the configure.ac file. 2025-04-04 02:48:43 -04:00
Storm Dragon
4b8ebcb599 Removed the Date plugin it was causing traceback. 2025-04-04 02:46:01 -04:00
Storm Dragon
d6a373c726 Fixed some errors with plugins. 2025-04-03 20:46:11 -04:00
Storm Dragon
dfe20fca30 More work on pluggy. 2025-04-03 20:38:27 -04:00
Storm Dragon
3f7d60763d Merge branch 'testing'
Plugins are currently broken as Cthulhu moves over to pluggy. Libpeas and pygobject no longer play nicely together after latest updates. I really did not want to make a new release yet, because it is not ready, but a screen reader that at least reads instead of crashing at launch is better than nothing.
2025-04-03 20:17:14 -04:00
Storm Dragon
084d4fe85f Attempt to get pluggy working. 2025-04-03 20:10:54 -04:00
Storm Dragon
6bbe6e47fc Simplified the plugin code. Hopefully it at least somewhat works better now. 2025-04-03 14:00:06 -04:00
Storm Dragon
312476bbed A simple test plugin added for testing. 2025-03-27 23:23:01 -04:00
Storm Dragon
0005d5ec71 Activate the plugin in settings.py. 2025-03-26 01:45:58 -04:00
Storm Dragon
88ad9833d2 Forgot to update configure.ac. 2025-03-26 01:26:22 -04:00
Storm Dragon
654f1acc21 Start updating plugins. 2025-03-26 01:21:28 -04:00
Storm Dragon
dfb53fff89 And another line I forgot to remove. 2025-03-25 20:18:57 -04:00
Storm Dragon
9cdb9f74e5 Decided to make the api helper part of the plugin_system_manager file. Forgot to remove the import from cthulhu.py. 2025-03-25 20:15:54 -04:00
Storm Dragon
41dae26d90 Fixed a message to be more clear. 2025-03-25 20:02:06 -04:00
Storm Dragon
edc1cbf7af Continue work on switching to pluggy for plugins. 2025-03-25 19:59:50 -04:00
Storm Dragon
d3d268004b Start migration to pluggy for plugins. 2025-03-25 19:41:57 -04:00
Didier Spaier
a8e16fcf01 Toggle screen reader keyboard shortcut for desktops relying on glib-2.0/gio such as Mate. 2024-12-23 14:29:10 -05:00
Storm Dragon
6bbf3d0e67 Merge branch 'testing' latest changes merged. 2024-12-22 19:04:57 -05:00
Storm Dragon
cbe3424e29 Fix the version.py file in preparation for merging. 2024-12-22 19:04:39 -05:00
Storm Dragon
1cf566c37c Error out if libpeas is not found during build. 2024-12-22 18:59:48 -05:00
Storm Dragon
936153f307 Fixed typo in keybinding. 2024-12-22 17:00:36 -05:00
Storm Dragon
29f8697a9f Fix missing method in default.py for scripts. 2024-12-22 15:16:18 -05:00
Storm Dragon
ba735c554b Try to fix sleep mode so it is actually detected. 2024-12-22 14:49:31 -05:00
Storm Dragon
1c9ca14272 Attempt to back port sleepmode. 2024-12-22 14:22:56 -05:00
Storm Dragon
d6af91bf42 Added version to active plugins. Reverted keybind to cthulhu+shift+v 2024-12-19 09:44:01 -05:00
Storm Dragon
5dd872535d Temperarily change the keyboard short fo version to cthulhu+x. 2024-12-19 09:30:59 -05:00
Storm Dragon
8e9ea3af5a Attempt to fix the cthulhu+shift+v keybinding. 2024-12-19 08:37:45 -05:00
Storm Dragon
a40087cd20 Update configure.ac. 2024-12-19 08:29:11 -05:00
Storm Dragon
35acddeb8f Added Display Version plugin, cthul+shift=V. 2024-12-19 08:20:21 -05:00
Storm Dragon
327ad99e49 Preparing for stable tag release. 2024-12-18 19:49:25 -05:00
Storm Dragon
c46cf1c939 Merge branch 'testing' fixed preferences GUI. 2024-12-18 19:45:59 -05:00
Storm Dragon
80033b3f37 Fixed missing function. 2024-12-18 19:41:39 -05:00
Storm Dragon
53e6e095b3 Oops, forgot to change orca to cthulhu in a couple of spots, no worky. 2024-12-18 19:33:16 -05:00
Storm Dragon
d863cf0353 Fixed the preferences gui keyboard shortcut. 2024-12-18 19:25:24 -05:00
Storm Dragon
a97bb30ed3 New version system merged. 2024-12-18 11:42:52 -05:00
Storm Dragon
e9916bbcc4 Fixed wrong variable names in version. 2024-12-18 11:34:18 -05:00
Storm Dragon
6e480db630 Forgot to add the version file to the Makefile.am. 2024-12-18 11:28:57 -05:00
Storm Dragon
384479a0a5 Add the code name to the version. 2024-12-18 11:22:41 -05:00
Storm Dragon
deccf846d8 Fix how version is obtained in PKGBUILD. 2024-12-18 11:01:55 -05:00
Storm Dragon
92a909edb8 Fixed path for version file in configure.ac. 2024-12-18 10:55:51 -05:00
Storm Dragon
55c7de8c65 Attempt to change the version number to be more like Fenrir's. Will work on adding the codename part if this works. 2024-12-18 10:52:07 -05:00
Storm Dragon
5a744a6809 One last modification to headers. 2024-12-18 10:20:50 -05:00
Storm Dragon
63539e8122 Updated headers in python files. 2024-12-18 10:05:44 -05:00
Storm Dragon
5178a66a6f Tidy up spacing. 2024-11-28 15:06:23 -05:00
Storm Dragon
89891f18af Forgot to restore _showPreferenceSUI. 2024-11-28 14:57:40 -05:00
Storm Dragon
71add76898 More fixes to removing classic preferences. 2024-11-28 14:48:34 -05:00
Storm Dragon
1a9eb35418 More fixes for preferences. 2024-11-28 06:32:21 -05:00
Storm Dragon
ba6382c3cd Hopefully fix the -s flag which was broken by plugin updates. 2024-11-28 06:22:07 -05:00
Storm Dragon
17febf488c Another file edited. 2024-11-28 06:00:17 -05:00
Storm Dragon
09718e5901 Missed a file, remove the last of classic preferences plugin. 2024-11-28 05:56:08 -05:00
Storm Dragon
03bed6c5d4 Remove Classic Preference plugin because of breakages. 2024-11-28 05:46:35 -05:00
Storm Dragon
d28e0086d9 Slackbuild added. 2024-11-24 13:59:46 -05:00
Storm Dragon
515827e830 Bump pkgver for the PKGBUILD. 2024-11-01 11:49:27 -04:00
Storm Dragon
4f6260eb6f Version bump, check for libpeas in configure.ac. 2024-11-01 11:36:08 -04:00
Storm Dragon
b6a44df82a updated the README. 2024-10-28 21:14:23 -04:00
Storm Dragon
0cadb12c00 Merge branch 'sps' of git.stormux.org:storm/cthulhu into sps 2024-10-23 19:16:07 -04:00
Storm Dragon
2f6fde6896 Removed add SimplePluginSystem as it is now done. 2024-10-23 19:15:45 -04:00
Chrys
89467b6988 remove unused variable 2024-10-24 00:58:11 +02:00
Chrys
17d2773344 make shortcuts work, migrate to plugin api 2024-10-24 00:55:22 +02:00
Chrys
0abe30791d fix all syntax issues in SOPS 2024-10-24 00:08:25 +02:00
Chrys
087dcc3ab2 add SimplePlugin to settings.py 2024-10-23 19:06:12 +02:00
Chrys
4eaa4fae86 add SimplePlugin to configure.ac 2024-10-23 19:04:22 +02:00
Chrys
ba0169b016 add SimplePlugin to make 2024-10-23 19:03:06 +02:00
Storm Dragon
7605e7d60f Found some stuff I missed on the initial attempt to get this working. 2024-10-23 09:37:42 -04:00
Storm Dragon
9562c08130 fixed author lines, I think. 2024-10-23 08:16:37 -04:00
Storm Dragon
8a9bbefeac Initial attempt at chaning SOPS into a plugin for Cthulhu. 2024-10-23 07:58:44 -04:00
689 changed files with 14630 additions and 10774 deletions

View File

@ -29,6 +29,8 @@ Cthulhu has the following dependencies:
* liblouis - Liblouis (<http://liblouis.org/>) support for contracted braille (optional) * liblouis - Liblouis (<http://liblouis.org/>) support for contracted braille (optional)
* py-setproctitle - Python library to set the process title (optional) * py-setproctitle - Python library to set the process title (optional)
* gstreamer-1.0 - GStreamer - Streaming media framework (optional) * gstreamer-1.0 - GStreamer - Streaming media framework (optional)
* socat - Used for self-voicing functionality.
* libpeas - For the plugin system.
You are strongly encouraged to also have the latest stable versions You are strongly encouraged to also have the latest stable versions
of AT-SPI2 and ATK. of AT-SPI2 and ATK.

1
TODO
View File

@ -1,4 +1,3 @@
- Add Simple Cthulhu Plugin System as native code for Cthulhu
- Merge in sleep mode. - Merge in sleep mode.
- Add in ocrdesktop code so that Cthulhu has native ocr support. - Add in ocrdesktop code so that Cthulhu has native ocr support.
- Get rid of build systems. My hope is git clone and run so long as requirements are satisfied. - Get rid of build systems. My hope is git clone and run so long as requirements are satisfied.

View File

@ -1,4 +1,7 @@
m4_define([cthulhu_version], [0.3]) m4_define([get_version], [m4_esyscmd_s([
grep "^version = " src/cthulhu/cthulhuVersion.py | sed 's/version = "\(.*\)"/\1/'
])])
m4_define([cthulhu_version], [get_version])
m4_define(pygobject_required_version, 3.18) m4_define(pygobject_required_version, 3.18)
m4_define(atspi_required_version, 2.48) m4_define(atspi_required_version, 2.48)
@ -28,6 +31,7 @@ PKG_CHECK_MODULES([PYGOBJECT], [pygobject-3.0 >= pygobject_required_version])
PKG_CHECK_MODULES([ATSPI2], [atspi-2 >= atspi_required_version]) PKG_CHECK_MODULES([ATSPI2], [atspi-2 >= atspi_required_version])
PKG_CHECK_MODULES([ATKBRIDGE], [atk-bridge-2.0 >= atkbridge_required_version]) PKG_CHECK_MODULES([ATKBRIDGE], [atk-bridge-2.0 >= atkbridge_required_version])
PKG_CHECK_MODULES([GSTREAMER], [gstreamer-1.0], [gstreamer="yes"], [gstreamer="no"]) PKG_CHECK_MODULES([GSTREAMER], [gstreamer-1.0], [gstreamer="yes"], [gstreamer="no"])
PKG_CHECK_MODULES([LIBPEAS], [libpeas-1.0])
dnl Needed programs dnl Needed programs
AC_PROG_INSTALL AC_PROG_INSTALL
@ -42,6 +46,7 @@ AM_PATH_PYTHON(3.3)
AM_CHECK_PYMOD(gi,,,[AC_MSG_ERROR(Could not find python module: gi)]) AM_CHECK_PYMOD(gi,,,[AC_MSG_ERROR(Could not find python module: gi)])
AM_CHECK_PYMOD(json,,,[AC_MSG_ERROR(Could not find python module: json)]) AM_CHECK_PYMOD(json,,,[AC_MSG_ERROR(Could not find python module: json)])
AM_CHECK_PYMOD(pluggy,,[pluggy_available="yes"],[pluggy_available="no"])
AM_CHECK_PYMOD(brlapi,,[brlapi_available="yes"],[brlapi_available="no"]) AM_CHECK_PYMOD(brlapi,,[brlapi_available="yes"],[brlapi_available="no"])
AM_CHECK_PYMOD(speechd,,[speechd_available="yes"],[speechd_available="no"]) AM_CHECK_PYMOD(speechd,,[speechd_available="yes"],[speechd_available="no"])
AC_ARG_WITH([liblouis], AC_ARG_WITH([liblouis],
@ -106,6 +111,7 @@ src/cthulhu/scripts/apps/SeaMonkey/Makefile
src/cthulhu/scripts/apps/smuxi-frontend-gnome/Makefile src/cthulhu/scripts/apps/smuxi-frontend-gnome/Makefile
src/cthulhu/scripts/apps/Thunderbird/Makefile src/cthulhu/scripts/apps/Thunderbird/Makefile
src/cthulhu/scripts/apps/xfwm4/Makefile src/cthulhu/scripts/apps/xfwm4/Makefile
src/cthulhu/scripts/sleepmode/Makefile
src/cthulhu/scripts/switcher/Makefile src/cthulhu/scripts/switcher/Makefile
src/cthulhu/scripts/terminal/Makefile src/cthulhu/scripts/terminal/Makefile
src/cthulhu/scripts/web/Makefile src/cthulhu/scripts/web/Makefile
@ -121,15 +127,11 @@ src/cthulhu/scripts/toolkits/gtk/Makefile
src/cthulhu/plugins/Makefile src/cthulhu/plugins/Makefile
src/cthulhu/plugins/ByeCthulhu/Makefile src/cthulhu/plugins/ByeCthulhu/Makefile
src/cthulhu/plugins/HelloCthulhu/Makefile src/cthulhu/plugins/HelloCthulhu/Makefile
src/cthulhu/plugins/PluginManager/Makefile
src/cthulhu/plugins/Clipboard/Makefile src/cthulhu/plugins/Clipboard/Makefile
src/cthulhu/plugins/HelloWorld/Makefile src/cthulhu/plugins/DisplayVersion/Makefile
src/cthulhu/plugins/CapsLockHack/Makefile src/cthulhu/plugins/hello_world/Makefile
src/cthulhu/plugins/SelfVoice/Makefile src/cthulhu/plugins/self_voice/Makefile
src/cthulhu/plugins/Date/Makefile src/cthulhu/plugins/SimplePluginSystem/Makefile
src/cthulhu/plugins/Time/Makefile
src/cthulhu/plugins/MouseReview/Makefile
src/cthulhu/plugins/ClassicPreferences/Makefile
src/cthulhu/backends/Makefile src/cthulhu/backends/Makefile
src/cthulhu/cthulhu_bin.py src/cthulhu/cthulhu_bin.py
src/cthulhu/cthulhu_i18n.py src/cthulhu/cthulhu_i18n.py
@ -157,7 +159,12 @@ echo
echo "NOTE: Sound support requires gstreamer-1.0." echo "NOTE: Sound support requires gstreamer-1.0."
fi fi
if test "$have_libpeas" = "no"; then
AC_MSG_ERROR([libpeas-1.0 >= 1.20 is required])
fi
echo echo
echo Use pluggy: $pluggy_available
echo Use speech-dispatcher: $speechd_available echo Use speech-dispatcher: $speechd_available
echo Use brltty: $brlapi_available echo Use brltty: $brlapi_available
echo Use liblouis: $louis_available echo Use liblouis: $louis_available

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<schemalist gettext-domain="slint">
<schema id="toggle.screenreader" path="/toggle/screenreader/">
<key name="binding" type="s">
<default>'&lt;Shift&gt;&lt;Alt&gt;v'</default>
<summary>Keybinding</summary>
<description>Keybinding associated to toggle screen reader.</description>
</key>
<key name="action" type="s">
<default>'/opt/I38/scripts/toggle_screenreader.sh 1>/dev/null'</default>
<summary>Command</summary>
<description>Command to toggle the screen reader between orca and cthulhu.</description>
</key>
<key name="name" type="s">
<default>'Toggle screenreader'</default>
<summary>Name</summary>
<description>Description associated to toggle screen reader.</description>
</key>
</schema>
</schemalist>

View File

@ -1,7 +1,7 @@
# Maintainer: Storm Dragon <storm_dragon@stormux.org> # Maintainer: Storm Dragon <storm_dragon@stormux.org>
pkgname=cthulhu pkgname=cthulhu
pkgver=0.3 pkgver=0.4
pkgrel=1 pkgrel=1
pkgdesc="Screen reader for individuals who are blind or visually impaired forked from Orca" pkgdesc="Screen reader for individuals who are blind or visually impaired forked from Orca"
url="https://git.stormux.org/storm/cthulhu" url="https://git.stormux.org/storm/cthulhu"
@ -44,6 +44,11 @@ prepare() {
NOCONFIGURE=1 ./autogen.sh NOCONFIGURE=1 ./autogen.sh
} }
pkgver() {
cd cthulhu
grep "^version = " src/cthulhu/cthulhuVersion.py | sed 's/version = "\(.*\)"/\1/'
}
build() { build() {
cd cthulhu cd cthulhu
./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var

View File

@ -0,0 +1,98 @@
#!/bin/bash
# Slackware build script for cthulhu
# Created based on PKGBUILD from Storm Dragon <storm_dragon@stormux.org>
cd $(dirname $0) ; CWD=$(pwd)
PRGNAM=cthulhu
VERSION=${VERSION:-0.4}
BUILD=${BUILD:-1}
TAG=storm
PKGTYPE=txz
export PYTHON=/usr/bin/python3.11
if [ -z "$ARCH" ]; then
case "$( uname -m )" in
i?86) ARCH=i586 ;;
arm*) ARCH=arm ;;
*) ARCH=$( uname -m ) ;;
esac
fi
# If the variable PRINT_PACKAGE_NAME is set, then this script will report what
# the name of the created package would be, and then exit. This information
# could be useful to other scripts.
if [ ! -z "${PRINT_PACKAGE_NAME}" ]; then
echo "$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.$PKGTYPE"
exit 0
fi
TMP=$CWD
PKG=$TMP/package-$PRGNAM
OUTPUT=$CWD
if [ "$ARCH" = "i586" ]; then
SLKCFLAGS="-O2 -march=i586 -mtune=i686"
LIBDIRSUFFIX=""
elif [ "$ARCH" = "i686" ]; then
SLKCFLAGS="-O2 -march=i686 -mtune=i686"
LIBDIRSUFFIX=""
elif [ "$ARCH" = "x86_64" ]; then
SLKCFLAGS="-O2 -fPIC"
LIBDIRSUFFIX="64"
else
SLKCFLAGS="-O2"
LIBDIRSUFFIX=""
fi
set -e
rm -rf $PKG
mkdir -p $TMP $PKG $OUTPUT
cd $TMP
rm -rf $PRGNAM-$VERSION
git clone https://git.stormux.org/storm/cthulhu.git $PRGNAM-$VERSION
cd $PRGNAM-$VERSION
chown -R root:root .
find -L . \
\( -perm 777 -o -perm 775 -o -perm 750 -o -perm 711 -o -perm 555 \
-o -perm 511 \) -exec chmod 755 {} \; -o \
\( -perm 666 -o -perm 664 -o -perm 640 -o -perm 600 -o -perm 444 \
-o -perm 440 -o -perm 400 \) -exec chmod 644 {} \;
# Prepare the source
NOCONFIGURE=1 ./autogen.sh
CFLAGS="$SLKCFLAGS" \
CXXFLAGS="$SLKCFLAGS" \
./configure \
--prefix=/usr \
--libdir=/usr/lib${LIBDIRSUFFIX} \
--sysconfdir=/etc \
--localstatedir=/var \
--mandir=/usr/man \
--docdir=/usr/doc/$PRGNAM-$VERSION \
--build=$ARCH-slackware-linux
make
make install DESTDIR=$PKG
find $PKG -print0 | xargs -0 file | grep -e "executable" -e "shared object" | grep ELF \
| cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null || true
mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION
cp -a AUTHORS COPYING ChangeLog NEWS README.md \
$PKG/usr/doc/$PRGNAM-$VERSION
cat $CWD/$PRGNAM.SlackBuild > $PKG/usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild
mkdir -p $PKG/install
cat $CWD/slack-desc > $PKG/install/slack-desc
cat $CWD/doinst.sh > $PKG/install/doinst.sh
cd $PKG
# let's avoid a "bad interpreter error
sed "s,#!python3.11,#!/usr/bin/python3.11," usr/bin/cthulhu > dummy
mv dummy usr/bin/cthulhu
chmod 755 usr/bin/cthulhu
/sbin/makepkg -l y -c n $OUTPUT/$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.$PKGTYPE

View File

@ -0,0 +1,28 @@
Cthulhu is a screen reader for individuals who are blind or visually impaired,
forked from Orca. It provides access to applications and toolkits that support
the AT-SPI (e.g., the GNOME desktop).
This screen reader helps users navigate their desktop environment and applications
through speech synthesis and braille output.
After installation, you can start Cthulhu through the GNOME desktop environment
or by running 'cthulhu' from the command line.
DEPENDENCIES:
This package requires the following packages, all available from SlackBuilds.org:
- at-spi2-core
- brltty
- gobject-introspection
- gsettings-desktop-schemas
- gstreamer
- gst-plugins-base
- gst-plugins-good
- gtk3
- liblouis
- libpeas
- libwnck3
- python3-atspi
- python3-cairo
- python3-gobject
- python3-setproctitle
- speech-dispatcher

View File

@ -0,0 +1,10 @@
PRGNAM="cthulhu"
VERSION="0.4"
HOMEPAGE="https://git.stormux.org/storm/cthulhu"
DOWNLOAD="https://git.stormux.org/storm/cthulhu.git"
MD5SUM="SKIP"
DOWNLOAD_x86_64=""
MD5SUM_x86_64=""
REQUIRES="at-spi2-core brltty gobject-introspection gsettings-desktop-schemas gstreamer gst-plugins-base gst-plugins-good gtk3 liblouis libpeas libwnck3 python3-atspi python3-cairo python3-gobject python3-setproctitle speech-dispatcher"
MAINTAINER="Storm Dragon"
EMAIL="storm_dragon@stormux.org"

View File

@ -0,0 +1,98 @@
#!/bin/bash
# Slackware build script for cthulhu
# Created based on PKGBUILD from Storm Dragon <storm_dragon@stormux.org>
cd $(dirname $0) ; CWD=$(pwd)
PRGNAM=cthulhu
VERSION=${VERSION:-0.4}
BUILD=${BUILD:-1}
TAG=storm
PKGTYPE=txz
export PYTHON=/usr/bin/python3.11
if [ -z "$ARCH" ]; then
case "$( uname -m )" in
i?86) ARCH=i586 ;;
arm*) ARCH=arm ;;
*) ARCH=$( uname -m ) ;;
esac
fi
# If the variable PRINT_PACKAGE_NAME is set, then this script will report what
# the name of the created package would be, and then exit. This information
# could be useful to other scripts.
if [ ! -z "${PRINT_PACKAGE_NAME}" ]; then
echo "$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.$PKGTYPE"
exit 0
fi
TMP=$CWD
PKG=$TMP/package-$PRGNAM
OUTPUT=$CWD
if [ "$ARCH" = "i586" ]; then
SLKCFLAGS="-O2 -march=i586 -mtune=i686"
LIBDIRSUFFIX=""
elif [ "$ARCH" = "i686" ]; then
SLKCFLAGS="-O2 -march=i686 -mtune=i686"
LIBDIRSUFFIX=""
elif [ "$ARCH" = "x86_64" ]; then
SLKCFLAGS="-O2 -fPIC"
LIBDIRSUFFIX="64"
else
SLKCFLAGS="-O2"
LIBDIRSUFFIX=""
fi
set -e
rm -rf $PKG
mkdir -p $TMP $PKG $OUTPUT
cd $TMP
rm -rf $PRGNAM-$VERSION
git clone https://git.stormux.org/storm/cthulhu.git $PRGNAM-$VERSION
cd $PRGNAM-$VERSION
chown -R root:root .
find -L . \
\( -perm 777 -o -perm 775 -o -perm 750 -o -perm 711 -o -perm 555 \
-o -perm 511 \) -exec chmod 755 {} \; -o \
\( -perm 666 -o -perm 664 -o -perm 640 -o -perm 600 -o -perm 444 \
-o -perm 440 -o -perm 400 \) -exec chmod 644 {} \;
# Prepare the source
NOCONFIGURE=1 ./autogen.sh
CFLAGS="$SLKCFLAGS" \
CXXFLAGS="$SLKCFLAGS" \
./configure \
--prefix=/usr \
--libdir=/usr/lib${LIBDIRSUFFIX} \
--sysconfdir=/etc \
--localstatedir=/var \
--mandir=/usr/man \
--docdir=/usr/doc/$PRGNAM-$VERSION \
--build=$ARCH-slackware-linux
make
make install DESTDIR=$PKG
find $PKG -print0 | xargs -0 file | grep -e "executable" -e "shared object" | grep ELF \
| cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null || true
mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION
cp -a AUTHORS COPYING ChangeLog NEWS README.md \
$PKG/usr/doc/$PRGNAM-$VERSION
cat $CWD/$PRGNAM.SlackBuild > $PKG/usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild
mkdir -p $PKG/install
cat $CWD/slack-desc > $PKG/install/slack-desc
cat $CWD/doinst.sh > $PKG/install/doinst.sh
cd $PKG
# let's avoid a "bad interpreter error
sed "s,#!python3.11,#!/usr/bin/python3.11," usr/bin/cthulhu > dummy
mv dummy usr/bin/cthulhu
chmod 755 usr/bin/cthulhu
/sbin/makepkg -l y -c n $OUTPUT/$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.$PKGTYPE

View File

@ -0,0 +1,9 @@
if [ -x /usr/bin/update-desktop-database ]; then
/usr/bin/update-desktop-database -q usr/share/applications >/dev/null 2>&1
fi
if [ -e usr/share/icons/hicolor/icon-theme.cache ]; then
if [ -x /usr/bin/gtk-update-icon-cache ]; then
/usr/bin/gtk-update-icon-cache usr/share/icons/hicolor >/dev/null 2>&1
fi
fi

View File

@ -0,0 +1,19 @@
# HOW TO EDIT THIS FILE:
# The "handy ruler" below makes it easier to edit a package description.
# Line up the first '|' above the ':' following the base package name, and
# the '|' on the right side marks the last column you can put a character in.
# You must make exactly 11 lines for the formatting to be correct. It's also
# customary to leave one space after the ':' except on otherwise blank lines.
|-----handy-ruler------------------------------------------------------|
cthulhu: cthulhu (Screen reader for blind or visually impaired users)
cthulhu:
cthulhu: Cthulhu is a screen reader for individuals who are blind or visually
cthulhu: impaired, forked from Orca. It provides a way to access applications
cthulhu: and toolkits that support the AT-SPI (e.g., the GNOME desktop).
cthulhu:
cthulhu: Homepage: https://git.stormux.org/storm/cthulhu
cthulhu:
cthulhu:
cthulhu:
cthulhu:

View File

@ -1,10 +1,27 @@
# Ruff linter. [build-system]
# requires = ["hatchling"]
# Repository: https://github.com/astral-sh/ruff build-backend = "hatchling.build"
#
# Documentation: https://beta.ruff.rs/docs/ [project]
[tool.ruff] name = "cthulhu"
line-length = 100 # same as rustfmt dynamic = ["version"]
ignore = [ description = "Fork of the Orca screen reader based on gnome-45"
"E402", # Module level import not at top of file readme = "README.md"
requires-python = ">=3.3"
license = { text = "LGPL-2.1-or-later" }
dependencies = [
"pygobject>=3.18",
"python-atspi>=2.48",
"brlapi; extra == 'braille'",
"python-speechd; extra == 'speech'",
"louis; extra == 'braille'"
] ]
[project.scripts]
cthulhu = "cthulhu.cthulhu:main"
[tool.hatch.version]
path = "src/cthulhu/__init__.py"
[tool.hatch.build.targets.wheel]
packages = ["src/cthulhu"]

294
src/cthulhu.py Normal file
View File

@ -0,0 +1,294 @@
#!/usr/bin/env python3
#
# Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
import argparse
import gi
gi.require_version("Atspi", "2.0")
from gi.repository import Atspi
import os
import signal
import subprocess
import sys
import time
def setup_paths():
"""Configure paths for both installed and source directory execution."""
currentDir = os.path.dirname(os.path.abspath(__file__))
# Check if running from source
if os.path.exists(os.path.join(currentDir, 'plugins')):
# Running from source directory
sys.path.insert(0, os.path.dirname(currentDir))
pythondir = currentDir
else:
# Running installed
sys.prefix = '/usr'
pythondir = os.path.join(sys.prefix, 'lib', f'python{sys.version_info.major}.{sys.version_info.minor}', 'site-packages')
sys.path.insert(1, pythondir)
# Set environment variables for resource paths
if 'CTHULHU_DATA_DIR' not in os.environ:
if os.path.exists(os.path.join(currentDir, 'plugins')):
os.environ['CTHULHU_DATA_DIR'] = currentDir
else:
os.environ['CTHULHU_DATA_DIR'] = os.path.join(sys.prefix, 'share', 'cthulhu')
# Set up paths before importing Cthulhu modules
setup_paths()
from cthulhu import debug
from cthulhu import messages
from cthulhu import settings
from cthulhu.ax_object import AXObject
from cthulhu.ax_utilities import AXUtilities
from cthulhu.cthulhu_platform import version
class ListApps(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
desktop = AXUtilities.get_desktop()
for app in AXObject.iter_children(desktop):
pid = AXObject.get_process_id(app)
try:
name = Atspi.Accessible.get_name(app) or "(none)"
except Exception:
name = "[DEAD]"
try:
cmdline = subprocess.getoutput('cat /proc/%s/cmdline' % pid)
except Exception:
cmdline = '(exception encountered)'
else:
cmdline = cmdline.replace('\x00', ' ')
print(time.strftime('%H:%M:%S', time.localtime()),
' pid: %5s %-25s %s' % (pid, name, cmdline))
parser.exit()
class Settings(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
settingsDict = getattr(namespace, 'settings', {})
invalid = getattr(namespace, 'invalid', [])
for value in values.split(','):
item = str.title(value).replace('-', '')
try:
test = 'enable%s' % item
eval('settings.%s' % test)
except AttributeError:
try:
test = 'show%s' % item
eval('settings.%s' % test)
except AttributeError:
invalid.append(value)
continue
settingsDict[test] = self.const
setattr(namespace, 'settings', settingsDict)
setattr(namespace, 'invalid', invalid)
class HelpFormatter(argparse.HelpFormatter):
def __init__(self, prog, indent_increment=2, max_help_position=32,
width=None):
super().__init__(prog, indent_increment, max_help_position, width)
def add_usage(self, usage, actions, groups, prefix=None):
super().add_usage(usage, actions, groups, messages.CLI_USAGE)
class Parser(argparse.ArgumentParser):
def __init__(self, *args, **kwargs):
super(Parser, self).__init__(
epilog=messages.CLI_EPILOG, formatter_class=HelpFormatter, add_help=False)
self.add_argument(
"-h", "--help", action="help", help=messages.CLI_HELP)
self.add_argument(
"-v", "--version", action="version", version=version, help=messages.CLI_VERSION)
self.add_argument(
"-r", "--replace", action="store_true", help=messages.CLI_REPLACE)
self.add_argument(
"-s", "--setup", action="store_true", help=messages.CLI_GUI_SETUP)
self.add_argument(
"-l", "--list-apps", action=ListApps, nargs=0,
help=messages.CLI_LIST_APPS)
self.add_argument(
"-e", "--enable", action=Settings, const=True,
help=messages.CLI_ENABLE_OPTION, metavar=messages.CLI_OPTION)
self.add_argument(
"-d", "--disable", action=Settings, const=False,
help=messages.CLI_DISABLE_OPTION, metavar=messages.CLI_OPTION)
self.add_argument(
"-p", "--profile", action="store",
help=messages.CLI_LOAD_PROFILE, metavar=messages.CLI_PROFILE_NAME)
self.add_argument(
"-u", "--user-prefs", action="store",
help=messages.CLI_LOAD_PREFS, metavar=messages.CLI_PREFS_DIR)
self.add_argument(
"--debug-file", action="store",
help=messages.CLI_DEBUG_FILE, metavar=messages.CLI_DEBUG_FILE_NAME)
self.add_argument(
"--debug", action="store_true", help=messages.CLI_ENABLE_DEBUG)
self._optionals.title = messages.CLI_OPTIONAL_ARGUMENTS
def parse_known_args(self, *args, **kwargs):
opts, invalid = super(Parser, self).parse_known_args(*args, **kwargs)
try:
invalid.extend(opts.invalid)
except Exception:
pass
if invalid:
print((messages.CLI_INVALID_OPTIONS + " ".join(invalid)))
if opts.debug_file:
opts.debug = True
elif opts.debug:
opts.debug_file = time.strftime('debug-%Y-%m-%d-%H:%M:%S.out')
return opts, invalid
def setProcessName(name):
"""Attempts to set the process name to the specified name."""
sys.argv[0] = name
try:
from setproctitle import setproctitle
except ImportError:
pass
else:
setproctitle(name)
return True
try:
from ctypes import cdll, byref, create_string_buffer
libc = cdll.LoadLibrary('libc.so.6')
stringBuffer = create_string_buffer(len(name) + 1)
stringBuffer.value = bytes(name, 'UTF-8')
libc.prctl(15, byref(stringBuffer), 0, 0, 0)
return True
except Exception:
pass
return False
def inGraphicalDesktop():
"""Returns True if we are in a graphical desktop."""
# TODO - JD: Make this desktop environment agnostic
try:
import gi
gi.require_version("Gdk", "3.0")
from gi.repository import Gdk
display = Gdk.Display.get_default()
except Exception:
return False
return display is not None
def otherCthulhus():
"""Returns the pid of any other instances of Cthulhu owned by this user."""
openFile = subprocess.Popen('pgrep -u %s -x cthulhu' % os.getuid(),
shell=True,
stdout=subprocess.PIPE).stdout
pids = openFile.read()
openFile.close()
cthulhus = [int(p) for p in pids.split()]
pid = os.getpid()
return [p for p in cthulhus if p != pid]
def cleanup(sigval):
"""Tries to clean up any other running Cthulhu instances owned by this user."""
cthulhusToKill = otherCthulhus()
debug.printMessage(debug.LEVEL_INFO, "INFO: Cleaning up these PIDs: %s" % cthulhusToKill)
def onTimeout(signum, frame):
cthulhusToKill = otherCthulhus()
debug.printMessage(debug.LEVEL_INFO, "INFO: Timeout cleaning up: %s" % cthulhusToKill)
for pid in cthulhusToKill:
os.kill(pid, signal.SIGKILL)
for pid in cthulhusToKill:
os.kill(pid, sigval)
signal.signal(signal.SIGALRM, onTimeout)
signal.alarm(2)
while otherCthulhus():
time.sleep(0.5)
def main():
setProcessName('cthulhu')
parser = Parser()
args, invalid = parser.parse_known_args()
if args.debug:
debug.debugLevel = debug.LEVEL_ALL
debug.eventDebugLevel = debug.LEVEL_OFF
debug.debugFile = open(args.debug_file, 'w')
if args.replace:
cleanup(signal.SIGKILL)
settingsDict = getattr(args, 'settings', {})
if not inGraphicalDesktop():
print(messages.CLI_NO_DESKTOP_ERROR)
return 1
debug.printMessage(debug.LEVEL_INFO, "INFO: Preparing to launch.", True)
from cthulhu import cthulhu
manager = cthulhu.getSettingsManager()
if not manager:
print(messages.CLI_SETTINGS_MANAGER_ERROR)
return 1
debug.printMessage(debug.LEVEL_INFO, "INFO: About to activate settings manager.", True)
manager.activate(args.user_prefs, settingsDict)
sys.path.insert(0, manager.getPrefsDir())
if args.profile:
try:
manager.setProfile(args.profile)
except Exception:
print(messages.CLI_LOAD_PROFILE_ERROR % args.profile)
manager.setProfile()
if args.setup:
cleanup(signal.SIGKILL)
cthulhu.showPreferencesGUI()
if otherCthulhus():
print(messages.CLI_OTHER_CTHULHUS_ERROR)
return 1
debug.printMessage(debug.LEVEL_INFO, "INFO: About to launch Cthulhu.", True)
return cthulhu.main()
if __name__ == "__main__":
sys.exit(main())

View File

@ -29,6 +29,7 @@ cthulhu_python_PYTHON = \
cmdnames.py \ cmdnames.py \
colornames.py \ colornames.py \
common_keyboardmap.py \ common_keyboardmap.py \
cthulhuVersion.py \
date_and_time_presenter.py \ date_and_time_presenter.py \
debug.py \ debug.py \
desktop_keyboardmap.py \ desktop_keyboardmap.py \

View File

@ -1,3 +1,28 @@
#!/usr/bin/env python3
#
# Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Cthulhu Screen Reader""" """Cthulhu Screen Reader"""
__copyright__ = "Copyright (c) 2005-2006 Sun Microsystems Inc." __copyright__ = "Copyright (c) 2005-2006 Sun Microsystems Inc."

View File

@ -1,7 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2005-2008 Google Inc. # Copyright (c) 2024 Stormux
# Portions Copyright 2007-2008, Sun Microsystems, Inc. # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -18,6 +20,9 @@
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
# #
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""ACSS --- Aural CSS. """ACSS --- Aural CSS.
Class ACSS defines a simple wrapper for holding ACSS voice Class ACSS defines a simple wrapper for holding ACSS voice

View File

@ -1,7 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2023 Igalia, S.L. # Copyright (c) 2024 Stormux
# Author: Joanmarie Diggs <jdiggs@igalia.com> # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Module for performing accessible actions via a menu""" """Module for performing accessible actions via a menu"""

View File

@ -1,7 +1,9 @@
# Utilities for obtaining objects via the collection interface. #!/usr/bin/env python3
# #
# Copyright 2023 Igalia, S.L. # Copyright (c) 2024 Stormux
# Author: Joanmarie Diggs <jdiggs@igalia.com> # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
""" """
Utilities for obtaining objects via the collection interface. Utilities for obtaining objects via the collection interface.

View File

@ -1,7 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2005-2008 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright 2018-2023 Igalia, S.L. # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Provides support for synthesizing accessible input events.""" """Provides support for synthesizing accessible input events."""

View File

@ -1,7 +1,9 @@
# Utilities for obtaining information about accessible objects. #!/usr/bin/env python3
# #
# Copyright 2023 Igalia, S.L. # Copyright (c) 2024 Stormux
# Author: Joanmarie Diggs <jdiggs@igalia.com> # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
""" """
Utilities for obtaining information about accessible objects. Utilities for obtaining information about accessible objects.

View File

@ -1,7 +1,9 @@
# Utilities for obtaining information about containers supporting selection #!/usr/bin/env python3
# #
# Copyright 2023 Igalia, S.L. # Copyright (c) 2024 Stormux
# Author: Joanmarie Diggs <jdiggs@igalia.com> # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
""" """
Utilities for obtaining information about containers supporting selection. Utilities for obtaining information about containers supporting selection.

View File

@ -1,7 +1,9 @@
# Utilities for performing tasks related to accessibility inspection. #!/usr/bin/env python3
# #
# Copyright 2023 Igalia, S.L. # Copyright (c) 2024 Stormux
# Author: Joanmarie Diggs <jdiggs@igalia.com> # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
""" """
Utilities for performing tasks related to accessibility inspection. Utilities for performing tasks related to accessibility inspection.

View File

@ -1,7 +1,9 @@
# Utilities for finding all objects that meet a certain criteria. #!/usr/bin/env python3
# #
# Copyright 2023 Igalia, S.L. # Copyright (c) 2024 Stormux
# Author: Joanmarie Diggs <jdiggs@igalia.com> # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
""" """
Utilities for finding all objects that meet a certain criteria. Utilities for finding all objects that meet a certain criteria.

View File

@ -1,7 +1,9 @@
# Utilities for obtaining role-related information. #!/usr/bin/env python3
# #
# Copyright 2023 Igalia, S.L. # Copyright (c) 2024 Stormux
# Author: Joanmarie Diggs <jdiggs@igalia.com> # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
""" """
Utilities for obtaining role-related information. Utilities for obtaining role-related information.

View File

@ -1,7 +1,9 @@
# Utilities for obtaining state-related information. #!/usr/bin/env python3
# #
# Copyright 2023 Igalia, S.L. # Copyright (c) 2024 Stormux
# Author: Joanmarie Diggs <jdiggs@igalia.com> # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
""" """
Utilities for obtaining state-related information. Utilities for obtaining state-related information.

View File

@ -0,0 +1,25 @@
#!/usr/bin/env python3
#
# Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca

View File

@ -1,8 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2010-2011 Consorcio Fernando de los Rios. # Copyright (c) 2024 Stormux
# Author: Juanje Ojeda Croissier <jojeda@emergya.es> # Copyright (c) 2010-2012 The Orca Team
# Author: Javier Hernandez Antunez <jhernandez@emergya.es> # Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -18,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""JSON backend for Cthulhu settings""" """JSON backend for Cthulhu settings"""

View File

@ -1,6 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2005-2008 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -16,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Provides the default implementation for bookmarks in Cthulhu.""" """Provides the default implementation for bookmarks in Cthulhu."""

View File

@ -1,6 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2005-2009 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -16,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""A very experimental approach to the refreshable Braille display. This """A very experimental approach to the refreshable Braille display. This
module treats each line of the display as a sequential set of regions, where module treats each line of the display as a sequential set of regions, where

View File

@ -1,6 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2005-2009 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -16,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Utilities for obtaining braille presentations for objects.""" """Utilities for obtaining braille presentations for objects."""

View File

@ -1,6 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2012 Igalia, S.L. # Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -16,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Dictionary of abbreviated rolenames for use with braille.""" """Dictionary of abbreviated rolenames for use with braille."""

View File

@ -1,8 +1,9 @@
# -*- coding: utf-8 -*- #!/usr/bin/env python3
# Cthulhu
# #
# Copyright 2006-2008 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright 2011 The Cthulhu Team. # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -18,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Provides a graphical braille display, mainly for development tasks.""" """Provides a graphical braille display, mainly for development tasks."""

View File

@ -1,7 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2004-2009 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright 2010-2013 The Cthulhu Team # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Braille translation table names. These have been put in their own module """Braille translation table names. These have been put in their own module
so that we can present them in the correct language when users change the so that we can present them in the correct language when users change the

View File

@ -1,7 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2013-2015 Igalia, S.L. # Copyright (c) 2024 Stormux
# Author: Joanmarie Diggs <jdiggs@igalia.com> # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Provides an Cthulhu-controlled caret for text content.""" """Provides an Cthulhu-controlled caret for text content."""

View File

@ -1,6 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2010-2011 The Cthulhu Team # Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -16,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Implements generic chat support.""" """Implements generic chat support."""

View File

@ -1,7 +1,9 @@
# -*- coding: utf-8 -*- #!/usr/bin/env python3
# Cthulhu
# #
# Copyright 2004-2008 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Provides getCharacterName that maps punctuation marks and other """Provides getCharacterName that maps punctuation marks and other
individual characters into localized words.""" individual characters into localized words."""

View File

@ -1,7 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2004-2009 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright 2010-2013 The Cthulhu Team # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Command names which Cthulhu presents in speech and/or braille. These """Command names which Cthulhu presents in speech and/or braille. These
have been put in their own module so that we can present them in have been put in their own module so that we can present them in
@ -455,6 +460,9 @@ TOGGLE_SPEECH = _("Toggle the silencing of speech")
# This string describes that command. # This string describes that command.
TOGGLE_SPEECH_VERBOSITY = _("Toggle speech verbosity level") TOGGLE_SPEECH_VERBOSITY = _("Toggle speech verbosity level")
# Translators: this string is associated with the keyboard shortcut to toggle sleepmode
TOGGLE_SLEEP_MODE = _("Toggle sleep mode")
# Translators: this string is associated with the keyboard shortcut to quit # Translators: this string is associated with the keyboard shortcut to quit
# Cthulhu. # Cthulhu.
QUIT_CTHULHU = _("Quit the screen reader") QUIT_CTHULHU = _("Quit the screen reader")

View File

@ -1,8 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2014 Igalia, S.L. # Copyright (c) 2024 Stormux
# # Copyright (c) 2010-2012 The Orca Team
# Author: Joanmarie Diggs <jdiggs@igalia.com> # Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -18,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
__id__ = "$Id$" __id__ = "$Id$"
__version__ = "$Revision$" __version__ = "$Revision$"

View File

@ -1,6 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2010-2011 The Cthulhu Team # Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -16,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
""" A list of common keybindings and unbound keys """ A list of common keybindings and unbound keys
pulled out from default.py: getKeyBindings() pulled out from default.py: getKeyBindings()
@ -51,6 +57,9 @@ keymap = (
("BackSpace", defaultModifierMask, CTHULHU_MODIFIER_MASK, ("BackSpace", defaultModifierMask, CTHULHU_MODIFIER_MASK,
"bypassNextCommandHandler"), "bypassNextCommandHandler"),
("q", defaultModifierMask, CTHULHU_CTRL_ALT_MODIFIER_MASK, CTHULHU_SHIFT_MODIFIER_MASK,
"toggleSleepModeHandler"),
("q", defaultModifierMask, CTHULHU_MODIFIER_MASK, ("q", defaultModifierMask, CTHULHU_MODIFIER_MASK,
"shutdownHandler"), "shutdownHandler"),

View File

@ -1,8 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2004-2009 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright 2010-2011 The Cthulhu Team # Copyright (c) 2010-2012 The Orca Team
# Copyright 2012 Igalia, S.L. # Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -18,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""The main module for the Cthulhu screen reader.""" """The main module for the Cthulhu screen reader."""
@ -30,6 +34,108 @@ __copyright__ = "Copyright (c) 2004-2009 Sun Microsystems Inc." \
__license__ = "LGPL" __license__ = "LGPL"
import faulthandler import faulthandler
class APIHelper:
"""Helper class for plugin API interactions, including keybindings."""
def __init__(self, app):
"""Initialize the APIHelper.
Arguments:
- app: the Cthulhu application
"""
self.app = app
self._gestureBindings = {}
def registerGestureByString(self, function, name, gestureString,
inputEventType='default', normalizer='cthulhu',
learnModeEnabled=True, contextName=None):
"""Register a gesture by string.
Arguments:
- function: the function to call when the gesture is performed
- name: a human-readable name for this gesture
- gestureString: string representation of the gesture (e.g., 'kb:cthulhu+z')
- inputEventType: the type of input event
- normalizer: the normalizer to use
- learnModeEnabled: whether this should be available in learn mode
- contextName: the context for this gesture (e.g., plugin name)
Returns the binding ID or None if registration failed
"""
if not gestureString.startswith("kb:"):
return None
# Extract the key portion from the gesture string
key = gestureString.split(":", 1)[1]
# Handle Cthulhu modifier specially
if "cthulhu+" in key.lower():
from . import keybindings
key_parts = key.lower().split("+")
# Determine appropriate modifier mask
modifiers = keybindings.CTHULHU_MODIFIER_MASK
# Extract the final key (without modifiers)
final_key = key_parts[-1]
# Check for additional modifiers
if "shift" in key_parts:
modifiers = keybindings.CTHULHU_SHIFT_MODIFIER_MASK
elif "ctrl" in key_parts or "control" in key_parts:
modifiers = keybindings.CTHULHU_CTRL_MODIFIER_MASK
elif "alt" in key_parts:
modifiers = keybindings.CTHULHU_ALT_MODIFIER_MASK
# Create a keybinding handler
class GestureHandler:
def __init__(self, function, description):
self.function = function
self.description = description
def __call__(self, script, inputEvent):
return self.function(script, inputEvent)
handler = GestureHandler(function, name)
# Register the binding with the active script
from . import cthulhu_state
if cthulhu_state.activeScript:
bindings = cthulhu_state.activeScript.getKeyBindings()
binding = keybindings.KeyBinding(
final_key,
keybindings.defaultModifierMask,
modifiers,
handler)
bindings.add(binding)
# Store binding for later reference
if contextName not in self._gestureBindings:
self._gestureBindings[contextName] = []
self._gestureBindings[contextName].append(binding)
return binding
return None
def unregisterShortcut(self, binding, contextName=None):
"""Unregister a previously registered shortcut.
Arguments:
- binding: the binding to unregister
- contextName: the context for this gesture
"""
# Remove from script's keybindings
from . import cthulhu_state
if cthulhu_state.activeScript:
bindings = cthulhu_state.activeScript.getKeyBindings()
bindings.remove(binding)
# Remove from our tracking
if contextName in self._gestureBindings:
if binding in self._gestureBindings[contextName]:
self._gestureBindings[contextName].remove(binding)
import gi import gi
import importlib import importlib
import os import os
@ -70,7 +176,7 @@ from .ax_object import AXObject
from .ax_utilities import AXUtilities from .ax_utilities import AXUtilities
from .input_event import BrailleEvent from .input_event import BrailleEvent
from . import cmdnames from . import cmdnames
from . import plugin_system_manager from . import plugin_system_manager # This will now be your pluggy-based implementation
from . import guilabels from . import guilabels
from . import acss from . import acss
from . import text_attribute_names from . import text_attribute_names
@ -530,6 +636,55 @@ def loadUserSettings(script=None, inputEvent=None, skipReloadMessage=False):
return True return True
def _showPreferencesUI(script, prefs):
if cthulhu_state.cthulhuOS:
cthulhu_state.cthulhuOS.showGUI()
return
try:
module = importlib.import_module('.cthulhu_gui_prefs', 'cthulhu')
except Exception:
debug.printException(debug.LEVEL_SEVERE)
return
uiFile = os.path.join(cthulhu_platform.datadir,
cthulhu_platform.package,
"ui",
"cthulhu-setup.ui")
cthulhu_state.cthulhuOS = module.CthulhuSetupGUI(uiFile, "cthulhuSetupWindow", prefs)
cthulhu_state.cthulhuOS.init(script)
cthulhu_state.cthulhuOS.showGUI()
def showAppPreferencesGUI(script=None, inputEvent=None):
"""Displays the user interface to configure the settings for a
specific applications within Cthulhu and set up those app-specific
user preferences using a GUI.
Returns True to indicate the input event has been consumed.
"""
prefs = {}
for key in settings.userCustomizableSettings:
prefs[key] = _settingsManager.getSetting(key)
script = script or cthulhu_state.activeScript
_showPreferencesUI(script, prefs)
return True
def showPreferencesGUI(script=None, inputEvent=None):
"""Displays the user interface to configure Cthulhu and set up
user preferences using a GUI.
Returns True to indicate the input event has been consumed.
"""
prefs = _settingsManager.getGeneralSettings(_settingsManager.profile)
script = _scriptManager.getDefaultScript()
_showPreferencesUI(script, prefs)
return True
def addKeyGrab(binding): def addKeyGrab(binding):
""" Add a key grab for the given key binding.""" """ Add a key grab for the given key binding."""
@ -867,7 +1022,6 @@ class Cthulhu(GObject.Object):
GObject.Object.__init__(self) GObject.Object.__init__(self)
# add members # add members
self.resourceManager = resource_manager.ResourceManager(self) self.resourceManager = resource_manager.ResourceManager(self)
self.APIHelper = plugin_system_manager.APIHelper(self)
self.eventManager = _eventManager self.eventManager = _eventManager
self.settingsManager = _settingsManager self.settingsManager = _settingsManager
self.scriptManager = _scriptManager self.scriptManager = _scriptManager
@ -875,8 +1029,11 @@ class Cthulhu(GObject.Object):
self.dynamicApiManager = dynamic_api_manager.DynamicApiManager(self) self.dynamicApiManager = dynamic_api_manager.DynamicApiManager(self)
self.translationManager = translation_manager.TranslationManager(self) self.translationManager = translation_manager.TranslationManager(self)
self.debugManager = debug self.debugManager = debug
self.APIHelper = APIHelper(self)
self.createCompatAPI() self.createCompatAPI()
self.pluginSystemManager = plugin_system_manager.PluginSystemManager(self) self.pluginSystemManager = plugin_system_manager.PluginSystemManager(self)
# Scan for available plugins at startup
self.pluginSystemManager.rescanPlugins()
def getAPIHelper(self): def getAPIHelper(self):
return self.APIHelper return self.APIHelper
def getPluginSystemManager(self): def getPluginSystemManager(self):
@ -934,6 +1091,7 @@ class Cthulhu(GObject.Object):
# cthulhu lets say, special compat handling.... # cthulhu lets say, special compat handling....
self.getDynamicApiManager().registerAPI('EmitRegionChanged', emitRegionChanged) self.getDynamicApiManager().registerAPI('EmitRegionChanged', emitRegionChanged)
self.getDynamicApiManager().registerAPI('LoadUserSettings', loadUserSettings) self.getDynamicApiManager().registerAPI('LoadUserSettings', loadUserSettings)
self.getDynamicApiManager().registerAPI('APIHelper', self.APIHelper)
cthulhuApp = Cthulhu() cthulhuApp = Cthulhu()

View File

@ -0,0 +1,27 @@
#!/usr/bin/env python3
#
# Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
version = "2025.04.04"
codeName = "testing"

View File

@ -1,9 +1,9 @@
#!@PYTHON@ #!@PYTHON@
# #
# Cthulhu # Copyright (c) 2024 Stormux
# # Copyright (c) 2010-2012 The Orca Team
# Copyright 2010-2012 The Cthulhu Team # Copyright (c) 2012 Igalia, S.L.
# Copyright 2012 Igalia, S.L. # Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -19,13 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
__id__ = "$Id$" # Fork of Orca Screen Reader (GNOME)
__version__ = "$Revision$" # Original source: https://gitlab.gnome.org/GNOME/orca
__date__ = "$Date$"
__copyright__ = "Copyright (c) 2010-2012 The Cthulhu Team" \
"Copyright (c) 2012 Igalia, S.L."
__license__ = "LGPL"
import argparse import argparse
import gi import gi

View File

@ -1,6 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2005-2009 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -16,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Displays a GUI for the user to quit Cthulhu.""" """Displays a GUI for the user to quit Cthulhu."""

View File

@ -1,6 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2005-2009 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -16,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Displays a GUI for the Cthulhu Find window""" """Displays a GUI for the Cthulhu Find window"""

View File

@ -1,8 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2012 Igalia, S.L. # Copyright (c) 2024 Stormux
# # Copyright (c) 2010-2012 The Orca Team
# Author: Joanmarie Diggs <jdiggs@igalia.com> # Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -18,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Displays a GUI for Cthulhu navigation list dialogs""" """Displays a GUI for Cthulhu navigation list dialogs"""

View File

@ -1,6 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2005-2009 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -16,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Displays a GUI for the user to set Cthulhu preferences.""" """Displays a GUI for the user to set Cthulhu preferences."""

View File

@ -1,8 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2010 Consorcio Fernando de los Rios. # Copyright (c) 2024 Stormux
# Author: Javier Hernandez Antunez <jhernandez@emergya.es> # Copyright (c) 2010-2012 The Orca Team
# Author: Alejandro Leiva <aleiva@emergya.es> # Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -18,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Displays the Save Profile As dialog.""" """Displays the Save Profile As dialog."""

View File

@ -17,6 +17,8 @@
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
from cthulhu import cthulhuVersion
"""Holds platform-specific settings. """Holds platform-specific settings.
""" """
@ -28,7 +30,7 @@ __license__ = "LGPL"
# $CTHULHU_VERSION # $CTHULHU_VERSION
# #
version = "@VERSION@" version = f"Cthulhu screen reader version {cthulhuVersion.version}-{cthulhuVersion.codeName}"
# The revision if built from git; otherwise an empty string # The revision if built from git; otherwise an empty string
# #

View File

@ -1,7 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2005-2009 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright 2010 Joanmarie Diggs, Mesar Hameed # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Holds state that is shared among many modules. """Holds state that is shared among many modules.
""" """

View File

@ -1,7 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2005-2008 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright 2016-2023 Igalia, S.L. # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Module for date and time presentation""" """Module for date and time presentation"""

View File

@ -1,6 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2005-2008 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -16,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Provides debug utilities for Cthulhu. Debugging is managed by a debug """Provides debug utilities for Cthulhu. Debugging is managed by a debug
level, which is held in the debugLevel field. All other methods take level, which is held in the debugLevel field. All other methods take

View File

@ -1,6 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2010 Joanmarie Diggs, Mesar Hameed. # Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -16,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
""" A list of common keybindings and unbound keys """ A list of common keybindings and unbound keys
pulled out from default.py: __getDesktopBindings() pulled out from default.py: __getDesktopBindings()

View File

@ -1,3 +1,28 @@
#!/usr/bin/env python3
#
# Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
import gi import gi
from gi.repository import GObject from gi.repository import GObject

View File

@ -1,7 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2011. Cthulhu Team. # Copyright (c) 2024 Stormux
# Author: Joanmarie Diggs <joanmarie.diggs@gmail.com> # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
__id__ = "$Id$" __id__ = "$Id$"
__version__ = "$Revision$" __version__ = "$Revision$"

View File

@ -1,7 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2006-2008 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright 2022 Igalia, S.L. # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Provides support for a flat review find.""" """Provides support for a flat review find."""

View File

@ -1,7 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2005-2008 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright 2016 Igalia, S.L. # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Provides the default implementation for flat review for Cthulhu.""" """Provides the default implementation for flat review for Cthulhu."""

View File

@ -1,7 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2005-2008 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright 2016-2023 Igalia, S.L. # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Module for flat-review commands""" """Module for flat-review commands"""

View File

@ -1,6 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2004-2009 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -16,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Manages the formatting settings for Cthulhu.""" """Manages the formatting settings for Cthulhu."""

View File

@ -1,7 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2009 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright 2015-2016 Igalia, S.L. # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Superclass of classes used to generate presentations for objects.""" """Superclass of classes used to generate presentations for objects."""

View File

@ -1,7 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2004-2009 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright 2010-2013 The Cthulhu Team # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Labels for Cthulhu's GUIs. These have been put in their own module so that we """Labels for Cthulhu's GUIs. These have been put in their own module so that we
can present them in the correct language when users change the language on the can present them in the correct language when users change the language on the

View File

@ -1,7 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2023 Igalia, S.L. # Copyright (c) 2024 Stormux
# Author: Joanmarie Diggs <jdiggs@igalia.com> # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Module for drawing highlights over an area of interest.""" """Module for drawing highlights over an area of interest."""

View File

@ -1,7 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2005-2008 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright 2011-2016 Igalia, S.L. # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Provides support for handling input events.""" """Provides support for handling input events."""

View File

@ -1,6 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2005-2008 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -16,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Provides support for defining keybindings and matching them to input """Provides support for defining keybindings and matching them to input
events.""" events."""

View File

@ -1,6 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2006-2008 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -16,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Exposes a dictionary, keynames, that maps key events """Exposes a dictionary, keynames, that maps key events
into localized words.""" into localized words."""

View File

@ -1,8 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright (C) 2011-2013 Igalia, S.L. # Copyright (c) 2024 Stormux
# # Copyright (c) 2010-2012 The Orca Team
# Author: Joanmarie Diggs <jdiggs@igalia.com> # Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -18,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Heuristic means to infer the functional/displayed label of a widget.""" """Heuristic means to infer the functional/displayed label of a widget."""

View File

@ -1,6 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2010 Joanmarie Diggs, Mesar Hameed. # Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -16,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
""" A list of common keybindings and unbound keys """ A list of common keybindings and unbound keys
pulled out from default.py: __getLaptopBindings() pulled out from default.py: __getLaptopBindings()

View File

@ -1,7 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2005-2008 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright 2016-2023 Igalia, S.L. # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Module for learn mode""" """Module for learn mode"""

View File

@ -1,3 +1,28 @@
#!/usr/bin/env python3
#
# Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
import gi import gi
gi.require_version("Atspi", "2.0") gi.require_version("Atspi", "2.0")
from gi.repository import Atspi from gi.repository import Atspi

View File

@ -1,9 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2008 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright 2012 Igalia, S.L. # Copyright (c) 2010-2012 The Orca Team
# # Copyright (c) 2012 Igalia, S.L.
# Author: Joanmarie Diggs <jdiggs@igalia.com> # Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -19,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Output logger for regression testing.""" """Output logger for regression testing."""

View File

@ -1,8 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2014 Igalia, S.L. # Copyright (c) 2024 Stormux
# # Copyright (c) 2010-2012 The Orca Team
# Author: Joanmarie Diggs <jdiggs@igalia.com> # Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -18,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
__id__ = "$Id$" __id__ = "$Id$"
__version__ = "$Revision$" __version__ = "$Revision$"

View File

@ -1,7 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2004-2009 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright 2010-2013 The Cthulhu Team # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Messages which Cthulhu presents in speech and/or braille. These """Messages which Cthulhu presents in speech and/or braille. These
have been put in their own module so that we can present them in have been put in their own module so that we can present them in
@ -2294,7 +2299,12 @@ SPOKEN_ELLIPSIS = _(" dot dot dot")
START_CTHULHU = _("Cthulhu welcomes you.") START_CTHULHU = _("Cthulhu welcomes you.")
# Translators: This message is presented to the user when Cthulhu is quit. # Translators: This message is presented to the user when Cthulhu is quit.
STOP_CTHULHU = _("Cthulhu lerks beneath the waves.") STOP_CTHULHU = _("Cthulhu lurks beneath the waves.")
# Sleep Mode
# Translators: This message is presented to the user when Cthulhu enters or leaves sleep mode.
SLEEP_MODE_ENABLED_FOR = _("Sleep mode enabled for %s")
SLEEP_MODE_DISABLED_FOR = _("Sleep mode disabled for %s")
# Translators: This message means speech synthesis is not installed or working. # Translators: This message means speech synthesis is not installed or working.
SPEECH_UNAVAILABLE = _("Speech is unavailable.") SPEECH_UNAVAILABLE = _("Speech is unavailable.")

View File

@ -1,7 +1,9 @@
# Mouse reviewer for Cthulhu #!/usr/bin/env python3
# #
# Copyright 2008 Eitan Isaacson # Copyright (c) 2024 Stormux
# Copyright 2016 Igalia, S.L. # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Mouse review mode.""" """Mouse review mode."""

View File

@ -1,10 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2023 Igalia, S.L. # Copyright (c) 2024 Stormux
# Author: Joanmarie Diggs <jdiggs@igalia.com> # Copyright (c) 2010-2012 The Orca Team
# Based on the feature created by: # Copyright (c) 2012 Igalia, S.L.
# Author: Jose Vilmar <vilmar@informal.com.br> # Copyright (c) 2005-2010 Sun Microsystems Inc.
# Copyright 2010 Informal Informatica LTDA.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -20,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Module for notification messages""" """Module for notification messages"""

View File

@ -1,7 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2023 The Cthulhu Team # Copyright (c) 2024 Stormux
# Author: Rynhardt Kruger <rynkruger@gmail.com> # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Provides ability to navigate objects hierarchically.""" """Provides ability to navigate objects hierarchically."""

View File

@ -1,7 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2004-2009 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright 2010-2013 The Cthulhu Team # Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Propeerties of accessible objects. These have been put in their own module """Propeerties of accessible objects. These have been put in their own module
so that we can present them in the correct language when users change the so that we can present them in the correct language when users change the

View File

@ -1,6 +1,9 @@
# Cthulhu #!/usr/bin/env python3
# #
# Copyright 2006-2008 Sun Microsystems Inc. # Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
# #
# This library is free software; you can redistribute it and/or # This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -16,6 +19,9 @@
# License along with this library; if not, write to the # License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA. # Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Provides getPhoneticName method that maps each letter of the """Provides getPhoneticName method that maps each letter of the
alphabet into its localized phonetic equivalent.""" alphabet into its localized phonetic equivalent."""

View File

@ -1,160 +1,92 @@
import os, inspect #!/usr/bin/env python3
import gi # Copyright (c) 2024 Stormux
from gi.repository import GObject #
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
class Plugin(): """Base class for Cthulhu plugins using pluggy."""
#__gtype_name__ = 'BasePlugin'
def __init__(self, *args, **kwargs): import os
self.API = None import logging
self.pluginInfo = None
self.moduleDir = '' # Import pluggy for hook specifications
self.hidden = False try:
self.moduleName = '' import pluggy
cthulhu_hookimpl = pluggy.HookimplMarker("cthulhu")
PLUGGY_AVAILABLE = True
logging.getLogger(__name__).info("Successfully imported pluggy")
except ImportError:
# Fallback if pluggy is not available
def cthulhu_hookimpl(func=None, **kwargs):
"""Fallback decorator when pluggy is not available.
This is a no-op decorator that returns the original function.
It allows the code to continue working without pluggy, though
plugins will be disabled.
"""
if func is None:
return lambda f: f
return func
PLUGGY_AVAILABLE = False
logging.getLogger(__name__).warning("Pluggy not available, plugins will be disabled")
import traceback
logging.getLogger(__name__).debug(traceback.format_exc())
logger = logging.getLogger(__name__)
class Plugin:
"""Base class for Cthulhu plugins."""
def __init__(self):
"""Initialize the plugin with default attributes."""
self.app = None
self.plugin_info = None
self.module_name = ''
self.name = '' self.name = ''
self.version = '' self.version = ''
self.website = ''
self.authors = []
self.buildIn = False
self.description = '' self.description = ''
self.iconName = ''
self.copyright = '' def set_app(self, app):
self.dependencies = False """Set the application reference."""
self.helpUri = ''
self.dataDir = ''
self.translationContext = None
def setApp(self, app):
self.app = app self.app = app
self.dynamicApiManager = app.getDynamicApiManager()
self.signalManager = app.getSignalManager()
def getApp(self): def set_plugin_info(self, plugin_info):
return self.app """Set plugin information and extract relevant attributes."""
def setPluginInfo(self, pluginInfo): self.plugin_info = plugin_info
self.pluginInfo = pluginInfo if plugin_info:
self.updatePluginInfoAttributes() self.module_name = getattr(plugin_info, 'module_name', '')
def getPluginInfo(self): self.name = getattr(plugin_info, 'name', '')
return self.pluginInfo self.version = getattr(plugin_info, 'version', '')
def updatePluginInfoAttributes(self): self.description = getattr(plugin_info, 'description', '')
self.moduleDir = ''
self.hidden = False @cthulhu_hookimpl
self.moduleName = '' def activate(self, plugin=None):
self.name = '' """Activate the plugin. Override this in subclasses."""
self.version = '' if plugin is not None and plugin is not self:
self.website = ''
self.authors = []
self.buildIn = False
self.description = ''
self.iconName = ''
self.copyright = ''
self.dependencies = False
self.helpUri = ''
self.dataDir = ''
pluginInfo = self.getPluginInfo()
if pluginInfo == None:
return return
self.moduleName = self.getApp().getPluginSystemManager().getPluginModuleName(pluginInfo) logger.info(f"Activating plugin: {self.name}")
self.name = self.getApp().getPluginSystemManager().getPluginName(pluginInfo)
self.version = self.getApp().getPluginSystemManager().getPluginVersion(pluginInfo)
self.moduleDir = self.getApp().getPluginSystemManager().getPluginModuleDir(pluginInfo)
self.buildIn = self.getApp().getPluginSystemManager().isPluginBuildIn(pluginInfo)
self.description = self.getApp().getPluginSystemManager().getPluginDescription(pluginInfo)
self.hidden = self.getApp().getPluginSystemManager().isPluginHidden(pluginInfo)
self.website = self.getApp().getPluginSystemManager().getPluginWebsite(pluginInfo)
self.authors = self.getApp().getPluginSystemManager().getPluginAuthors(pluginInfo)
self.iconName = self.getApp().getPluginSystemManager().getPluginIconName(pluginInfo)
self.copyright = self.getApp().getPluginSystemManager().getPluginCopyright(pluginInfo)
self.dependencies = self.getApp().getPluginSystemManager().getPluginDependencies(pluginInfo)
#settings = self.getApp().getPluginSystemManager().getPluginSettings(pluginInfo) @cthulhu_hookimpl
#hasDependencies = self.getApp().getPluginSystemManager().hasPluginDependency(pluginInfo) def deactivate(self, plugin=None):
"""Deactivate the plugin. Override this in subclasses."""
if plugin is not None and plugin is not self:
return
logger.info(f"Deactivating plugin: {self.name}")
#externalData = self.getApp().getPluginSystemManager().getPluginExternalData(pluginInfo) def registerGestureByString(self, function, name, gestureString, learnModeEnabled=True):
self.helpUri = self.getApp().getPluginSystemManager().getPlugingetHelpUri(pluginInfo) """Register a gesture by string."""
self.dataDir = self.getApp().getPluginSystemManager().getPluginDataDir(pluginInfo) if self.app:
self.updateTranslationContext() api_helper = self.app.getAPIHelper()
if api_helper:
def updateTranslationContext(self, domain = None, localeDir = None, language = None, fallbackToCthulhuTranslation = True): return api_helper.registerGestureByString(
self.translationContext = None function,
useLocaleDir = '{}/locale/'.format(self.getModuleDir()) name,
if localeDir: gestureString,
if os.path.isdir(localeDir): 'default',
useLocaleDir = localeDir 'cthulhu',
useName = self.getModuleName() learnModeEnabled,
useDomain = useName contextName=self.module_name
if domain: )
useDomain = domain
useLanguage = None
if language:
useLanguage = language
self.translationContext = self.getApp().getTranslationManager().initTranslation(useName, domain=useDomain, localeDir=useLocaleDir, language=useLanguage, fallbackToCthulhuTranslation=fallbackToCthulhuTranslation)
# Point _ to the translation object in the globals namespace of the caller frame
try:
callerFrame = inspect.currentframe().f_back
# Install our gettext and ngettext function to the upper frame
callerFrame.f_globals['_'] = self.translationContext.gettext
callerFrame.f_globals['ngettext'] = self.translationContext.ngettext
finally:
del callerFrame # Avoid reference problems with frames (per python docs)
def getTranslationContext(self):
return self.translationContext
def isPluginBuildIn(self):
return self.buildIn
def isPluginHidden(self):
return self.hidden
def getAuthors(self):
return self.authors
def getCopyright(self):
return self.copyright
def getDataDir(self):
return self.dataDir
def getDependencies(self):
return self.dependencies
def getDescription(self):
return self.description
def getgetHelpUri(self):
return self.helpUri
def getIconName(self):
return self.iconName
def getModuleDir(self):
return self.moduleDir
def getModuleName(self):
return self.moduleName
def getName(self):
return self.name
def getVersion(self):
return self.version
def getWebsite(self):
return self.website
def getSetting(key):
#self.getModuleName())
return None return None
def setSetting(key, value):
#self.getModuleName())
pass
def registerGestureByString(self, function, name, gestureString, learnModeEnabled = True):
keybinding = self.getApp().getAPIHelper().registerGestureByString(function, name, gestureString, 'default', 'cthulhu', learnModeEnabled, contextName = self.getModuleName())
return keybinding
def unregisterShortcut(self, function, name, gestureString, learnModeEnabled = True):
ok = self.getApp().getAPIHelper().unregisterShortcut(keybinding, contextName = self.getModuleName())
return ok
def registerSignal(self, signalName, signalFlag = GObject.SignalFlags.RUN_LAST, closure = GObject.TYPE_NONE, accumulator=()):
ok = self.signalManager.registerSignal(signalName, signalFlag, closure, accumulator, contextName = self.getModuleName())
return ok
def unregisterSignal(self, signalName):
# how to unregister?
pass
def connectSignal(self, signalName, function, param = None):
signalID = self.signalManager.connectSignal(signalName, function, param, contextName = self.getModuleName())
return signalID
def disconnectSignalByFunction(self, function):
# need get mapped function
mappedFunction = function
self.signalManager.disconnectSignalByFunction(mappedFunction, contextName = self.getModuleName())
def registerAPI(self, key, value, application = ''):
ok = self.dynamicApiManager.registerAPI(key, value, application = application, contextName = self.getModuleName())
return ok
def unregisterAPI(self, key, application = ''):
self.dynamicApiManager.unregisterAPI(key, application = application, contextName = self.getModuleName())

View File

@ -1,520 +1,469 @@
#!/bin/python #!/usr/bin/env python3
"""PluginManager for loading cthulhu plugins.""" # Copyright (c) 2024 Stormux
import os, inspect, sys, tarfile, shutil #
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
"""Plugin System Manager for Cthulhu using pluggy."""
import os
import inspect
import importlib.util
import logging
from enum import IntEnum from enum import IntEnum
version = sys.version[:3] # we only need major.minor version. # Import pluggy if available
if version in ["3.3","3.4"]: try:
from importlib.machinery import SourceFileLoader import pluggy
else: # Python 3.5+, no support for python < 3.3. PLUGGY_AVAILABLE = True
import importlib.util except ImportError:
PLUGGY_AVAILABLE = False
logging.getLogger(__name__).info("Pluggy not available, plugins will be disabled")
import gi # Set to True for more detailed plugin loading debug info
gi.require_version('Peas', '1.0') PLUGIN_DEBUG = True
from gi.repository import GObject
from gi.repository import Peas
gi.require_version('Atspi', '2.0') logger = logging.getLogger(__name__)
from gi.repository import Atspi if PLUGIN_DEBUG:
logger.setLevel(logging.DEBUG)
from cthulhu import resource_manager
class API(GObject.GObject):
"""Interface that gives access to all the objects of Cthulhu."""
def __init__(self, app):
GObject.GObject.__init__(self)
self.app = app
class PluginType(IntEnum): class PluginType(IntEnum):
"""Types of plugins we support, depending on their directory location.""" """Types of plugins we support."""
# pylint: disable=comparison-with-callable,inconsistent-return-statements,no-else-return
# SYSTEM: provides system wide plugins
SYSTEM = 1 SYSTEM = 1
# USER: provides per user plugin
USER = 2 USER = 2
def __str__(self):
if self.value == PluginType.SYSTEM:
return _("System plugin")
elif self.value == PluginType.USER:
return _("User plugin")
def get_root_dir(self): def get_root_dir(self):
"""Returns the directory where this type of plugins can be found.""" """Returns the directory where this type of plugins can be found."""
if self.value == PluginType.SYSTEM: if self.value == PluginType.SYSTEM:
return os.path.dirname(os.path.realpath(os.path.abspath(inspect.getfile(inspect.currentframe())))) + '/plugins' current_file = inspect.getfile(inspect.currentframe())
current_dir = os.path.dirname(os.path.realpath(os.path.abspath(current_file)))
return os.path.join(current_dir, 'plugins')
elif self.value == PluginType.USER: elif self.value == PluginType.USER:
return os.path.expanduser('~') + '/.local/share/cthulhu/plugins' return os.path.expanduser('~/.local/share/cthulhu/plugins')
class PluginSystemManager(): class PluginInfo:
"""Cthulhu Plugin Manager to handle a set of plugins. """Information about a plugin."""
Attributes:
DEFAULT_LOADERS (tuple): Default loaders used by the plugin manager. For def __init__(self, name, module_name, module_dir, metadata=None):
possible values see self.name = name
https://developer.gnome.org/libpeas/stable/PeasEngine.html#peas-engine-enable-loader self.module_name = module_name
""" self.module_dir = module_dir
DEFAULT_LOADERS = ("python3", ) self.metadata = metadata or {}
self.builtin = False
self.hidden = False
self.module = None
self.instance = None
self.loaded = False
def get_module_name(self):
return self.module_name
def get_name(self):
return self.metadata.get('name', self.name)
def get_version(self):
return self.metadata.get('version', '0.0.0')
def get_description(self):
return self.metadata.get('description', '')
def get_module_dir(self):
return self.module_dir
class PluginSystemManager:
"""Cthulhu Plugin Manager using pluggy."""
def __init__(self, app): def __init__(self, app):
self.app = app self.app = app
self.engine = Peas.Engine.get_default() logger.info("Initializing PluginSystemManager")
for loader in self.DEFAULT_LOADERS: # Initialize plugin manager
self.engine.enable_loader(loader) if PLUGGY_AVAILABLE:
logger.info("Pluggy is available, setting up plugin manager")
self.plugin_manager = pluggy.PluginManager("cthulhu")
self._setupPluginsDir() # Define hook specifications
self._setupExtensionSet() hook_spec = pluggy.HookspecMarker("cthulhu")
class CthulhuHookSpecs:
@hook_spec
def activate(self, plugin=None):
"""Called when the plugin is activated."""
pass
@hook_spec
def deactivate(self, plugin=None):
"""Called when the plugin is deactivated."""
pass
logger.info("Adding hook specifications to plugin manager")
self.plugin_manager.add_hookspecs(CthulhuHookSpecs)
else:
logger.warning("Pluggy is not available, plugins will be disabled")
self.plugin_manager = None
# Plugin storage
self._plugins = {} # module_name -> PluginInfo
self._active_plugins = []
# Create plugin directories
self._setup_plugin_dirs()
# Log available plugins directory paths
logger.info(f"System plugins directory: {PluginType.SYSTEM.get_root_dir()}")
logger.info(f"User plugins directory: {PluginType.USER.get_root_dir()}")
def _setup_plugin_dirs(self):
"""Ensure plugin directories exist."""
os.makedirs(PluginType.SYSTEM.get_root_dir(), exist_ok=True)
os.makedirs(PluginType.USER.get_root_dir(), exist_ok=True)
if self.app:
self.gsettingsManager = self.app.getSettingsManager()
# settings else:
# settings self.gsettingsManager = gsettings_manager.getSettingsManager(self.app)
self._activePlugins = []
self._ignorePluginModulePath = []
@property @property
def plugins(self): def plugins(self):
"""Gets the engine's plugin list.""" """Get all available plugins."""
return self.engine.get_plugin_list() return list(self._plugins.values())
@classmethod
def getPluginType(cls, pluginInfo):
"""Gets the PluginType for the specified Peas.PluginInfo."""
paths = [pluginInfo.get_data_dir(), PluginType.SYSTEM.get_root_dir()]
if os.path.commonprefix(paths) == PluginType.SYSTEM.get_root_dir():
return PluginType.SYSTEM
return PluginType.USER
def getExtension(self, pluginInfo):
if not pluginInfo:
return None
return self.extension_set.get_extension(pluginInfo)
def rescanPlugins(self):
self.engine.garbage_collect()
self.engine.rescan_plugins()
def getApp(self): def getApp(self):
return self.app return self.app
def getPluginInfoByName(self, pluginName, pluginType=PluginType.USER):
"""Gets the plugin info for the specified plugin name.
Args:
pluginName (str): The name from the .plugin file of the module.
Returns:
Peas.PluginInfo: The plugin info if it exists. Otherwise, `None`.
"""
for pluginInfo in self.plugins:
if pluginInfo.get_module_name() == pluginName and PluginSystemManager.getPluginType(pluginInfo) == pluginType:
return pluginInfo
return None
def getActivePlugins(self):
return self._activePlugins
def setActivePlugins(self, activePlugins):
self._activePlugins = activePlugins
self.syncAllPluginsActive()
def isPluginBuildIn(self, pluginInfo):
return pluginInfo.is_builtin()
def isPluginHidden(self, pluginInfo):
return pluginInfo.is_hidden()
def getPluginAuthors(self, pluginInfo):
return pluginInfo.get_authors()
def getPluginCopyright(self, pluginInfo):
return pluginInfo.get_copyright()
def getPluginDataDir(self, pluginInfo):
return pluginInfo.get_data_dir()
def getPluginDependencies(self, pluginInfo):
return pluginInfo.get_dependencies()
def getPluginDescription(self, pluginInfo):
return pluginInfo.get_description()
def getPlugingetHelpUri(self, pluginInfo):
return pluginInfo.get_help_uri()
def getPluginIconName(self, pluginInfo):
return pluginInfo.get_icon_name()
def getPluginModuleDir(self, pluginInfo):
return pluginInfo.get_module_dir()
def getPluginModuleName(self, pluginInfo):
return pluginInfo.get_module_name()
def getPluginName(self, pluginInfo):
return pluginInfo.get_name()
def getPluginSettings(self, pluginInfo):
return pluginInfo.get_settings()
def getPluginVersion(self, pluginInfo):
return pluginInfo.get_version()
def getPluginWebsite(self, pluginInfo):
return pluginInfo.get_website()
# has_dependency and get_external_data seems broken-> takes exactly 2 arguments (1 given) but documentation doesnt say any parameter
#def hasPluginDependency(self, pluginInfo):
# return pluginInfo.has_dependency()
#def getPluginExternalData(self, pluginInfo):
# return pluginInfo.get_external_data()
def isPluginAvailable(self, pluginInfo):
try:
return pluginInfo.is_available()
except:
return False
def isPluginLoaded(self, pluginInfo):
try:
return pluginInfo.is_loaded()
except:
return False
def getIgnoredPlugins(self): def rescanPlugins(self):
return self._ignorePluginModulePath """Scan for plugins in the plugin directories."""
def setIgnoredPlugins(self, pluginModulePath, ignored): old_plugins = self._plugins.copy()
if pluginModulePath.endswith('/'): self._plugins = {}
pluginModulePath = pluginModulePath[:-1]
if ignored: # Scan system and user plugins
if not pluginModulePath in self.getIgnoredPlugins(): self._scan_plugins_in_directory(PluginType.SYSTEM.get_root_dir())
self._ignorePluginModulePath.append(pluginModulePath) self._scan_plugins_in_directory(PluginType.USER.get_root_dir())
# Preserve state for already loaded plugins
for name, old_info in old_plugins.items():
if name in self._plugins and old_info.loaded:
self._plugins[name].loaded = True
self._plugins[name].instance = old_info.instance
self._plugins[name].module = old_info.module
def _scan_plugins_in_directory(self, directory):
"""Scan for plugins in a directory."""
if not os.path.exists(directory) or not os.path.isdir(directory):
logger.warning(f"Plugin directory not found or not a directory: {directory}")
return
logger.info(f"Scanning for plugins in directory: {directory}")
for item in os.listdir(directory):
plugin_dir = os.path.join(directory, item)
if not os.path.isdir(plugin_dir):
continue
# Check for the traditional structure first (plugin.py & plugin.info)
plugin_file = os.path.join(plugin_dir, "plugin.py")
metadata_file = os.path.join(plugin_dir, "plugin.info")
# Fall back to [PluginName].py if plugin.py doesn't exist
if not os.path.isfile(plugin_file):
alternative_plugin_file = os.path.join(plugin_dir, f"{item}.py")
if os.path.isfile(alternative_plugin_file):
plugin_file = alternative_plugin_file
logger.info(f"Using alternative plugin file: {alternative_plugin_file}")
# Check if we have any valid plugin file
if os.path.isfile(plugin_file):
# Extract plugin info
module_name = os.path.basename(plugin_dir)
logger.info(f"Found plugin: {module_name} in {plugin_dir}")
metadata = self._load_plugin_metadata(metadata_file)
plugin_info = PluginInfo(
metadata.get('name', module_name),
module_name,
plugin_dir,
metadata
)
# Check if it's a built-in or hidden plugin
plugin_info.builtin = metadata.get('builtin', 'false').lower() == 'true'
plugin_info.hidden = metadata.get('hidden', 'false').lower() == 'true'
logger.info(f"Adding plugin to registry: {module_name}")
self._plugins[module_name] = plugin_info
else: else:
if pluginModulePath in self.getIgnoredPlugins(): logger.warning(f"No plugin file found in directory: {plugin_dir}")
self._ignorePluginModulePath.remove(pluginModulePath)
def _load_plugin_metadata(self, metadata_file):
"""Load plugin metadata from a file."""
metadata = {}
if os.path.isfile(metadata_file):
try:
with open(metadata_file, 'r') as f:
for line in f:
line = line.strip()
if not line or line.startswith('#'):
continue
if '=' in line:
key, value = line.split('=', 1)
metadata[key.strip()] = value.strip()
except Exception as e:
logger.error(f"Error loading plugin metadata: {e}")
return metadata
def getActivePlugins(self):
"""Get the list of active plugin names."""
return self._active_plugins
def setActivePlugins(self, activePlugins):
"""Set active plugins and sync their state."""
logger.info(f"Setting active plugins: {activePlugins}")
# Make sure we have scanned for plugins first
if not self._plugins:
logger.info("No plugins found, rescanning...")
self.rescanPlugins()
self._active_plugins = activePlugins
# Log active vs available plugins
available_plugins = [p.get_module_name() for p in self.plugins]
logger.info(f"Available plugins: {available_plugins}")
logger.info(f"Active plugins: {self._active_plugins}")
# Find missing plugins
missing_plugins = [p for p in self._active_plugins if p not in available_plugins]
if missing_plugins:
logger.warning(f"Active plugins not found: {missing_plugins}")
self.syncAllPluginsActive()
def setPluginActive(self, pluginInfo, active): def setPluginActive(self, pluginInfo, active):
if self.isPluginBuildIn(pluginInfo): """Set the active state of a plugin."""
if pluginInfo.builtin:
active = True active = True
pluginName = self.getPluginModuleName(pluginInfo)
pluginName = pluginInfo.get_module_name()
if active: if active:
if not pluginName in self.getActivePlugins(): if pluginName not in self.getActivePlugins():
if self.loadPlugin(pluginInfo): if self.loadPlugin(pluginInfo):
self._activePlugins.append(pluginName ) self._active_plugins.append(pluginName)
else: else:
if pluginName in self.getActivePlugins(): if pluginName in self.getActivePlugins():
if self.unloadPlugin(pluginInfo): if self.unloadPlugin(pluginInfo):
self._activePlugins.remove(pluginName ) self._active_plugins.remove(pluginName)
def isPluginActive(self, pluginInfo): def isPluginActive(self, pluginInfo):
if self.isPluginBuildIn(pluginInfo): """Check if a plugin is active."""
return True module_name = pluginInfo.get_module_name()
if self.isPluginLoaded(pluginInfo):
return True
active_plugin_names = self.getActivePlugins()
return self.getPluginModuleName(pluginInfo) in active_plugin_names
def syncAllPluginsActive(self, ForceAllPlugins=False):
self.unloadAllPlugins(ForceAllPlugins)
self.loadAllPlugins(ForceAllPlugins)
def loadAllPlugins(self, ForceAllPlugins=False): # Builtin plugins are always active
"""Loads plugins from settings.""" if pluginInfo.builtin:
logger.debug(f"Plugin {module_name} is builtin, active by default")
return True
# If a plugin is already loaded, it's active
if pluginInfo.loaded:
logger.debug(f"Plugin {module_name} is already loaded, considered active")
return True
# Check case-insensitive match in active plugins list
active_plugins = self.getActivePlugins()
# Try exact match first
if module_name in active_plugins:
logger.debug(f"Plugin {module_name} found in active plugins list")
return True
# Try case-insensitive match
module_name_lower = module_name.lower()
is_active = any(plugin.lower() == module_name_lower for plugin in active_plugins)
if is_active:
logger.debug(f"Plugin {module_name} found in active plugins list (case-insensitive match)")
else:
logger.debug(f"Plugin {module_name} not found in active plugins list")
return is_active
def syncAllPluginsActive(self):
"""Sync the active state of all plugins."""
logger.info("Syncing active state of all plugins")
# Log plugin status before syncing
if PLUGIN_DEBUG:
for pluginInfo in self.plugins: for pluginInfo in self.plugins:
if self.isPluginActive(pluginInfo) or ForceAllPlugins: is_active = self.isPluginActive(pluginInfo)
self.loadPlugin(pluginInfo) is_loaded = pluginInfo.loaded
logger.debug(f"Plugin {pluginInfo.get_module_name()}: active={is_active}, loaded={is_loaded}")
def loadPlugin(self, pluginInfo): # First unload inactive plugins
resourceManager = self.getApp().getResourceManager()
moduleName = pluginInfo.get_module_name()
try:
if pluginInfo not in self.plugins:
print("Plugin missing: {}".format(moduleName))
return False
resourceManager.addResourceContext(moduleName)
self.engine.load_plugin(pluginInfo)
except Exception as e:
print('loadPlugin:',e)
return False
return True
def unloadAllPlugins(self, ForceAllPlugins=False):
"""Loads plugins from settings."""
for pluginInfo in self.plugins: for pluginInfo in self.plugins:
if not self.isPluginActive(pluginInfo) or ForceAllPlugins: if not self.isPluginActive(pluginInfo) and pluginInfo.loaded:
logger.info(f"Unloading inactive plugin: {pluginInfo.get_module_name()}")
self.unloadPlugin(pluginInfo) self.unloadPlugin(pluginInfo)
# Then load active plugins
for pluginInfo in self.plugins:
if self.isPluginActive(pluginInfo) and not pluginInfo.loaded:
logger.info(f"Loading active plugin: {pluginInfo.get_module_name()}")
result = self.loadPlugin(pluginInfo)
logger.info(f"Plugin {pluginInfo.get_module_name()} load result: {result}")
# Log final plugin status
active_plugins = [p.get_module_name() for p in self.plugins if p.loaded]
logger.info(f"Active plugins after sync: {active_plugins}")
inactive_plugins = [p.get_module_name() for p in self.plugins if not p.loaded]
logger.info(f"Inactive plugins after sync: {inactive_plugins}")
def loadPlugin(self, pluginInfo):
"""Load a plugin."""
# Skip if pluggy is not available
if not PLUGGY_AVAILABLE:
logger.info(f"Skipping plugin {pluginInfo.get_name()}: pluggy not available")
return False
module_name = pluginInfo.get_module_name()
logger.info(f"Attempting to load plugin: {module_name}")
try:
# Already loaded?
if pluginInfo.loaded:
logger.info(f"Plugin {module_name} already loaded, skipping")
return True
# Try to find the plugin file
module_name = pluginInfo.get_module_name()
plugin_dir = pluginInfo.get_module_dir()
# Check for plugin.py first (standard format)
plugin_file = os.path.join(plugin_dir, "plugin.py")
# Fall back to [PluginName].py if plugin.py doesn't exist
if not os.path.exists(plugin_file):
alternative_plugin_file = os.path.join(plugin_dir, f"{module_name}.py")
if os.path.exists(alternative_plugin_file):
plugin_file = alternative_plugin_file
logger.info(f"Using alternative plugin file: {alternative_plugin_file}")
if not os.path.exists(plugin_file):
logger.error(f"Plugin file not found: {plugin_file}")
return False
logger.info(f"Loading plugin from: {plugin_file}")
spec = importlib.util.spec_from_file_location(module_name, plugin_file)
if spec is None:
logger.error(f"Failed to create spec for plugin: {module_name}")
return False
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
pluginInfo.module = module
# Find Plugin class
plugin_class = None
for attr_name in dir(module):
attr = getattr(module, attr_name)
if (inspect.isclass(attr) and
attr.__module__ == module.__name__ and
hasattr(attr, 'activate')):
plugin_class = attr
logger.info(f"Found plugin class: {attr.__name__} in {module_name}")
break
if not plugin_class:
logger.error(f"No plugin class found in {module_name}")
return False
# Create and initialize plugin instance
logger.info(f"Creating instance of plugin class: {plugin_class.__name__}")
plugin_instance = plugin_class()
pluginInfo.instance = plugin_instance
# Ensure plugins have a reference to the app
plugin_instance.app = self.getApp()
logger.info(f"Set app reference for plugin: {module_name}")
if hasattr(plugin_instance, 'set_app'):
plugin_instance.set_app(self.getApp())
logger.info(f"Called set_app() for plugin: {module_name}")
if hasattr(plugin_instance, 'set_plugin_info'):
plugin_instance.set_plugin_info(pluginInfo)
logger.info(f"Called set_plugin_info() for plugin: {module_name}")
# Register with pluggy and activate
if self.plugin_manager is None:
logger.error(f"Plugin manager is None when loading {module_name}")
return False
logger.info(f"Registering plugin with pluggy: {module_name}")
self.plugin_manager.register(plugin_instance)
try:
logger.info(f"Activating plugin: {module_name}")
self.plugin_manager.hook.activate(plugin=plugin_instance)
except Exception as e:
logger.error(f"Error activating plugin {module_name}: {e}")
import traceback
logger.error(traceback.format_exc())
return False
pluginInfo.loaded = True
logger.info(f"Successfully loaded plugin: {module_name}")
return True
except Exception as e:
logger.error(f"Failed to load plugin {module_name}: {e}")
import traceback
logger.error(traceback.format_exc())
return False
def unloadPlugin(self, pluginInfo): def unloadPlugin(self, pluginInfo):
resourceManager = self.getApp().getResourceManager() """Unload a plugin."""
moduleName = pluginInfo.get_module_name() # Skip if pluggy is not available
if not PLUGGY_AVAILABLE:
return False
if pluginInfo.builtin:
return False
module_name = pluginInfo.get_module_name()
try: try:
if pluginInfo not in self.plugins: # Not loaded?
print("Plugin missing: {}".format(moduleName)) if not pluginInfo.loaded:
return False
if self.isPluginBuildIn(pluginInfo):
return False
self.engine.unload_plugin(pluginInfo)
self.getApp().getResourceManager().removeResourceContext(moduleName)
self.engine.garbage_collect()
except Exception as e:
print('unloadPlugin:',e)
return False
return True return True
def installPlugin(self, pluginFilePath, pluginType=PluginType.USER):
if not self.isValidPluginFile(pluginFilePath): # Deactivate plugin
return False plugin_instance = pluginInfo.instance
pluginFolder = pluginType.get_root_dir() if plugin_instance:
if not pluginFolder.endswith('/'):
pluginFolder += '/'
if not os.path.exists(pluginFolder):
os.mkdir(pluginFolder)
else:
if not os.path.isdir(pluginFolder):
return False
try: try:
with tarfile.open(pluginFilePath) as tar: self.plugin_manager.hook.deactivate(plugin=plugin_instance)
tar.extractall(path=pluginFolder)
except Exception as e: except Exception as e:
print(e) logger.error(f"Error deactivating plugin {module_name}: {e}")
pluginModulePath = self.getModuleDirByPluginFile(pluginFilePath) # Unregister from pluggy
if pluginModulePath != '': self.plugin_manager.unregister(plugin_instance)
pluginModulePath = pluginFolder + pluginModulePath
self.setIgnoredPlugins(pluginModulePath[:-1], False) # without ending /
print('install', pluginFilePath)
self.callPackageTriggers(pluginModulePath, 'onPostInstall')
self.rescanPlugins()
# Clean up
pluginInfo.instance = None
pluginInfo.loaded = False
logger.info(f"Unloaded plugin: {module_name}")
return True return True
def getModuleDirByPluginFile(self, pluginFilePath):
if not isinstance(pluginFilePath, str):
return ''
if pluginFilePath == '':
return ''
if not os.path.exists(pluginFilePath):
return ''
try:
with tarfile.open(pluginFilePath) as tar:
tarMembers = tar.getmembers()
for tarMember in tarMembers:
if tarMember.isdir():
return tarMember.name
except Exception as e:
print(e)
return ''
def isValidPluginFile(self, pluginFilePath):
if not isinstance(pluginFilePath, str):
return False
if pluginFilePath == '':
return False
if not os.path.exists(pluginFilePath):
return False
pluginFolder = ''
pluginFileExists = False
packageFileExists = False
try:
with tarfile.open(pluginFilePath) as tar:
tarMembers = tar.getmembers()
for tarMember in tarMembers:
if tarMember.isdir():
if pluginFolder == '':
pluginFolder = tarMember.name
if tarMember.isfile():
if tarMember.name.endswith('.plugin'):
pluginFileExists = True
if tarMember.name.endswith('package.py'):
pluginFileExists = True
if not tarMember.name.startswith(pluginFolder):
return False
except Exception as e:
print(e)
return False
return pluginFileExists
def uninstallPlugin(self, pluginInfo):
if self.isPluginBuildIn(pluginInfo):
return False
# do we want to allow removing system plugins?
if PluginSystemManager.getPluginType(pluginInfo) == PluginType.SYSTEM:
return False
pluginFolder = pluginInfo.get_data_dir()
if not pluginFolder.endswith('/'):
pluginFolder += '/'
if not os.path.isdir(pluginFolder):
return False
if self.isPluginActive(pluginInfo):
self.setPluginActive(pluginInfo, False)
SettingsManager = self.app.getSettingsManager()
# TODO SettingsManager.set_settings_value_list('active-plugins', self.getActivePlugins())
self.callPackageTriggers(pluginFolder, 'onPreUninstall')
try:
shutil.rmtree(pluginFolder, ignore_errors=True)
except Exception as e: except Exception as e:
print(e) logger.error(f"Failed to unload plugin {module_name}: {e}")
return False return False
self.setIgnoredPlugins(pluginFolder, True)
self.rescanPlugins()
return True def unloadAllPlugins(self, ForceAllPlugins=False):
def callPackageTriggers(self, pluginPath, trigger): """Unload all plugins."""
if not os.path.exists(pluginPath): if not PLUGGY_AVAILABLE:
return return
if not pluginPath.endswith('/'):
pluginPath += '/'
packageModulePath = pluginPath + 'package.py'
if not os.path.isfile(packageModulePath):
return
if not os.access(packageModulePath, os.R_OK):
return
package = self.getApp().getAPIHelper().importModule('package', packageModulePath)
if trigger == 'onPostInstall': for pluginInfo in self.plugins:
try: if ForceAllPlugins or pluginInfo.loaded:
package.onPostInstall(pluginPath, self.getApp()) self.unloadPlugin(pluginInfo)
except Exception as e:
print(e)
elif trigger == 'onPreUninstall':
try:
package.onPreUninstall(pluginPath, self.getApp())
except Exception as e:
print(e)
def _setupExtensionSet(self):
plugin_iface = API(self.getApp())
self.extension_set = Peas.ExtensionSet.new(self.engine,
Peas.Activatable,
["object"],
[plugin_iface])
self.extension_set.connect("extension-removed",
self.__extensionRemoved)
self.extension_set.connect("extension-added",
self.__extensionAdded)
def _setupPluginsDir(self):
system_plugins_dir = PluginType.SYSTEM.get_root_dir()
user_plugins_dir = PluginType.USER.get_root_dir()
if os.path.exists(user_plugins_dir):
self.engine.add_search_path(user_plugins_dir)
if os.path.exists(system_plugins_dir):
self.engine.add_search_path(system_plugins_dir)
def __extensionRemoved(self, unusedSet, pluginInfo, extension):
extension.deactivate()
def __extensionAdded(self, unusedSet, pluginInfo, extension):
extension.setApp(self.getApp())
extension.setPluginInfo(pluginInfo)
extension.activate()
def __loadedPlugins(self, engine, unusedSet):
"""Handles the changing of the loaded plugin list."""
self.getApp().settings.ActivePlugins = engine.get_property("loaded-plugins")
class APIHelper():
def __init__(self, app):
self.app = app
self.cthulhuKeyBindings = None
'''
_pluginAPIManager.seCthulhuAPI('Logger', _logger)
_pluginAPIManager.setCthulhuAPI('SettingsManager', _settingsManager)
_pluginAPIManager.setCthulhuAPI('ScriptManager', _scriptManager)
_pluginAPIManager.setCthulhuAPI('EventManager', _eventManager)
_pluginAPIManager.setCthulhuAPI('Speech', speech)
_pluginAPIManager.setCthulhuAPI('Sound', sound)
_pluginAPIManager.setCthulhuAPI('Braille', braille)
_pluginAPIManager.setCthulhuAPI('Debug', debug)
_pluginAPIManager.setCthulhuAPI('Messages', messages)
_pluginAPIManager.setCthulhuAPI('MouseReview', mouse_review)
_pluginAPIManager.setCthulhuAPI('NotificationMessages', notification_messages)
_pluginAPIManager.setCthulhuAPI('CthulhuState', cthulhu_state)
_pluginAPIManager.setCthulhuAPI('CthulhuPlatform', cthulhu_platform)
_pluginAPIManager.setCthulhuAPI('Settings', settings)
_pluginAPIManager.setCthulhuAPI('Keybindings', keybindings)
'''
def outputMessage(self, Message, interrupt=False):
settings = self.app.getDynamicApiManager().getAPI('Settings')
braille = self.app.getDynamicApiManager().getAPI('Braille')
speech = self.app.getDynamicApiManager().getAPI('Speech')
if speech != None:
if (settings.enableSpeech):
if interrupt:
speech.cancel()
if Message != '':
speech.speak(Message)
if braille != None:
if (settings.enableBraille):
braille.displayMessage(Message)
def createInputEventHandler(self, function, name, learnModeEnabled=True):
EventManager = self.app.getDynamicApiManager().getAPI('EventManager')
newInputEventHandler = EventManager.input_event.InputEventHandler(function, name, learnModeEnabled)
return newInputEventHandler
def registerGestureByString(self, function, name, gestureString, profile, application, learnModeEnabled = True, contextName = None):
gestureList = gestureString.split(',')
registeredGestures = []
for gesture in gestureList:
if gesture.startswith('kb:'):
shortcutString = gesture[3:]
registuredGesture = self.registerShortcutByString(function, name, shortcutString, profile, application, learnModeEnabled, contextName=contextName)
if registuredGesture:
registeredGestures.append(registuredGesture)
return registeredGestures
def registerShortcutByString(self, function, name, shortcutString, profile, application, learnModeEnabled = True, contextName = None):
keybindings = self.app.getDynamicApiManager().getAPI('Keybindings')
settings = self.app.getDynamicApiManager().getAPI('Settings')
resourceManager = self.app.getResourceManager()
clickCount = 0
cthulhuKey = False
shiftKey = False
ctrlKey = False
altKey = False
key = ''
shortcutList = shortcutString.split('+')
for shortcutElement in shortcutList:
shortcutElementLower = shortcutElement.lower()
if shortcutElementLower == 'press':
clickCount += 1
elif shortcutElement == 'cthulhu':
cthulhuKey = True
elif shortcutElementLower == 'shift':
shiftKey = True
elif shortcutElementLower == 'control':
ctrlKey = True
elif shortcutElementLower == 'alt':
altKey = True
else:
key = shortcutElementLower
if clickCount == 0:
clickCount = 1
if self.cthulhuKeyBindings == None:
self.cthulhuKeyBindings = keybindings.KeyBindings()
tryFunction = resource_manager.TryFunction(function)
newInputEventHandler = self.createInputEventHandler(tryFunction.runInputEvent, name, learnModeEnabled)
currModifierMask = keybindings.NO_MODIFIER_MASK
if cthulhuKey:
currModifierMask = currModifierMask | 1 << keybindings.MODIFIER_CTHULHU
if shiftKey:
currModifierMask = currModifierMask | 1 << Atspi.ModifierType.SHIFT
if altKey:
currModifierMask = currModifierMask | 1 << Atspi.ModifierType.ALT
if ctrlKey:
currModifierMask = currModifierMask | 1 << Atspi.ModifierType.CONTROL
newKeyBinding = keybindings.KeyBinding(key, keybindings.defaultModifierMask, currModifierMask, newInputEventHandler, clickCount)
self.cthulhuKeyBindings.add(newKeyBinding)
settings.keyBindingsMap["default"] = self.cthulhuKeyBindings
if contextName:
resourceContext = resourceManager.getResourceContext(contextName)
if resourceContext:
resourceEntry = resource_manager.ResourceEntry('keyboard', newKeyBinding, function, tryFunction, shortcutString)
resourceContext.addGesture(profile, application, newKeyBinding, resourceEntry)
return newKeyBinding
def unregisterShortcut(self, KeyBindingToRemove, contextName = None):
ok = False
keybindings = self.app.getDynamicApiManager().getAPI('Keybindings')
settings = self.app.getDynamicApiManager().getAPI('Settings')
resourceManager = self.app.getResourceManager()
if self.cthulhuKeyBindings == None:
self.cthulhuKeyBindings = keybindings.KeyBindings()
try:
self.cthulhuKeyBindings.remove(KeyBindingToRemove)
settings.keyBindingsMap["default"] = self.cthulhuKeyBindings
ok = True
except KeyError:
pass
if contextName:
resourceContext = resourceManager.getResourceContext(contextName)
if resourceContext:
resourceContext.removeGesture(KeyBindingToRemove)
return ok
def importModule(self, moduleName, moduleLocation):
if version in ["3.3","3.4"]:
return SourceFileLoader(moduleName, moduleLocation).load_module()
else:
spec = importlib.util.spec_from_file_location(moduleName, moduleLocation)
driver_mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(driver_mod)
return driver_mod

View File

@ -1,6 +0,0 @@
[Plugin]
Module=ByeCthulhu
Loader=python3
Name=Stop announcement for cthulhu
Description=Test plugin for cthulhu
Authors=Chrys chrys@linux-a11y.org

View File

@ -1,27 +0,0 @@
from cthulhu import plugin
import gi
gi.require_version('Peas', '1.0')
from gi.repository import GObject
from gi.repository import Peas
import time
class ByeCthulhu(GObject.Object, Peas.Activatable, plugin.Plugin):
#__gtype_name__ = 'ByeCthulhu'
object = GObject.Property(type=GObject.Object)
def __init__(self):
plugin.Plugin.__init__(self)
def do_activate(self):
API = self.object
self.connectSignal("stop-application-completed", self.process)
def do_deactivate(self):
API = self.object
def do_update_state(self):
API = self.object
def process(self, app):
messages = app.getDynamicApiManager().getAPI('Messages')
activeScript = app.getDynamicApiManager().getAPI('CthulhuState').activeScript
activeScript.presentationInterrupt()
activeScript.presentMessage(messages.STOP_CTHULHU, resetStyles=False)

View File

@ -1,7 +1,7 @@
cthulhu_python_PYTHON = \ cthulhu_python_PYTHON = \
__init__.py \ __init__.py \
ByeCthulhu.plugin \ plugin.info \
ByeCthulhu.py plugin.py
cthulhu_pythondir=$(pkgpythondir)/plugins/ByeCthulhu cthulhu_pythondir=$(pkgpythondir)/plugins/ByeCthulhu

View File

@ -0,0 +1,25 @@
#!/usr/bin/env python3
#
# Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca

View File

@ -0,0 +1,8 @@
name = Bye Cthulhu
version = 1.0.0
description = Says goodbye when Cthulhu is shutting down
authors = Stormux <storm_dragon@stormux.org>
website = https://stormux.org
copyright = Copyright 2025
builtin = false
hidden = false

View File

@ -0,0 +1,75 @@
#!/usr/bin/env python3
#
# Copyright (c) 2025 Stormux
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
"""Bye Cthulhu plugin for Cthulhu."""
import logging
import time
from cthulhu.plugin import Plugin, cthulhu_hookimpl
logger = logging.getLogger(__name__)
class ByeCthulhu(Plugin):
"""Plugin that speaks a goodbye message when Cthulhu is shutting down."""
def __init__(self, *args, **kwargs):
"""Initialize the plugin."""
super().__init__(*args, **kwargs)
logger.info("ByeCthulhu plugin initialized")
self._signal_handler_id = None
@cthulhu_hookimpl
def activate(self, plugin=None):
"""Activate the plugin."""
# Skip if this activation call isn't for us
if plugin is not None and plugin is not self:
return
logger.info("Activating ByeCthulhu plugin")
try:
# Connect to the stop-application-completed signal
signal_manager = self.app.getSignalManager()
self._signal_handler_id = signal_manager.connectSignal(
"stop-application-completed",
self.process,
"default" # Add profile parameter
)
except Exception as e:
logger.error(f"Error activating ByeCthulhu plugin: {e}")
@cthulhu_hookimpl
def deactivate(self, plugin=None):
"""Deactivate the plugin."""
# Skip if this deactivation call isn't for us
if plugin is not None and plugin is not self:
return
logger.info("Deactivating ByeCthulhu plugin")
try:
# Disconnect signal if we have an ID
if self._signal_handler_id is not None:
signal_manager = self.app.getSignalManager()
# Use disconnectSignalByFunction instead since disconnectSignal doesn't exist
signal_manager.disconnectSignalByFunction(
self.process
)
self._signal_handler_id = None
except Exception as e:
logger.error(f"Error deactivating ByeCthulhu plugin: {e}")
def process(self, app):
"""Process the stop-application-completed signal."""
try:
messages = app.getDynamicApiManager().getAPI('Messages')
state = app.getDynamicApiManager().getAPI('CthulhuState')
if state.activeScript:
state.activeScript.presentationInterrupt()
state.activeScript.presentMessage(messages.STOP_CTHULHU, resetStyles=False)
except Exception as e:
logger.error(f"Error in ByeCthulhu process: {e}")

View File

@ -1,6 +0,0 @@
[Plugin]
Module=CapsLockHack
Loader=python3
Name=Caps Lock Hack
Description=Fix Capslock sometimes switch on / off when its used as modifier
Authors=Chrys chrys@linux-a11y.org

View File

@ -1,119 +0,0 @@
from cthulhu import plugin
import gi
gi.require_version('Peas', '1.0')
from gi.repository import GObject
from gi.repository import Peas
from threading import Thread, Lock
import subprocess, time, re, os
class CapsLockHack(GObject.Object, Peas.Activatable, plugin.Plugin):
__gtype_name__ = 'CapsLockHack'
object = GObject.Property(type=GObject.Object)
def __init__(self):
plugin.Plugin.__init__(self)
self.lock = Lock()
self.active = False
self.workerThread = Thread(target=self.worker)
def do_activate(self):
API = self.object
"""Enable or disable use of the caps lock key as an Cthulhu modifier key."""
self.interpretCapsLineProg = re.compile(
r'^\s*interpret\s+Caps[_+]Lock[_+]AnyOfOrNone\s*\(all\)\s*{\s*$', re.I)
self.normalCapsLineProg = re.compile(
r'^\s*action\s*=\s*LockMods\s*\(\s*modifiers\s*=\s*Lock\s*\)\s*;\s*$', re.I)
self.interpretShiftLineProg = re.compile(
r'^\s*interpret\s+Shift[_+]Lock[_+]AnyOf\s*\(\s*Shift\s*\+\s*Lock\s*\)\s*{\s*$', re.I)
self.normalShiftLineProg = re.compile(
r'^\s*action\s*=\s*LockMods\s*\(\s*modifiers\s*=\s*Shift\s*\)\s*;\s*$', re.I)
self.disabledModLineProg = re.compile(
r'^\s*action\s*=\s*NoAction\s*\(\s*\)\s*;\s*$', re.I)
self.normalCapsLine = ' action= LockMods(modifiers=Lock);'
self.normalShiftLine = ' action= LockMods(modifiers=Shift);'
self.disabledModLine = ' action= NoAction();'
self.activateWorker()
def do_deactivate(self):
API = self.object
self.deactivateWorker()
def do_update_state(self):
API = self.object
def deactivateWorker(self):
with self.lock:
self.active = False
self.workerThread.join()
def activateWorker(self):
with self.lock:
self.active = True
self.workerThread.start()
def isActive(self):
with self.lock:
return self.active
def worker(self):
"""Makes an Cthulhu-specific Xmodmap so that the keys behave as we
need them to do. This is especially the case for the Cthulhu modifier.
"""
API = self.object
capsLockCleared = False
settings = API.app.getDynamicApiManager().getAPI('Settings')
time.sleep(3)
while self.isActive():
if "Caps_Lock" in settings.cthulhuModifierKeys \
or "Shift_Lock" in settings.cthulhuModifierKeys:
self.setCapsLockAsCthulhuModifier(True)
capsLockCleared = True
elif capsLockCleared:
self.setCapsLockAsCthulhuModifier(False)
capsLockCleared = False
time.sleep(1)
def setCapsLockAsCthulhuModifier(self, enable):
originalXmodmap = None
lines = None
try:
originalXmodmap = subprocess.check_output(['xkbcomp', os.environ['DISPLAY'], '-'])
lines = originalXmodmap.decode('UTF-8').split('\n')
except:
return
foundCapsInterpretSection = False
foundShiftInterpretSection = False
modified = False
for i, line in enumerate(lines):
if not foundCapsInterpretSection and not foundShiftInterpretSection:
if self.interpretCapsLineProg.match(line):
foundCapsInterpretSection = True
elif self.interpretShiftLineProg.match(line):
foundShiftInterpretSection = True
elif foundCapsInterpretSection:
if enable:
if self.normalCapsLineProg.match(line):
lines[i] = self.disabledModLine
modified = True
else:
if self.disabledModLineProg.match(line):
lines[i] = self.normalCapsLine
modified = True
if line.find('}'):
foundCapsInterpretSection = False
else: # foundShiftInterpretSection
if enable:
if self.normalShiftLineProg.match(line):
lines[i] = self.disabledModLine
modified = True
else:
if self.disabledModLineProg.match(line):
lines[i] = self.normalShiftLine
modified = True
if line.find('}'):
foundShiftInterpretSection = False
if modified:
newXmodMap = bytes('\n'.join(lines), 'UTF-8')
self.setXmodmap(newXmodMap)
def setXmodmap(self, xkbmap):
"""Set the keyboard map using xkbcomp."""
try:
p = subprocess.Popen(['xkbcomp', '-w0', '-', os.environ['DISPLAY']],
stdin=subprocess.PIPE, stdout=None, stderr=None)
p.communicate(xkbmap)
except:
pass

View File

@ -1,7 +0,0 @@
cthulhu_python_PYTHON = \
__init__.py \
CapsLockHack.plugin \
CapsLockHack.py
cthulhu_pythondir=$(pkgpythondir)/plugins/CapsLockHack

View File

@ -1,14 +0,0 @@
[Plugin]
Module=ClassicPreferences
Loader=python3
Name=Classic Preferences UI
Description=The classic preferences dialog
Authors=Chrys chrys@linux-a11y.org
Website=
Version=1.0
Copyright=
Builtin=true
Hidden=true
Depends=
Icon=
Help=

View File

@ -1,84 +0,0 @@
from cthulhu import plugin
import gi, time
gi.require_version('Peas', '1.0')
from gi.repository import GObject
from gi.repository import Peas
import importlib, os
import cthulhu_gui_prefs
class ClassicPreferences(GObject.Object, Peas.Activatable, plugin.Plugin):
#__gtype_name__ = 'ClassicPreferences'
object = GObject.Property(type=GObject.Object)
def __init__(self):
plugin.Plugin.__init__(self)
def do_activate(self):
API = self.object
self.connectSignal("setup-inputeventhandlers-completed", self.setupCompatBinding)
#self.setupCompatBinding(API.app)
def setupCompatBinding(self, app):
cmdnames = app.getDynamicApiManager().getAPI('Cmdnames')
inputEventHandlers = app.getDynamicApiManager().getAPI('inputEventHandlers')
inputEventHandlers['preferencesSettingsHandler'] = app.getAPIHelper().createInputEventHandler(self.showPreferencesGUI, cmdnames.SHOW_PREFERENCES_GUI)
inputEventHandlers['appPreferencesSettingsHandler'] = app.getAPIHelper().createInputEventHandler(self.showAppPreferencesGUI, cmdnames.SHOW_APP_PREFERENCES_GUI)
def do_deactivate(self):
API = self.object
inputEventHandlers = API.app.getDynamicApiManager().getAPI('inputEventHandlers')
del inputEventHandlers['preferencesSettingsHandler']
del inputEventHandlers['appPreferencesSettingsHandler']
def do_update_state(self):
API = self.object
def showAppPreferencesGUI(self, script=None, inputEvent=None):
"""Displays the user interface to configure the settings for a
specific applications within Cthulhu and set up those app-specific
user preferences using a GUI.
Returns True to indicate the input event has been consumed.
"""
API = self.object
cthulhu_state = API.app.getDynamicApiManager().getAPI('CthulhuState')
settings = API.app.getDynamicApiManager().getAPI('Settings')
_settingsManager = API.app.getDynamicApiManager().getAPI('SettingsManager').getManager()
_scriptManager = API.app.getDynamicApiManager().getAPI('ScriptManager').getManager()
prefs = {}
for key in settings.userCustomizableSettings:
prefs[key] = _settingsManager.getSetting(key)
script = script or cthulhu_state.activeScript
self._showPreferencesUI(script, prefs)
return True
def showPreferencesGUI(self, script=None, inputEvent=None):
"""Displays the user interface to configure Cthulhu and set up
user preferences using a GUI.
Returns True to indicate the input event has been consumed.
"""
API = self.object
cthulhu_state = API.app.getDynamicApiManager().getAPI('CthulhuState')
settings = API.app.getDynamicApiManager().getAPI('Settings')
_settingsManager = API.app.getDynamicApiManager().getAPI('SettingsManager').getManager()
_scriptManager = API.app.getDynamicApiManager().getAPI('ScriptManager').getManager()
debug = API.app.getDynamicApiManager().getAPI('Debug')
prefs = _settingsManager.getGeneralSettings(_settingsManager.profile)
script = _scriptManager.getDefaultScript()
self._showPreferencesUI(script, prefs)
return True
def _showPreferencesUI(self, script, prefs):
API = self.object
cthulhu_state = API.app.getDynamicApiManager().getAPI('CthulhuState')
debug = API.app.getDynamicApiManager().getAPI('Debug')
cthulhu_platform = API.app.getDynamicApiManager().getAPI('CthulhuPlatform')
if cthulhu_state.cthulhuOS:
cthulhu_state.cthulhuOS.showGUI()
return
uiFile = os.path.join(self.getModuleDir(),
"cthulhu-setup.ui")
cthulhu_state.cthulhuOS = cthulhu_gui_prefs.CthulhuSetupGUI(uiFile, "cthulhuSetupWindow", prefs, API.app)
cthulhu_state.cthulhuOS.init(script)
cthulhu_state.cthulhuOS.setTranslationContext(self.getTranslationContext())
cthulhu_state.cthulhuOS.showGUI()

View File

@ -1,10 +0,0 @@
cthulhu_python_PYTHON = \
__init__.py \
ClassicPreferences.plugin \
ClassicPreferences.py \
cthulhu_gui_prefs.py \
cthulhu_gui_profile.py \
cthulhu-setup.ui
cthulhu_pythondir=$(pkgpythondir)/plugins/ClassicPreferences

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,163 +0,0 @@
# Cthulhu
#
# Copyright 2010 Consorcio Fernando de los Rios.
# Author: Javier Hernandez Antunez <jhernandez@emergya.es>
# Author: Alejandro Leiva <aleiva@emergya.es>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA.
"""Displays the Save Profile As dialog."""
__id__ = "$Id$"
__version__ = "$Revision$"
__date__ = "$Date$"
__copyright__ = "Copyright (c) 2010 Consorcio Fernando de los Rios."
__license__ = "LGPL"
import locale
import sys
from gi.repository import Gtk
cthulhu_state = None
guilabels = None
OS = None
newProfile = None
app = None
class CthulhuProfileGUI(Gtk.Dialog):
def __init__(self, app):
"""Initialize the Cthulhu profile configuration GUI."""
self.app = app
global guilabels
global cthulhu_state
guilabels = self.app.getDynamicApiManager().getAPI('GuiLabels')
cthulhu_state = self.app.getDynamicApiManager().getAPI('CthulhuState')
Gtk.Dialog.__init__(self)
self.set_title(guilabels.PROFILE_SAVE_AS_TITLE)
self.set_has_resize_grip(False)
self.add_button('gtk-cancel', Gtk.ResponseType.CANCEL)
self.add_button('gtk-save', Gtk.ResponseType.ACCEPT)
grid = Gtk.Grid()
grid.set_property('margin', 12)
grid.set_row_spacing(10)
grid.set_column_spacing(10)
# Right now the content area is a GtkBox. We'll need to update
# this once GtkBox is fully deprecated.
contentArea = self.get_content_area()
contentArea.pack_start(grid, True, True, 0)
self.profileEntry = Gtk.Entry()
self.profileEntry.set_property('hexpand', True)
self.profileEntry.set_activates_default(True)
grid.attach(self.profileEntry, 1, 0, 1, 1)
label = Gtk.Label(guilabels.PROFILE_NAME_LABEL)
label.set_use_underline(True)
label.set_mnemonic_widget(self.profileEntry)
grid.attach(label, 0, 0, 1, 1)
defaultButton = self.get_widget_for_response(Gtk.ResponseType.ACCEPT)
defaultButton.set_property('can-default', True)
defaultButton.set_property('has-default', True)
self.connect('response', self.onResponse)
self.connect('destroy', self.onDestroy)
self.searchString = None
self.profileString = None
self.prefsDialog = None
self.translationContext = None
def init(self):
self.profileString = ''
def showGUI(self, prefsDialog):
"""Show the Save Profile As dialog."""
self.show_all()
self.prefsDialog = prefsDialog
self.profileEntry.set_text(self.profileString)
ts = 0
try:
ts = cthulhu_state.lastInputEvent.timestamp
except:
pass
if ts == 0:
ts = Gtk.get_current_event_time()
self.present_with_time(ts)
def onResponse(self, widget, response):
"""Signal handler for the responses emitted by the dialog."""
if response in [Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT]:
self.hide()
return
if response == Gtk.ResponseType.ACCEPT:
global newProfile
newProfile = self.profileEntry.get_text()
if newProfile:
self.destroy()
if self.prefsDialog:
self.prefsDialog.saveProfile(newProfile)
def onDestroy(self, widget):
"""Signal handler for the 'destroy' signal of the dialog."""
global OS
OS = None
def setTranslationContext(newTranslationContext):
global _, translationContext
translationContext = newTranslationContext
_ = newTranslationContext.gettext
def setApp(newApp):
global app
app = newApp
def showProfileUI(prefsDialog=None):
global OS
global newProfile
newProfile = None
if not OS:
OS = CthulhuProfileGUI(app)
OS.init()
OS.showGUI(prefsDialog)
def main():
locale.setlocale(locale.LC_ALL, '')
showProfileUI()
Gtk.main()
sys.exit(0)
if __name__ == "__main__":
main()

View File

@ -1,6 +0,0 @@
[Plugin]
Module=Clipboard
Loader=python3
Name=Clipboard
Description=Present the content of the current clipboard
Authors=Chrys chrys@linux-a11y.org

View File

@ -1,76 +0,0 @@
from cthulhu import plugin
import gi, os
gi.require_version('Peas', '1.0')
from gi.repository import GObject
from gi.repository import Peas
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk
class Clipboard(GObject.Object, Peas.Activatable, plugin.Plugin):
#__gtype_name__ = 'Clipboard'
object = GObject.Property(type=GObject.Object)
def __init__(self):
plugin.Plugin.__init__(self)
def do_activate(self):
API = self.object
self.registerGestureByString(self.speakClipboard, _('clipboard'), 'kb:cthulhu+c')
def do_deactivate(self):
API = self.object
def do_update_state(self):
API = self.object
def speakClipboard(self, script=None, inputEvent=None):
API = self.object
Message = self.getClipboard()
API.app.getDynamicApiManager().getAPI('CthulhuState').activeScript.presentMessage(Message, resetStyles=False)
return True
def getClipboard(self):
Message = ""
FoundClipboardContent = False
# Get Clipboard
ClipboardObj = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
ClipboardText = ClipboardObj.wait_for_text()
ClipboardImage = ClipboardObj.wait_for_image()
ClipboardURI = ClipboardObj.wait_for_uris()
if (ClipboardText != None):
FoundClipboardContent = True
if (ClipboardObj.wait_is_uris_available()):
noOfObjects = 0
noOfFolder = 0
noOfFiles = 0
noOfDisks = 0
noOfLinks = 0
for Uri in ClipboardURI:
if Uri == '':
continue
noOfObjects += 1
uriWithoutProtocoll = Uri[Uri.find('://') + 3:]
Message += " " + Uri[Uri.rfind('/') + 1:] + " "
if (os.path.isdir(uriWithoutProtocoll)):
noOfFolder += 1
Message = Message + _("Folder") #Folder
if (os.path.isfile(uriWithoutProtocoll)):
noOfFiles += 1
Message = Message + _("File") #File
if (os.path.ismount(uriWithoutProtocoll)):
noOfDisks += 1
Message = Message + _("Disk") #Mountpoint
if (os.path.islink(uriWithoutProtocoll)):
noOfLinks += 1
Message = Message + _("Link") #Link
if (noOfObjects > 1):
Message = str(noOfObjects) + _(" Objects in clipboard ") + Message # X Objects in Clipboard Object Object
else:
Message = str(noOfObjects) + _(" Object in clipboard ") + Message # 1 Object in Clipboard Object
else:
Message = _("Text in clipboard ") + ClipboardText # Text in Clipboard
if (ClipboardImage != None):
FoundClipboardContent = True
Message = _("The clipboard contains a image") # Image is in Clipboard
if (not FoundClipboardContent):
Message = _("The clipboard is empty")
return Message

View File

@ -1,7 +1,7 @@
cthulhu_python_PYTHON = \ cthulhu_python_PYTHON = \
__init__.py \ __init__.py \
Clipboard.plugin \ plugin.info \
Clipboard.py plugin.py
cthulhu_pythondir=$(pkgpythondir)/plugins/Clipboard cthulhu_pythondir=$(pkgpythondir)/plugins/Clipboard

View File

@ -0,0 +1,25 @@
#!/usr/bin/env python3
#
# Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca

View File

@ -0,0 +1,7 @@
[Plugin]
Name = Clipboard
Module = Clipboard
Description = Present the content of the current clipboard
Authors = Storm Dragon <storm_dragon@stormux.org>
Version = 1.0
Category = Utilities

View File

@ -0,0 +1,193 @@
#!/usr/bin/env python3
#
# Copyright (c) 2024 Stormux
# Copyright (c) 2010-2012 The Orca Team
# Copyright (c) 2012 Igalia, S.L.
# Copyright (c) 2005-2010 Sun Microsystems Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA.
#
# Fork of Orca Screen Reader (GNOME)
# Original source: https://gitlab.gnome.org/GNOME/orca
"""Clipboard plugin for Cthulhu."""
import os
import logging
import gettext
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk
from cthulhu.plugin import Plugin, cthulhu_hookimpl
# Set up translation function
_ = gettext.gettext
logger = logging.getLogger(__name__)
class Clipboard(Plugin):
"""Plugin to read the clipboard contents."""
def __init__(self, *args, **kwargs):
"""Initialize the plugin."""
super().__init__(*args, **kwargs)
logger.info("Clipboard plugin initialized")
self._signal_handler_id = None
@cthulhu_hookimpl
def activate(self, plugin=None):
"""Activate the plugin."""
# Skip if this activation call isn't for us
if plugin is not None and plugin is not self:
return
logger.info("Activating Clipboard plugin")
try:
# Register keyboard shortcut
self.registerGestureByString(self.speakClipboard, _('clipboard'), 'kb:cthulhu+shift+c')
logger.debug("Registered shortcut for clipboard")
except Exception as e:
logger.error(f"Error activating Clipboard plugin: {e}")
@cthulhu_hookimpl
def deactivate(self, plugin=None):
"""Deactivate the plugin."""
# Skip if this deactivation call isn't for us
if plugin is not None and plugin is not self:
return
logger.info("Deactivating Clipboard plugin")
try:
# Unregister keyboard shortcut
if self.app:
api_helper = self.app.getAPIHelper()
if api_helper and hasattr(api_helper, 'unregisterShortcut'):
api_helper.unregisterShortcut('kb:cthulhu+shift+c')
logger.debug("Unregistered clipboard shortcut")
except Exception as e:
logger.error(f"Error deactivating Clipboard plugin: {e}")
"""Activate the plugin."""
# Skip if this activation call isn't for us
if plugin is not None and plugin is not self:
return
logger.info("Activating Clipboard plugin")
try:
# Register keyboard shortcut
self.registerGestureByString(self.speakClipboard, _('clipboard'), 'kb:cthulhu+shift+c')
logger.debug("Registered shortcut for clipboard")
except Exception as e:
logger.error(f"Error activating Clipboard plugin: {e}")
@cthulhu_hookimpl
def deactivate(self, plugin=None):
"""Deactivate the plugin."""
# Skip if this deactivation call isn't for us
if plugin is not None and plugin is not self:
return
logger.info("Deactivating Clipboard plugin")
try:
# Unregister keyboard shortcut
self.unregisterGestureByString('kb:cthulhu+shift+c')
logger.debug("Unregistered clipboard shortcut")
except Exception as e:
logger.error(f"Error deactivating Clipboard plugin: {e}")
def speakClipboard(self, script=None, inputEvent=None):
"""Present the contents of the clipboard."""
try:
message = self.getClipboard()
state = self.app.getDynamicApiManager().getAPI('CthulhuState')
if state and state.activeScript:
state.activeScript.presentMessage(message, resetStyles=False)
logger.debug("Presented clipboard contents")
else:
logger.warning("Could not present clipboard: no active script")
return True
except Exception as e:
logger.error(f"Error in speakClipboard: {e}")
return False
def getClipboard(self):
"""Get the contents of the clipboard."""
try:
message = ""
found_clipboard_content = False
# Get Clipboard
clipboard_obj = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
clipboard_text = clipboard_obj.wait_for_text()
clipboard_image = clipboard_obj.wait_for_image()
clipboard_uri = clipboard_obj.wait_for_uris()
if clipboard_text is not None:
found_clipboard_content = True
if clipboard_obj.wait_is_uris_available():
no_of_objects = 0
no_of_folder = 0
no_of_files = 0
no_of_disks = 0
no_of_links = 0
for uri in clipboard_uri:
if uri == '':
continue
no_of_objects += 1
uri_without_protocol = uri[uri.find('://') + 3:]
message += " " + uri[uri.rfind('/') + 1:] + " "
if os.path.isdir(uri_without_protocol):
no_of_folder += 1
message = message + _("Folder")
if os.path.isfile(uri_without_protocol):
no_of_files += 1
message = message + _("File")
if os.path.ismount(uri_without_protocol):
no_of_disks += 1
message = message + _("Disk")
if os.path.islink(uri_without_protocol):
no_of_links += 1
message = message + _("Link")
if no_of_objects > 1:
message = str(no_of_objects) + _(" Objects in clipboard ") + message
else:
message = str(no_of_objects) + _(" Object in clipboard ") + message
else:
message = _("Text in clipboard ") + clipboard_text
if clipboard_image is not None:
found_clipboard_content = True
message = _("The clipboard contains a image")
if not found_clipboard_content:
message = _("The clipboard is empty")
return message
except Exception as e:
logger.error(f"Error getting clipboard content: {e}")
return _("Error accessing clipboard")

Some files were not shown because too many files have changed in this diff Show More