[gobject-introspection/ebassi/signal-emitter: 58/59] scanner: Add (emitter) annotation for signals




commit 59a77cc7a96e34aa0d49b8c82f647115a8286a56
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Wed Jun 23 19:12:18 2021 +0100

    scanner: Add (emitter) annotation for signals
    
    Signals that have an emitter function should have an annotation to allow
    consumers of the introspection XML to effectively pair signals to their
    corresponding emitter functions that share the same prototype.

 docs/gir-1.2.rnc                           |  2 ++
 docs/website/annotations/giannotations.rst |  4 +++
 giscanner/annotationparser.py              | 15 ++++++++
 giscanner/ast.py                           |  1 +
 giscanner/girparser.py                     |  1 +
 giscanner/girwriter.py                     |  2 ++
 giscanner/maintransformer.py               | 58 ++++++++++++++++++++++++------
 7 files changed, 73 insertions(+), 10 deletions(-)
---
diff --git a/docs/gir-1.2.rnc b/docs/gir-1.2.rnc
index a4943108..f7b1cd15 100644
--- a/docs/gir-1.2.rnc
+++ b/docs/gir-1.2.rnc
@@ -374,6 +374,8 @@ grammar {
       attribute no-hooks { "0" | "1" }?,
       ## Binary attribute, true if signals emitted for an object while currently being in emission for this 
very object will not be emitted recursively, but instead cause the first emission to be restarted 
(https://docs.gtk.org/gobject/flags.SignalFlags.html)
       attribute no-recurse { "0" | "1" }?,
+      ## The emitter method for the signal
+      attribute emitter { xsd:string }?,
 
       # Other elements a signal can contain
       (Info.elements
diff --git a/docs/website/annotations/giannotations.rst b/docs/website/annotations/giannotations.rst
index 7ed1a7cf..3e4bfa92 100644
--- a/docs/website/annotations/giannotations.rst
+++ b/docs/website/annotations/giannotations.rst
@@ -125,6 +125,10 @@ Support for GObject objects
       called by the ``GObjectClass.get_property`` implementation in a
       class.
     - :issue:`13`
+  * - ``(emitter METHOD)``
+    - identifier (only applies to methods)
+    - This signal is emitted by the given method
+    -
 
 
 Support for GObject closures
diff --git a/giscanner/annotationparser.py b/giscanner/annotationparser.py
index 9fbcfe7d..9a2677af 100644
--- a/giscanner/annotationparser.py
+++ b/giscanner/annotationparser.py
@@ -195,6 +195,7 @@ ANN_CLOSURE = 'closure'
 ANN_CONSTRUCTOR = 'constructor'
 ANN_DESTROY = 'destroy'
 ANN_ELEMENT_TYPE = 'element-type'
+ANN_EMITTER = 'emitter'
 ANN_FOREIGN = 'foreign'
 ANN_GET_PROPERTY = 'get-property'
 ANN_GET_VALUE_FUNC = 'get-value-func'
@@ -229,6 +230,7 @@ GI_ANNS = [ANN_ALLOW_NONE,
            ANN_CONSTRUCTOR,
            ANN_DESTROY,
            ANN_ELEMENT_TYPE,
+           ANN_EMITTER,
            ANN_FOREIGN,
            ANN_GET_PROPERTY,
            ANN_GET_VALUE_FUNC,
@@ -810,6 +812,18 @@ class GtkDocAnnotatable(object):
 
         self._validate_annotation(position, ann_name, options, min_n_options=1, max_n_options=2)
 
+    def _do_validate_emitter(self, position, ann_name, options):
+        '''
+        Validate the ``(emitter)`` annotation.
+
+        :param position: :class:`giscanner.message.Position` of the line in the source file
+                         containing the annotation to be validated
+        :param ann_name: name of the annotation holding the options to validate
+        :param options: annotation options to validate
+        '''
+
+        self._validate_annotation(position, ann_name, options, exact_n_options=1)
+
     def _do_validate_foreign(self, position, ann_name, options):
         '''
         Validate the ``(foreign)`` annotation.
@@ -1153,6 +1167,7 @@ class GtkDocCommentBlock(GtkDocAnnotatable):
     valid_annotations = (
         ANN_ATTRIBUTES,
         ANN_CONSTRUCTOR,
+        ANN_EMITTER,
         ANN_FOREIGN,
         ANN_GET_PROPERTY,
         ANN_GET_VALUE_FUNC,
diff --git a/giscanner/ast.py b/giscanner/ast.py
index c99c93d8..2cfd81fc 100644
--- a/giscanner/ast.py
+++ b/giscanner/ast.py
@@ -1184,6 +1184,7 @@ class Signal(Callable):
         self.detailed = detailed
         self.action = action
         self.no_hooks = no_hooks
+        self.emitter = None
 
 
 class Class(Node, Registered):
diff --git a/giscanner/girparser.py b/giscanner/girparser.py
index d9cda8d2..edaaa992 100644
--- a/giscanner/girparser.py
+++ b/giscanner/girparser.py
@@ -379,6 +379,7 @@ class GIRParser(object):
                          detailed=node.attrib.get('detailed', '0') == '1',
                          action=node.attrib.get('action', '0') == '1',
                          no_hooks=node.attrib.get('no-hooks', '0') == '1')
+            func.emitter = node.attrib.get('emitter')
         else:
             assert False
 
diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py
index 9a315145..9ff10d31 100644
--- a/giscanner/girwriter.py
+++ b/giscanner/girwriter.py
@@ -674,6 +674,8 @@ class GIRWriter(XMLWriter):
             attrs.append(('action', '1'))
         if signal.no_hooks:
             attrs.append(('no-hooks', '1'))
+        if signal.emitter:
+            attrs.append(('emitter', signal.emitter))
 
         self._append_version(signal, attrs)
         self._append_node_generic(signal, attrs)
diff --git a/giscanner/maintransformer.py b/giscanner/maintransformer.py
index 0f1ea9b6..2004d254 100644
--- a/giscanner/maintransformer.py
+++ b/giscanner/maintransformer.py
@@ -22,16 +22,49 @@ import re
 from . import ast
 from . import message
 from .annotationparser import (TAG_DEPRECATED, TAG_SINCE, TAG_STABILITY, TAG_RETURNS)
-from .annotationparser import (ANN_ALLOW_NONE, ANN_ARRAY, ANN_ATTRIBUTES, ANN_CLOSURE,
-                               ANN_CONSTRUCTOR, ANN_DESTROY, ANN_ELEMENT_TYPE, ANN_FOREIGN,
-                               ANN_GET_PROPERTY, ANN_GET_VALUE_FUNC, ANN_GETTER, ANN_IN, ANN_INOUT,
-                               ANN_METHOD, ANN_OUT, ANN_REF_FUNC, ANN_RENAME_TO, ANN_SCOPE,
-                               ANN_SET_PROPERTY, ANN_SET_VALUE_FUNC, ANN_SETTER, ANN_SKIP, ANN_TRANSFER,
-                               ANN_TYPE, ANN_UNREF_FUNC, ANN_VALUE, ANN_VFUNC, ANN_NULLABLE,
-                               ANN_OPTIONAL, ANN_NOT)
-from .annotationparser import (OPT_ARRAY_FIXED_SIZE, OPT_ARRAY_LENGTH, OPT_ARRAY_ZERO_TERMINATED,
-                               OPT_OUT_CALLEE_ALLOCATES, OPT_OUT_CALLER_ALLOCATES,
-                               OPT_TRANSFER_CONTAINER, OPT_TRANSFER_FLOATING, OPT_TRANSFER_NONE)
+from .annotationparser import (
+    ANN_ALLOW_NONE,
+    ANN_ARRAY,
+    ANN_ATTRIBUTES,
+    ANN_CLOSURE,
+    ANN_CONSTRUCTOR,
+    ANN_DESTROY,
+    ANN_ELEMENT_TYPE,
+    ANN_EMITTER,
+    ANN_FOREIGN,
+    ANN_GET_PROPERTY,
+    ANN_GET_VALUE_FUNC,
+    ANN_GETTER,
+    ANN_IN,
+    ANN_INOUT,
+    ANN_METHOD,
+    ANN_OUT,
+    ANN_REF_FUNC,
+    ANN_RENAME_TO,
+    ANN_SCOPE,
+    ANN_SET_PROPERTY,
+    ANN_SET_VALUE_FUNC,
+    ANN_SETTER,
+    ANN_SKIP,
+    ANN_TRANSFER,
+    ANN_TYPE,
+    ANN_UNREF_FUNC,
+    ANN_VALUE,
+    ANN_VFUNC,
+    ANN_NULLABLE,
+    ANN_OPTIONAL,
+    ANN_NOT,
+)
+from .annotationparser import (
+    OPT_ARRAY_FIXED_SIZE,
+    OPT_ARRAY_LENGTH,
+    OPT_ARRAY_ZERO_TERMINATED,
+    OPT_OUT_CALLEE_ALLOCATES,
+    OPT_OUT_CALLER_ALLOCATES,
+    OPT_TRANSFER_CONTAINER,
+    OPT_TRANSFER_FLOATING,
+    OPT_TRANSFER_NONE,
+)
 
 from .utils import to_underscores_noprefix
 
@@ -938,6 +971,11 @@ class MainTransformer(object):
 
         if block:
             self._apply_annotations_annotated(signal, block)
+
+            emitter = block.annotations.get(ANN_EMITTER)
+            if emitter:
+                signal.emitter = emitter[0]
+
             # We're only attempting to name the signal parameters if
             # the number of parameters (@foo) is the same or greater
             # than the number of signal parameters


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]