Linux lhjmq-records 5.15.0-118-generic #128-Ubuntu SMP Fri Jul 5 09:28:59 UTC 2024 x86_64
Your IP : 18.224.38.170
# Copyright 2015 Dustin Spicuzza <dustin@virtualroadside.com>
# 2018 Nikita Churaev <lamefun.x0r@gmail.com>
# 2018 Christoph Reiter <reiter.christoph@gmail.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
# USA
from collections import abc
from functools import partial
from gi.repository import GLib, GObject, Gio
def _extract_handler_and_args(obj_or_map, handler_name):
handler = None
if isinstance(obj_or_map, abc.Mapping):
handler = obj_or_map.get(handler_name, None)
else:
handler = getattr(obj_or_map, handler_name, None)
if handler is None:
raise AttributeError('Handler %s not found' % handler_name)
args = ()
if isinstance(handler, abc.Sequence):
if len(handler) == 0:
raise TypeError("Handler %s tuple can not be empty" % handler)
args = handler[1:]
handler = handler[0]
elif not callable(handler):
raise TypeError('Handler %s is not a method, function or tuple' % handler)
return handler, args
def define_builder_scope():
from gi.repository import Gtk
class BuilderScope(GObject.GObject, Gtk.BuilderScope):
def __init__(self, scope_object=None):
super().__init__()
self._scope_object = scope_object
def do_create_closure(self, builder, func_name, flags, obj):
current_object = builder.get_current_object() or self._scope_object
if not self._scope_object:
current_object = builder.get_current_object()
if func_name not in current_object.__gtktemplate_methods__:
return None
current_object.__gtktemplate_handlers__.add(func_name)
handler_name = current_object.__gtktemplate_methods__[func_name]
else:
current_object = self._scope_object
handler_name = func_name
swapped = int(flags & Gtk.BuilderClosureFlags.SWAPPED)
if swapped:
raise RuntimeError(
"%r not supported" % GObject.ConnectFlags.SWAPPED)
return None
handler, args = _extract_handler_and_args(current_object, handler_name)
if obj:
p = partial(handler, *args, swap_data=obj)
else:
p = partial(handler, *args)
p.__gtk_template__ = True
return p
return BuilderScope
def connect_func(builder, obj, signal_name, handler_name,
connect_object, flags, cls):
if handler_name not in cls.__gtktemplate_methods__:
return
method_name = cls.__gtktemplate_methods__[handler_name]
template_inst = builder.get_object(cls.__gtype_name__)
template_inst.__gtktemplate_handlers__.add(handler_name)
handler = getattr(template_inst, method_name)
after = int(flags & GObject.ConnectFlags.AFTER)
swapped = int(flags & GObject.ConnectFlags.SWAPPED)
if swapped:
raise RuntimeError(
"%r not supported" % GObject.ConnectFlags.SWAPPED)
if connect_object is not None:
if after:
func = obj.connect_object_after
else:
func = obj.connect_object
func(signal_name, handler, connect_object)
else:
if after:
func = obj.connect_after
else:
func = obj.connect
func(signal_name, handler)
def register_template(cls):
from gi.repository import Gtk
bound_methods = {}
bound_widgets = {}
for attr_name, obj in list(cls.__dict__.items()):
if isinstance(obj, CallThing):
setattr(cls, attr_name, obj._func)
handler_name = obj._name
if handler_name is None:
handler_name = attr_name
if handler_name in bound_methods:
old_attr_name = bound_methods[handler_name]
raise RuntimeError(
"Error while exposing handler %r as %r, "
"already available as %r" % (
handler_name, attr_name, old_attr_name))
else:
bound_methods[handler_name] = attr_name
elif isinstance(obj, Child):
widget_name = obj._name
if widget_name is None:
widget_name = attr_name
if widget_name in bound_widgets:
old_attr_name = bound_widgets[widget_name]
raise RuntimeError(
"Error while exposing child %r as %r, "
"already available as %r" % (
widget_name, attr_name, old_attr_name))
else:
bound_widgets[widget_name] = attr_name
cls.bind_template_child_full(widget_name, obj._internal, 0)
cls.__gtktemplate_methods__ = bound_methods
cls.__gtktemplate_widgets__ = bound_widgets
if Gtk._version == "4.0":
BuilderScope = define_builder_scope()
cls.set_template_scope(BuilderScope())
else:
cls.set_connect_func(connect_func, cls)
base_init_template = cls.init_template
cls.__dontuse_ginstance_init__ = \
lambda s: init_template(s, cls, base_init_template)
# To make this file work with older PyGObject we expose our init code
# as init_template() but make it a noop when we call it ourselves first
cls.init_template = cls.__dontuse_ginstance_init__
def init_template(self, cls, base_init_template):
self.init_template = lambda: None
if self.__class__ is not cls:
raise TypeError(
"Inheritance from classes with @Gtk.Template decorators "
"is not allowed at this time")
self.__gtktemplate_handlers__ = set()
base_init_template(self)
for widget_name, attr_name in self.__gtktemplate_widgets__.items():
self.__dict__[attr_name] = self.get_template_child(cls, widget_name)
for handler_name, attr_name in self.__gtktemplate_methods__.items():
if handler_name not in self.__gtktemplate_handlers__:
raise RuntimeError(
"Handler '%s' was declared with @Gtk.Template.Callback "
"but was not present in template" % handler_name)
class Child(object):
def __init__(self, name=None, **kwargs):
self._name = name
self._internal = kwargs.pop("internal", False)
if kwargs:
raise TypeError("Unhandled arguments: %r" % kwargs)
class CallThing(object):
def __init__(self, name, func):
self._name = name
self._func = func
class Callback(object):
def __init__(self, name=None):
self._name = name
def __call__(self, func):
return CallThing(self._name, func)
def validate_resource_path(path):
"""Raises GLib.Error in case the resource doesn't exist"""
try:
Gio.resources_get_info(path, Gio.ResourceLookupFlags.NONE)
except GLib.Error:
# resources_get_info() doesn't handle overlays but we keep using it
# as a fast path.
# https://gitlab.gnome.org/GNOME/pygobject/issues/230
Gio.resources_lookup_data(path, Gio.ResourceLookupFlags.NONE)
class Template(object):
def __init__(self, **kwargs):
self.string = None
self.filename = None
self.resource_path = None
if "string" in kwargs:
self.string = kwargs.pop("string")
elif "filename" in kwargs:
self.filename = kwargs.pop("filename")
elif "resource_path" in kwargs:
self.resource_path = kwargs.pop("resource_path")
else:
raise TypeError(
"Requires one of the following arguments: "
"string, filename, resource_path")
if kwargs:
raise TypeError("Unhandled keyword arguments %r" % kwargs)
@classmethod
def from_file(cls, filename):
return cls(filename=filename)
@classmethod
def from_string(cls, string):
return cls(string=string)
@classmethod
def from_resource(cls, resource_path):
return cls(resource_path=resource_path)
Callback = Callback
Child = Child
def __call__(self, cls):
from gi.repository import Gtk
if not isinstance(cls, type) or not issubclass(cls, Gtk.Widget):
raise TypeError("Can only use @Gtk.Template on Widgets")
if "__gtype_name__" not in cls.__dict__:
raise TypeError(
"%r does not have a __gtype_name__. Set it to the name "
"of the class in your template" % cls.__name__)
if hasattr(cls, "__gtktemplate_methods__"):
raise TypeError("Cannot nest template classes")
if self.string is not None:
data = self.string
if not isinstance(data, bytes):
data = data.encode("utf-8")
bytes_ = GLib.Bytes.new(data)
cls.set_template(bytes_)
register_template(cls)
return cls
elif self.resource_path is not None:
validate_resource_path(self.resource_path)
cls.set_template_from_resource(self.resource_path)
register_template(cls)
return cls
else:
assert self.filename is not None
file_ = Gio.File.new_for_path(self.filename)
bytes_ = GLib.Bytes.new(file_.load_contents()[1])
cls.set_template(bytes_)
register_template(cls)
return cls
__all__ = ["Template"]
|