Almost read for new version.
This commit is contained in:
@@ -63,41 +63,26 @@ class ActionList(Gtk.Window):
|
||||
"""Window containing a list of accessible actions."""
|
||||
|
||||
def __init__(self, presenter: ActionPresenter):
|
||||
super().__init__()
|
||||
super().__init__(window_position=Gtk.WindowPosition.MOUSE, transient_for=None)
|
||||
self._presenter = presenter
|
||||
self._actions = []
|
||||
self._setup_gui()
|
||||
|
||||
def _setup_gui(self) -> None:
|
||||
"""Sets up the GUI for the actions list."""
|
||||
|
||||
|
||||
self.set_title(guilabels.KB_GROUP_ACTIONS)
|
||||
self.set_modal(True)
|
||||
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.set_selection_mode(Gtk.SelectionMode.SINGLE)
|
||||
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("destroy", self._on_destroy)
|
||||
|
||||
self.show_all()
|
||||
|
||||
def _on_key_press(self, widget, event) -> bool:
|
||||
"""Handles key press events."""
|
||||
|
||||
@@ -108,19 +93,17 @@ class ActionList(Gtk.Window):
|
||||
|
||||
def _on_row_activated(self, listbox, row) -> None:
|
||||
"""Handles row activation (Enter or double-click)."""
|
||||
|
||||
if row is not None:
|
||||
action_index = row.get_index()
|
||||
if 0 <= action_index < len(self._actions):
|
||||
action_name = self._actions[action_index]
|
||||
self._presenter._perform_action(action_name)
|
||||
|
||||
action_name = getattr(row, "_action_name", None)
|
||||
if action_name:
|
||||
self._presenter._perform_action(action_name)
|
||||
|
||||
def _on_destroy(self, widget) -> None:
|
||||
"""Handles window destruction."""
|
||||
|
||||
|
||||
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."""
|
||||
|
||||
if isinstance(actions, dict):
|
||||
@@ -128,22 +111,19 @@ class ActionList(Gtk.Window):
|
||||
else:
|
||||
items = [(action, action) for action in actions]
|
||||
|
||||
self._actions = [name for name, _label in items]
|
||||
|
||||
# Clear existing items
|
||||
for child in self._listbox.get_children():
|
||||
self._listbox.remove(child)
|
||||
|
||||
# Add actions to list
|
||||
for _action, label_text in items:
|
||||
label = Gtk.Label(label=label_text)
|
||||
label.set_xalign(0.0) # Left align
|
||||
label.set_margin_left(10)
|
||||
label.set_margin_right(10)
|
||||
label.set_margin_top(5)
|
||||
label.set_margin_bottom(5)
|
||||
|
||||
self._listbox.add(label)
|
||||
for action_name, label_text in items:
|
||||
row = Gtk.ListBoxRow()
|
||||
label = Gtk.Label(label=label_text, xalign=0)
|
||||
label.set_margin_start(10)
|
||||
label.set_margin_end(10)
|
||||
row.add(label)
|
||||
setattr(row, "_action_name", action_name)
|
||||
self._listbox.add(row)
|
||||
|
||||
# Select first item
|
||||
if actions:
|
||||
@@ -152,7 +132,12 @@ class ActionList(Gtk.Window):
|
||||
self._listbox.select_row(first_row)
|
||||
first_row.grab_focus()
|
||||
|
||||
def show_gui(self) -> None:
|
||||
"""Shows the window."""
|
||||
|
||||
self.show_all()
|
||||
self.present_with_time(time.time())
|
||||
self._listbox.grab_focus()
|
||||
|
||||
|
||||
class ActionPresenter:
|
||||
@@ -264,7 +249,26 @@ class ActionPresenter:
|
||||
"""Clears the GUI reference and then restores focus."""
|
||||
|
||||
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()
|
||||
return False
|
||||
|
||||
def _perform_action(self, action: str) -> None:
|
||||
"""Attempts to perform the named action."""
|
||||
@@ -327,6 +331,7 @@ class ActionPresenter:
|
||||
|
||||
self._gui = ActionList(self)
|
||||
self._gui.populate_actions(actions)
|
||||
self._gui.show_gui()
|
||||
|
||||
debug.printMessage(debug.LEVEL_INFO, "ACTION PRESENTER: GUI created successfully", True)
|
||||
return True
|
||||
|
||||
@@ -23,5 +23,5 @@
|
||||
# Forked from Orca screen reader.
|
||||
# Cthulhu project: https://git.stormux.org/storm/cthulhu
|
||||
|
||||
version = "2025.12.27"
|
||||
version = "2025.12.28"
|
||||
codeName = "testing"
|
||||
|
||||
Reference in New Issue
Block a user