| Server IP : 85.112.90.236 / Your IP : 192.168.1.26 Web Server : Apache System : Linux 85-112-90-236.cprapid.com 6.12.0-211.7.3.el10_2.x86_64 #1 SMP PREEMPT_DYNAMIC Tue May 19 12:46:58 EDT 2026 x86_64 User : ftechme ( 1002) PHP Version : 8.2.32 Disable Function : exec,passthru,shell_exec,system MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /proc/thread-self/root/lib/python3.12/site-packages/orca/ |
Upload File : |
# Orca
#
# Copyright 2011-2024 Igalia, S.L.
# Author: Joanmarie Diggs <jdiggs@igalia.com>
#
# 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.
# pylint: disable=broad-exception-caught
# pylint: disable=wrong-import-position
"""Manages Orca's scripts."""
__id__ = "$Id$"
__version__ = "$Revision$"
__date__ = "$Date$"
__copyright__ = "Copyright (c) 2011-2024 Igalia, S.L."
__license__ = "LGPL"
import importlib
from typing import Optional
import gi
gi.require_version("Atspi", "2.0")
from gi.repository import Atspi
# TODO - JD: The script manager should not be interacting with speech or braille directly.
# When the presentation manager is created, it should handle speech and braille.
from . import braille
from . import debug
from . import settings_manager
from . import speech_and_verbosity_manager
from .ax_object import AXObject
from .ax_utilities import AXUtilities
from .scripts import apps, default, sleepmode, toolkits
class ScriptManager:
"""Manages Orca's scripts."""
def __init__(self) -> None:
debug.print_message(debug.LEVEL_INFO, "SCRIPT MANAGER: Initializing", True)
self.app_scripts: dict = {}
self.toolkit_scripts: dict = {}
self.custom_scripts: dict = {}
self._sleep_mode_scripts: dict = {}
self._default_script: Optional[default.Script] = None
self._active_script: Optional[default.Script] = None
self._active: bool = False
debug.print_message(debug.LEVEL_INFO, "SCRIPT MANAGER: Initialized", True)
def activate(self) -> None:
"""Called when this script manager is activated."""
debug.print_message(debug.LEVEL_INFO, "SCRIPT MANAGER: Activating", True, True)
if self._active:
debug.print_message(debug.LEVEL_INFO, "SCRIPT MANAGER: Already activated", True)
return
self._default_script = self.get_default_script(None)
self._default_script.register_event_listeners()
self.set_active_script(self._default_script, "activate")
self._active = True
debug.print_message(debug.LEVEL_INFO, "SCRIPT MANAGER: Activated", True)
def deactivate(self) -> None:
"""Called when this script manager is deactivated."""
debug.print_message(debug.LEVEL_INFO, "SCRIPT MANAGER: Deactivating", True, True)
if not self._active:
debug.print_message(debug.LEVEL_INFO, "SCRIPT MANAGER: Already deactivated", True)
return
if self._default_script is not None:
self._default_script.deregister_event_listeners()
self._default_script = None
self.set_active_script(None, "deactivate")
self.app_scripts = {}
self.toolkit_scripts = {}
self.custom_scripts = {}
self._active = False
debug.print_message(debug.LEVEL_INFO, "SCRIPT MANAGER: Deactivated", True)
def get_module_name(self, app: Optional[Atspi.Accessible]) -> Optional[str]:
"""Returns the module name of the script to use for application app."""
if app is None:
msg = "SCRIPT MANAGER: Cannot get module name for null app"
debug.print_message(debug.LEVEL_INFO, msg, True)
return None
name = AXObject.get_name(app)
if not name:
msg = "SCRIPT MANAGER: Cannot get module name for nameless app"
debug.print_message(debug.LEVEL_INFO, msg, True)
return None
app_names = {"gtk-window-decorator": "switcher",
"marco": "switcher",
"mate-notification-daemon": "notification-daemon",
"metacity": "switcher",
"pluma": "gedit",
"xfce4-notifyd": "notification-daemon"}
alt_names = list(app_names.keys())
if name.endswith(".py") or name.endswith(".bin"):
name = name.split(".")[0]
elif name.startswith("org.") or name.startswith("com."):
name = name.split(".")[-1]
names = [n for n in alt_names if n.lower() == name.lower()]
if names:
name = app_names.get(names[0], "")
else:
for name_list in (apps.__all__, toolkits.__all__):
names = [n for n in name_list if n.lower() == name.lower()]
if names:
name = names[0]
break
tokens = ["SCRIPT MANAGER: Mapped", app, "to", name]
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
return name
def _toolkit_for_object(self, obj: Atspi.Accessible) -> Optional[str]:
"""Returns the name of the toolkit associated with obj."""
names = {"GTK": "gtk", "GAIL": "gtk"}
name = AXObject.get_attribute(obj, "toolkit")
return names.get(name, name)
def _script_for_role(self, obj: Atspi.Accessible) -> str:
"""Returns the role-based script for obj."""
if AXUtilities.is_terminal(obj):
return "terminal"
return ""
def _new_named_script(self, app: Atspi.Accessible, name: str) -> Optional[default.Script]:
"""Returns a script based on this module if it was located and loadable."""
if not (app and name):
return None
packages = ["orca-scripts", "orca.scripts", "orca.scripts.apps", "orca.scripts.toolkits"]
script = None
for package in packages:
module_name = ".".join((package, name))
try:
module = importlib.import_module(module_name)
except ImportError:
continue
except OSError as error:
tokens = ["EXCEPTION: Could not import", module_name, ":", error]
debug.print_tokens(debug.LEVEL_INFO, tokens, True, True)
tokens = ["SCRIPT MANAGER: Found", module_name]
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
try:
if hasattr(module, "getScript"):
script = module.get_script(app)
else:
script = module.Script(app)
break
except Exception as error:
tokens = ["EXCEPTION: Could not load", module_name, ":", error]
debug.print_tokens(debug.LEVEL_INFO, tokens, True, True)
return script
def _create_script(
self, app: Atspi.Accessible, obj: Optional[Atspi.Accessible] = None
) -> default.Script:
"""For the given application, create a new script instance."""
module_name = self.get_module_name(app) or ""
script = self._new_named_script(app, module_name)
if script:
return script
obj_toolkit = self._toolkit_for_object(obj) or ""
script = self._new_named_script(app, obj_toolkit)
if script:
return script
toolkit_name = AXUtilities.get_application_toolkit_name(app)
if app and toolkit_name:
script = self._new_named_script(app, toolkit_name)
if not script:
script = self.get_default_script(app)
tokens = ["SCRIPT MANAGER: Default script created for", app, "(obj: ", obj, ")"]
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
return script
def get_default_script(self, app: Optional[Atspi.Accessible] = None) -> default.Script:
"""Returns the default script."""
if not app and self._default_script:
return self._default_script
script = default.Script(app)
if not app:
self._default_script = script
return script
def get_or_create_sleep_mode_script(self, app: Atspi.Accessible) -> sleepmode.Script:
"""Gets or crates the sleep mode script."""
script = self._sleep_mode_scripts.get(app)
if script is not None:
return script
script = sleepmode.Script(app)
self._sleep_mode_scripts[app] = script
return script
def get_script(
self, app: Optional[Atspi.Accessible], obj: Optional[Atspi.Accessible] = None
) -> default.Script:
"""Get a script for an app (and make it if necessary)."""
tokens = ["SCRIPT MANAGER: Getting script for", app, obj]
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
custom_script: Optional[default.Script] = None
app_script: Optional[default.Script] = None
toolkit_script: Optional[default.Script] = None
role_name = self._script_for_role(obj)
if role_name:
custom_scripts = self.custom_scripts.get(app, {})
custom_script = custom_scripts.get(role_name)
if not custom_script:
custom_script = self._new_named_script(app, role_name)
custom_scripts[role_name] = custom_script
self.custom_scripts[app] = custom_scripts
obj_toolkit = self._toolkit_for_object(obj)
if obj_toolkit:
toolkit_scripts = self.toolkit_scripts.get(app, {})
toolkit_script = toolkit_scripts.get(obj_toolkit)
if not toolkit_script:
toolkit_script = self._create_script(app, obj)
toolkit_scripts[obj_toolkit] = toolkit_script
self.toolkit_scripts[app] = toolkit_scripts
try:
if not app:
app_script = self.get_default_script()
elif app in self.app_scripts:
app_script = self.app_scripts[app]
else:
app_script = self._create_script(app, None)
self.app_scripts[app] = app_script
except Exception as error:
tokens = ["EXCEPTION: Exception getting app script for", app, ":", error]
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
app_script = self.get_default_script()
assert app_script is not None
if app_script.get_sleep_mode_manager().is_active_for_app(app):
tokens = ["SCRIPT MANAGER: Sleep-mode toggled on for", app_script, app]
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
return self.get_or_create_sleep_mode_script(app)
if custom_script:
tokens = ["SCRIPT MANAGER: Script is custom script", custom_script]
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
return custom_script
# Only defer to the toolkit script for this object if the app script
# is based on a different toolkit.
if toolkit_script and not (AXUtilities.is_frame(obj) or AXUtilities.is_status_bar(obj)) \
and not issubclass(app_script.__class__, toolkit_script.__class__):
tokens = ["SCRIPT MANAGER: Script is toolkit script", toolkit_script]
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
return toolkit_script
tokens = ["SCRIPT MANAGER: Script is app script", app_script]
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
return app_script
def get_active_script(self) -> Optional[default.Script]:
"""Returns the active script."""
tokens = ["SCRIPT MANAGER: Active script is:", self._active_script]
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
return self._active_script
def get_active_script_app(self) -> Optional[Atspi.Accessible]:
"""Returns the app associated with the active script."""
if self._active_script is None:
return None
tokens = ["SCRIPT MANAGER: Active script app is:", self._active_script.app]
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
return self._active_script.app
def set_active_script(self, new_script: Optional[default.Script], reason: str = "") -> None:
"""Set the active script to new_script."""
if self._active_script == new_script:
return
if self._active_script is not None:
tokens = ["SCRIPT MANAGER: Deactivating", self._active_script, "reason:", reason]
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
self._active_script.deactivate()
old_script = self._active_script
self._active_script = new_script
if new_script is None:
return
manager = settings_manager.get_manager()
runtime_settings = {}
if old_script and old_script.app == new_script.app:
# Example: old_script is terminal, new_script is mate-terminal (e.g. for UI)
runtime_settings = manager.get_runtime_settings()
tokens = ["SCRIPT MANAGER: Setting active script to", new_script, "reason:", reason]
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
new_script.activate()
for key, value in runtime_settings.items():
manager.set_setting(key, value)
braille.checkBrailleSetting()
braille.setupKeyRanges(new_script.braille_bindings.keys())
speech_and_verbosity_manager.get_manager().check_speech_setting()
def reclaim_scripts(self) -> None:
"""Compares the list of known scripts to the list of known apps,
deleting any scripts as necessary.
"""
msg = "SCRIPT MANAGER: Checking and cleaning up scripts."
debug.print_message(debug.LEVEL_INFO, msg, True)
app_list = list(self.app_scripts.keys())
for app in app_list:
if AXUtilities.is_application_in_desktop(app):
continue
try:
app_script = self.app_scripts.pop(app)
except KeyError:
tokens = ["SCRIPT MANAGER:", app, "not found in app_scripts"]
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
continue
tokens = ["SCRIPT MANAGER: Old script for app found:", app_script, app_script.app]
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
try:
self._sleep_mode_scripts.pop(app)
except KeyError:
pass
try:
self.toolkit_scripts.pop(app)
except KeyError:
pass
try:
self.custom_scripts.pop(app)
except KeyError:
pass
_manager: ScriptManager = ScriptManager()
def get_manager() -> ScriptManager:
"""Returns the Script Manager singleton."""
return _manager