Almost read for new version.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
# Maintainer: Storm Dragon <storm_dragon@stormux.org>
|
# Maintainer: Storm Dragon <storm_dragon@stormux.org>
|
||||||
|
|
||||||
pkgname=cthulhu
|
pkgname=cthulhu
|
||||||
pkgver=2025.12.27-testing
|
pkgver=2025.12.27
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="Desktop-agnostic screen reader with plugin system, forked from Orca"
|
pkgdesc="Desktop-agnostic screen reader with plugin system, forked from Orca"
|
||||||
url="https://git.stormux.org/storm/cthulhu"
|
url="https://git.stormux.org/storm/cthulhu"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
project('cthulhu',
|
project('cthulhu',
|
||||||
version: '2025.12.27-testing',
|
version: '2025.12.28-testing',
|
||||||
meson_version: '>= 1.0.0',
|
meson_version: '>= 1.0.0',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ if [[ -n "$codeNameValue" ]]; then
|
|||||||
sed -i "s/^codeName = \".*\"/codeName = \"${codeNameValue}\"/" "$cthulhuVersionFile"
|
sed -i "s/^codeName = \".*\"/codeName = \"${codeNameValue}\"/" "$cthulhuVersionFile"
|
||||||
fi
|
fi
|
||||||
sed -i "s/^ version: '.*',/ version: '${fullVersion}',/" "$mesonFile"
|
sed -i "s/^ version: '.*',/ version: '${fullVersion}',/" "$mesonFile"
|
||||||
sed -i "s/^pkgver=.*/pkgver=${fullVersion}/" "$pkgbuildFile"
|
sed -i "s/^pkgver=.*/pkgver=${pythonVersion}/" "$pkgbuildFile"
|
||||||
sed -i "s/^pkgrel=.*/pkgrel=1/" "$pkgbuildFile"
|
sed -i "s/^pkgrel=.*/pkgrel=1/" "$pkgbuildFile"
|
||||||
|
|
||||||
if ! rg -q "^version = \"${pythonVersion}\"" "$cthulhuVersionFile"; then
|
if ! rg -q "^version = \"${pythonVersion}\"" "$cthulhuVersionFile"; then
|
||||||
|
|||||||
@@ -63,41 +63,26 @@ class ActionList(Gtk.Window):
|
|||||||
"""Window containing a list of accessible actions."""
|
"""Window containing a list of accessible actions."""
|
||||||
|
|
||||||
def __init__(self, presenter: ActionPresenter):
|
def __init__(self, presenter: ActionPresenter):
|
||||||
super().__init__()
|
super().__init__(window_position=Gtk.WindowPosition.MOUSE, transient_for=None)
|
||||||
self._presenter = presenter
|
self._presenter = presenter
|
||||||
self._actions = []
|
|
||||||
self._setup_gui()
|
self._setup_gui()
|
||||||
|
|
||||||
def _setup_gui(self) -> None:
|
def _setup_gui(self) -> None:
|
||||||
"""Sets up the GUI for the actions list."""
|
"""Sets up the GUI for the actions list."""
|
||||||
|
|
||||||
self.set_title(guilabels.KB_GROUP_ACTIONS)
|
self.set_title(guilabels.KB_GROUP_ACTIONS)
|
||||||
self.set_modal(True)
|
|
||||||
self.set_decorated(False)
|
self.set_decorated(False)
|
||||||
self.set_skip_taskbar_hint(True)
|
|
||||||
self.set_skip_pager_hint(True)
|
|
||||||
self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
|
|
||||||
# Note: set_window_position is deprecated, using move() instead
|
|
||||||
self.move(100, 100) # Position window at reasonable location
|
|
||||||
self.set_default_size(400, 300)
|
|
||||||
|
|
||||||
# Create scrolled window
|
|
||||||
scrolled = Gtk.ScrolledWindow()
|
|
||||||
scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
|
|
||||||
self.add(scrolled)
|
|
||||||
|
|
||||||
# Create list box
|
|
||||||
self._listbox = Gtk.ListBox()
|
self._listbox = Gtk.ListBox()
|
||||||
self._listbox.set_selection_mode(Gtk.SelectionMode.SINGLE)
|
self._listbox.set_selection_mode(Gtk.SelectionMode.SINGLE)
|
||||||
self._listbox.connect("row-activated", self._on_row_activated)
|
self._listbox.connect("row-activated", self._on_row_activated)
|
||||||
scrolled.add(self._listbox)
|
self._listbox.set_margin_top(5)
|
||||||
|
self._listbox.set_margin_bottom(5)
|
||||||
|
self.add(self._listbox)
|
||||||
|
|
||||||
# Connect key events
|
|
||||||
self.connect("key-press-event", self._on_key_press)
|
self.connect("key-press-event", self._on_key_press)
|
||||||
self.connect("destroy", self._on_destroy)
|
self.connect("destroy", self._on_destroy)
|
||||||
|
|
||||||
self.show_all()
|
|
||||||
|
|
||||||
def _on_key_press(self, widget, event) -> bool:
|
def _on_key_press(self, widget, event) -> bool:
|
||||||
"""Handles key press events."""
|
"""Handles key press events."""
|
||||||
|
|
||||||
@@ -108,19 +93,17 @@ class ActionList(Gtk.Window):
|
|||||||
|
|
||||||
def _on_row_activated(self, listbox, row) -> None:
|
def _on_row_activated(self, listbox, row) -> None:
|
||||||
"""Handles row activation (Enter or double-click)."""
|
"""Handles row activation (Enter or double-click)."""
|
||||||
|
|
||||||
if row is not None:
|
action_name = getattr(row, "_action_name", None)
|
||||||
action_index = row.get_index()
|
if action_name:
|
||||||
if 0 <= action_index < len(self._actions):
|
self._presenter._perform_action(action_name)
|
||||||
action_name = self._actions[action_index]
|
|
||||||
self._presenter._perform_action(action_name)
|
|
||||||
|
|
||||||
def _on_destroy(self, widget) -> None:
|
def _on_destroy(self, widget) -> None:
|
||||||
"""Handles window destruction."""
|
"""Handles window destruction."""
|
||||||
|
|
||||||
GLib.idle_add(self._presenter._clear_gui_and_restore_focus)
|
GLib.idle_add(self._presenter._clear_gui_and_restore_focus)
|
||||||
|
|
||||||
def populate_actions(self, actions: list[str]) -> None:
|
def populate_actions(self, actions: dict[str, str] | list[str]) -> None:
|
||||||
"""Populates the list with accessible actions."""
|
"""Populates the list with accessible actions."""
|
||||||
|
|
||||||
if isinstance(actions, dict):
|
if isinstance(actions, dict):
|
||||||
@@ -128,22 +111,19 @@ class ActionList(Gtk.Window):
|
|||||||
else:
|
else:
|
||||||
items = [(action, action) for action in actions]
|
items = [(action, action) for action in actions]
|
||||||
|
|
||||||
self._actions = [name for name, _label in items]
|
|
||||||
|
|
||||||
# Clear existing items
|
# Clear existing items
|
||||||
for child in self._listbox.get_children():
|
for child in self._listbox.get_children():
|
||||||
self._listbox.remove(child)
|
self._listbox.remove(child)
|
||||||
|
|
||||||
# Add actions to list
|
# Add actions to list
|
||||||
for _action, label_text in items:
|
for action_name, label_text in items:
|
||||||
label = Gtk.Label(label=label_text)
|
row = Gtk.ListBoxRow()
|
||||||
label.set_xalign(0.0) # Left align
|
label = Gtk.Label(label=label_text, xalign=0)
|
||||||
label.set_margin_left(10)
|
label.set_margin_start(10)
|
||||||
label.set_margin_right(10)
|
label.set_margin_end(10)
|
||||||
label.set_margin_top(5)
|
row.add(label)
|
||||||
label.set_margin_bottom(5)
|
setattr(row, "_action_name", action_name)
|
||||||
|
self._listbox.add(row)
|
||||||
self._listbox.add(label)
|
|
||||||
|
|
||||||
# Select first item
|
# Select first item
|
||||||
if actions:
|
if actions:
|
||||||
@@ -152,7 +132,12 @@ class ActionList(Gtk.Window):
|
|||||||
self._listbox.select_row(first_row)
|
self._listbox.select_row(first_row)
|
||||||
first_row.grab_focus()
|
first_row.grab_focus()
|
||||||
|
|
||||||
|
def show_gui(self) -> None:
|
||||||
|
"""Shows the window."""
|
||||||
|
|
||||||
self.show_all()
|
self.show_all()
|
||||||
|
self.present_with_time(time.time())
|
||||||
|
self._listbox.grab_focus()
|
||||||
|
|
||||||
|
|
||||||
class ActionPresenter:
|
class ActionPresenter:
|
||||||
@@ -264,7 +249,26 @@ class ActionPresenter:
|
|||||||
"""Clears the GUI reference and then restores focus."""
|
"""Clears the GUI reference and then restores focus."""
|
||||||
|
|
||||||
self._gui = None
|
self._gui = None
|
||||||
|
GLib.timeout_add(150, self._maybe_restore_focus)
|
||||||
|
|
||||||
|
def _maybe_restore_focus(self) -> bool:
|
||||||
|
"""Restores focus unless it already moved to another object in the target app."""
|
||||||
|
|
||||||
|
if not AXObject.is_valid(self._obj):
|
||||||
|
return False
|
||||||
|
|
||||||
|
manager = focus_manager.get_manager()
|
||||||
|
current_focus = manager.get_locus_of_focus()
|
||||||
|
if current_focus and AXObject.is_valid(current_focus):
|
||||||
|
target_app = AXObject.get_application(self._obj)
|
||||||
|
focus_app = AXObject.get_application(current_focus)
|
||||||
|
if target_app and focus_app == target_app and current_focus != self._obj:
|
||||||
|
tokens = ["ACTION PRESENTER: Skipping focus restore; focus now on", current_focus]
|
||||||
|
debug.printTokens(debug.LEVEL_INFO, tokens, True)
|
||||||
|
return False
|
||||||
|
|
||||||
self._restore_focus()
|
self._restore_focus()
|
||||||
|
return False
|
||||||
|
|
||||||
def _perform_action(self, action: str) -> None:
|
def _perform_action(self, action: str) -> None:
|
||||||
"""Attempts to perform the named action."""
|
"""Attempts to perform the named action."""
|
||||||
@@ -327,6 +331,7 @@ class ActionPresenter:
|
|||||||
|
|
||||||
self._gui = ActionList(self)
|
self._gui = ActionList(self)
|
||||||
self._gui.populate_actions(actions)
|
self._gui.populate_actions(actions)
|
||||||
|
self._gui.show_gui()
|
||||||
|
|
||||||
debug.printMessage(debug.LEVEL_INFO, "ACTION PRESENTER: GUI created successfully", True)
|
debug.printMessage(debug.LEVEL_INFO, "ACTION PRESENTER: GUI created successfully", True)
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -23,5 +23,5 @@
|
|||||||
# Forked from Orca screen reader.
|
# Forked from Orca screen reader.
|
||||||
# Cthulhu project: https://git.stormux.org/storm/cthulhu
|
# Cthulhu project: https://git.stormux.org/storm/cthulhu
|
||||||
|
|
||||||
version = "2025.12.27"
|
version = "2025.12.28"
|
||||||
codeName = "testing"
|
codeName = "testing"
|
||||||
|
|||||||
Reference in New Issue
Block a user