language: Add not-swapped flag for signals

This is needed because GtkBuilder defaults to swapped when you specify
the object attribute.
This commit is contained in:
James Westman 2024-12-09 20:29:08 -06:00
parent 9b9fab832b
commit a6d57cebec
10 changed files with 72 additions and 8 deletions

View file

@ -27,6 +27,7 @@ from .gtkbuilder_template import Template
class SignalFlag(AstNode):
grammar = AnyOf(
UseExact("flag", "swapped"),
UseExact("flag", "not-swapped"),
UseExact("flag", "after"),
)
@ -40,6 +41,27 @@ class SignalFlag(AstNode):
f"Duplicate flag '{self.flag}'", lambda x: x.flag == self.flag
)
@validate()
def swapped_exclusive(self):
if self.flag in ["swapped", "not-swapped"]:
self.validate_unique_in_parent(
"'swapped' and 'not-swapped' flags cannot be used together",
lambda x: x.flag in ["swapped", "not-swapped"],
)
@validate()
def swapped_unnecessary(self):
if self.flag == "not-swapped" and self.parent.object_id is None:
raise CompileWarning(
"'not-swapped' is the default for handlers that do not specify an object",
actions=[CodeAction("Remove 'not-swapped' flag", "")],
)
elif self.flag == "swapped" and self.parent.object_id is not None:
raise CompileWarning(
"'swapped' is the default for handlers that specify an object",
actions=[CodeAction("Remove 'swapped' flag", "")],
)
@docs()
def ref_docs(self):
return get_docs_section("Syntax Signal")
@ -92,9 +114,17 @@ class Signal(AstNode):
def flags(self) -> T.List[SignalFlag]:
return self.children[SignalFlag]
# Returns True if the "swapped" flag is present, False if "not-swapped" is present, and None if neither are present.
# GtkBuilder's default if swapped is not specified is to not swap the arguments if no object is specified, and to
# swap them if an object is specified.
@property
def is_swapped(self) -> bool:
return any(x.flag == "swapped" for x in self.flags)
def is_swapped(self) -> T.Optional[bool]:
for flag in self.flags:
if flag.flag == "swapped":
return True
elif flag.flag == "not-swapped":
return False
return None
@property
def is_after(self) -> bool:
@ -194,15 +224,16 @@ class Signal(AstNode):
@decompiler("signal")
def decompile_signal(
ctx, gir, name, handler, swapped="false", after="false", object=None
):
def decompile_signal(ctx, gir, name, handler, swapped=None, after="false", object=None):
object_name = object or ""
name = name.replace("_", "-")
line = f"{name} => ${handler}({object_name})"
if decompile.truthy(swapped):
line += " swapped"
elif swapped is not None:
line += " not-swapped"
if decompile.truthy(after):
line += " after"

View file

@ -169,7 +169,7 @@ class XmlOutput(OutputFormat):
"signal",
name=name,
handler=signal.handler,
swapped=signal.is_swapped or None,
swapped=signal.is_swapped,
after=signal.is_after or None,
object=(
self._object_id(signal, signal.object_id) if signal.object_id else None

View file

@ -91,7 +91,7 @@ Signal Handlers
.. rst-class:: grammar-block
Signal = <name::ref:`IDENT<Syntax IDENT>`> ('::' <detail::ref:`IDENT<Syntax IDENT>`>)? '=>' '$' <handler::ref:`IDENT<Syntax IDENT>`> '(' <object::ref:`IDENT<Syntax IDENT>`>? ')' (SignalFlag)* ';'
SignalFlag = 'after' | 'swapped'
SignalFlag = 'after' | 'swapped' | 'not-swapped'
Signals are one way to respond to user input (another is `actions <https://docs.gtk.org/gtk4/actions.html>`_, which use the `action-name property <https://docs.gtk.org/gtk4/property.Actionable.action-name.html>`_).
@ -99,6 +99,8 @@ Signals provide a handle for your code to listen to events in the UI. The handle
Optionally, you can provide an object ID to use when connecting the signal.
The ``swapped`` flag is used to swap the order of the object and userdata arguments in C applications. If an object argument is specified, then this is the default behavior, so the ``not-swapped`` flag can be used to prevent the swap.
Example
~~~~~~~
@ -108,7 +110,6 @@ Example
clicked => $on_button_clicked();
}
.. _Syntax Child:
Children

View file

@ -0,0 +1,5 @@
using Gtk 4.0;
$MyObject obj {
signal1 => $handler() swapped not-swapped;
}

View file

@ -0,0 +1 @@
4,33,11,'swapped' and 'not-swapped' flags cannot be used together

View file

@ -0,0 +1,6 @@
using Gtk 4.0;
$MyObject obj {
signal1 => $handler() not-swapped;
signal2 => $handler(obj) swapped;
}

View file

@ -0,0 +1,2 @@
4,25,11,'not-swapped' is the default for handlers that do not specify an object
5,28,7,'swapped' is the default for handlers that specify an object

View file

@ -0,0 +1,5 @@
using Gtk 4.0;
Button obj {
clicked => $handler(obj) not-swapped;
}

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
DO NOT EDIT!
This file was @generated by blueprint-compiler. Instead, edit the
corresponding .blp file and regenerate this file with blueprint-compiler.
-->
<interface>
<requires lib="gtk" version="4.0"/>
<object class="GtkButton" id="obj">
<signal name="clicked" handler="handler" swapped="False" object="obj"/>
</object>
</interface>

View file

@ -200,6 +200,7 @@ class TestSamples(unittest.TestCase):
"expr_closure_args",
"parseable",
"signal",
"signal_not_swapped",
"template",
"template_binding",
"template_binding_extern",