Skip to content

Instantly share code, notes, and snippets.

@theY4Kman
Created May 16, 2020 11:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save theY4Kman/f3ba8ee054aebeb25dc80e3d794d4d7d to your computer and use it in GitHub Desktop.
Save theY4Kman/f3ba8ee054aebeb25dc80e3d794d4d7d to your computer and use it in GitHub Desktop.
Query for GTK widgets using CSS syntax
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
pygobject
cssselect
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment