Created
May 16, 2020 11:11
-
-
Save theY4Kman/f3ba8ee054aebeb25dc80e3d794d4d7d to your computer and use it in GitHub Desktop.
Query for GTK widgets using CSS syntax
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from typing import Callable, Iterable, List | |
import cssselect | |
import gi | |
from cssselect import GenericTranslator | |
gi.require_version('Gtk', '3.0') | |
from gi.repository import Gtk | |
def match_none(widget: Gtk.Widget) -> bool: | |
return False | |
def match_all(widget: Gtk.Widget) -> bool: | |
return True | |
def widget_find_children( | |
root: Gtk.Widget, | |
predicate: Callable[[Gtk.Widget], bool], | |
) -> List[Gtk.Widget]: | |
if not hasattr(root, 'get_children'): | |
return [] | |
return [child for child in root.get_children() if predicate(child)] | |
def widget_find_descendants( | |
root: Gtk.Widget, | |
predicate: Callable[[Gtk.Widget], bool], | |
) -> List[Gtk.Widget]: | |
matches = [] | |
parents = [root] | |
while parents: | |
parent = parents.pop() | |
if predicate(parent): | |
matches.append(parent) | |
parents.extend(widget_get_children(parent)) | |
return matches | |
def widget_get_children(root: Gtk.Widget) -> List[Gtk.Widget]: | |
if isinstance(root, Gtk.Container): | |
children = [] | |
root.forall(children.append) | |
return children | |
elif hasattr(root, 'get_child'): | |
child = root.get_child() | |
if child: | |
return [child] | |
return [] | |
def widget_select_children(root: Gtk.Widget, selector: str) -> List[Gtk.Widget]: | |
parsed = cssselect.parse('* ' + selector)[0] | |
tree = getattr(parsed, 'parsed_tree', None) | |
if not tree: | |
raise TypeError(f'Expected a parsed selector, got {selector!r}') | |
translator = GtkContainerSelectorTranslator() | |
get_matches = translator.xpath(tree) | |
return list(get_matches(root)) | |
class GtkContainerSelectorTranslator(GenericTranslator): | |
def xpath_descendant_combinator(self, left, right): | |
def filter_descendants(*roots: Gtk.Widget) -> Iterable[Gtk.Widget]: | |
for parent in left(*roots): | |
yield from widget_find_descendants(parent, self.as_predicate(right)) | |
return filter_descendants | |
def xpath_child_combinator(self, left, right): | |
def filter_children(*roots: Gtk.Widget) -> Iterable[Gtk.Widget]: | |
for parent in left(*roots): | |
yield from widget_find_children(parent, self.as_predicate(right)) | |
return filter_children | |
def as_predicate(self, widget_filter) -> Callable[[Gtk.Widget], bool]: | |
return lambda widget: any(widget_filter(widget)) | |
def xpath_hash(self, id_selector): | |
get_matches = self.xpath(id_selector.selector) | |
def filter_widget_name(*roots: Gtk.Widget) -> Iterable[Gtk.Widget]: | |
for widget in get_matches(*roots): | |
if widget.get_name() == id_selector.id: | |
yield widget | |
return filter_widget_name | |
def xpath_element(self, selector): | |
element = selector.element | |
if not element: | |
predicate = match_all | |
else: | |
suffix = f'.Gtk{element}'.lower() | |
predicate = lambda widget: widget.class_path().path.lower().endswith(suffix) | |
def filter_element(*roots: Gtk.Widget) -> Iterable[Gtk.Widget]: | |
for widget in roots: | |
if predicate(widget): | |
yield widget | |
return filter_element |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pygobject | |
cssselect |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment