refactor(ui-query): extract shared find_windows() to common.py

Consolidates duplicate find_windows() from get-text.py and find-element.py
into a shared module. Also adds get_all_windows() helper.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
dan 2026-01-15 14:54:11 -08:00
parent e428be1ae6
commit bccf7514ce
4 changed files with 76 additions and 76 deletions

1
skills/ui-query/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
__pycache__/

View file

@ -0,0 +1,69 @@
"""Shared utilities for ui-query scripts."""
import pyatspi
def find_windows(pattern=None, app_name=None, all_windows=False):
"""Find windows matching criteria.
Args:
pattern: Substring to match in window name (case-insensitive)
app_name: Substring to match in application name (case-insensitive)
all_windows: If True, return all windows (ignore pattern/app_name)
Returns:
List of dicts with 'app', 'window', and 'accessible' keys
"""
desktop = pyatspi.Registry.getDesktop(0)
matches = []
for i in range(desktop.childCount):
app = desktop.getChildAtIndex(i)
if not app:
continue
# Filter by app name
if app_name and app_name.lower() not in (app.name or "").lower():
continue
for j in range(app.childCount):
window = app.getChildAtIndex(j)
if not window:
continue
window_name = window.name or ""
# Filter by window pattern
if pattern and pattern.lower() not in window_name.lower():
continue
# Include if: all_windows requested, or any filter was specified
if all_windows or pattern or app_name:
matches.append({
"app": app.name or "(unnamed)",
"window": window_name,
"accessible": window,
})
return matches
def get_all_windows():
"""Get all windows without filtering.
Returns:
List of dicts with 'accessible' key (minimal info for searching)
"""
desktop = pyatspi.Registry.getDesktop(0)
windows = []
for i in range(desktop.childCount):
app = desktop.getChildAtIndex(i)
if not app:
continue
for j in range(app.childCount):
window = app.getChildAtIndex(j)
if window:
windows.append({"accessible": window})
return windows

View file

@ -22,6 +22,8 @@ import sys
import pyatspi
from common import find_windows, get_all_windows
def get_element_info(element):
"""Extract useful info from an accessible element."""
@ -126,37 +128,6 @@ def find_elements(accessible, role=None, name=None, results=None, max_depth=15,
return results
def find_windows(pattern=None, app_name=None):
"""Find windows matching criteria."""
desktop = pyatspi.Registry.getDesktop(0)
matches = []
for i in range(desktop.childCount):
app = desktop.getChildAtIndex(i)
if not app:
continue
if app_name and app_name.lower() not in (app.name or "").lower():
continue
for j in range(app.childCount):
window = app.getChildAtIndex(j)
if not window:
continue
window_name = window.name or ""
if pattern and pattern.lower() not in window_name.lower():
continue
matches.append({
"app": app.name or "(unnamed)",
"window": window_name,
"accessible": window,
})
return matches
def print_results(results, as_json=False):
"""Print search results."""
if as_json:
@ -206,7 +177,7 @@ def main():
sys.exit(1)
try:
windows = find_windows(args.window, args.app)
windows = find_windows(pattern=args.window, app_name=args.app)
except Exception as e:
print(f"Error accessing AT-SPI: {e}", file=sys.stderr)
sys.exit(1)
@ -216,15 +187,7 @@ def main():
print("No matching windows found.", file=sys.stderr)
else:
# Search all windows
desktop = pyatspi.Registry.getDesktop(0)
windows = []
for i in range(desktop.childCount):
app = desktop.getChildAtIndex(i)
if app:
for j in range(app.childCount):
win = app.getChildAtIndex(j)
if win:
windows.append({"accessible": win})
windows = get_all_windows()
all_results = []
for win in windows:

View file

@ -21,6 +21,8 @@ from dataclasses import dataclass, field
import pyatspi
from common import find_windows
@dataclass
class TextNode:
@ -118,41 +120,6 @@ def flatten_text(node, indent=0):
return lines
def find_windows(pattern=None, app_name=None, all_windows=False):
"""Find windows matching criteria."""
desktop = pyatspi.Registry.getDesktop(0)
matches = []
for i in range(desktop.childCount):
app = desktop.getChildAtIndex(i)
if not app:
continue
# Filter by app name
if app_name and app_name.lower() not in (app.name or "").lower():
continue
for j in range(app.childCount):
window = app.getChildAtIndex(j)
if not window:
continue
window_name = window.name or ""
# Filter by window pattern
if pattern and pattern.lower() not in window_name.lower():
continue
if all_windows or pattern or app_name:
matches.append({
"app": app.name or "(unnamed)",
"window": window_name,
"accessible": window,
})
return matches
def main():
parser = argparse.ArgumentParser(description="Extract text from AT-SPI windows")
parser.add_argument("pattern", nargs="?", help="Window name pattern to match")