pelagicore / gdbus-codegen-glibmm Goto Github PK
View Code? Open in Web Editor NEWCode generator for C++ D-Bus stubs and proxies using Giomm/Glibmm
License: GNU Lesser General Public License v2.1
Code generator for C++ D-Bus stubs and proxies using Giomm/Glibmm
License: GNU Lesser General Public License v2.1
Should they be removed? Left over from refactoring? Or are they there intentionally?
If intentional, I think a comment is in order in the body or something. It is confusing as it is now. (Do I need to call it to be future proof?)
Starting out on my journey with DBus bindings so forgive me if I am doing something wrong/silly here...
Starting at the start: My goal is to generate a proxy object for Network Manager.
I can generate NetworkManager introspection XML with:
gdbus introspect --system --dest=org.freedesktop.NetworkManager --object-path=/org/freedesktop/NetworkManager --xml > generated/network_manager_introspect.xml
Then feed the XML into codegen:
gdbus-codegen-glibmm3 --generate-cpp-code=generated/network-manager generated/network_manager_introspect.xml --interface-prefix="org.freedesktop"
Firstly, this reproduces #77 as the sub-nodes are not populated in generated/network_manager_introspect.xml (stripping unnecessary detail):
...snip...
<node>
<interface name="org.freedesktop.NetworkManager">
...snip...
</interface>
<node name="DnsManager"/>
<node name="DHCP4Config"/>
<node name="ActiveConnection"/>
<node name="Devices"/>
<node name="AgentManager"/>
<node name="Settings"/>
<node name="IP6Config"/>
<node name="IP4Config"/>
</node>
Secondly, after deleting the sub-nodes, I tried feeding the modified XML into codegen again, it successfully generates the expected [cpp|h] files.
The 'CheckPermissions' signal: docs
that has no parameters and no return values is incorrectly generated in generated/network-manager_proxy.h:
class NetworkManager : public Glib::ObjectBase {
public:
...snip...
sigc::signal<void, > CheckPermissions_signal;
...snip...
The original GError
object is leaked in our throw_func
implementation.
First of all, thank you so much for providing this great utility. There seems to be trivial issue with the generated template function.
Input method schema:
<method name="SetProperty">
<arg name="name" type="s" direction="in"/>
<arg name="value" type="v" direction="in"/>
</method>
Generated proxy template function (indent as generated):
template <typename T>
void SetProperty(
std::string name,
T value,
const Gio::SlotAsyncReady &callback)
{
Glib::VariantContainerBase base;
std::vector<Glib::VariantBase> params;
Glib::Variant<Glib::ustring> name_param = Glib::Variant<Glib::ustring>::create(arg_name);
params.push_back(name_param);
Glib::Variant<Glib::Variant<T> > value_variantValue;
value_variantValue = Glib::Variant<Glib::Variant<T> >::create(Glib::Variant<T>::create(value_param));
params.push_back(value_variantValue);
base = Glib::VariantContainerBase::create_tuple(params);
m_proxy->call(
"SetProperty",
callback,
base);
}
Comparing the generated template function and other functions, it seems that the function argument naming and the variantValue reference are inconsistent. Is it correct that the template function should be generated as the following?
template <typename T>
void SetProperty(
std::string arg_name,
T arg_value,
const Gio::SlotAsyncReady &callback)
{
...
Glib::Variant<Glib::ustring> name_param = Glib::Variant<Glib::ustring>::create(arg_name);
...
value_variantValue = Glib::Variant<Glib::Variant<T> >::create(Glib::Variant<T>::create(arg_value));
...
Related code:
When running python setup.py install
on master I'm getting a syntax error:
byte-compiling build/bdist.linux-x86_64/egg/codegen_glibmm/codegen.py to codegen.cpython-36.pyc
File "build/bdist.linux-x86_64/egg/codegen_glibmm/codegen.py", line 227
print "WARNING: signal %s has too many parameters, skipping" % s.name
^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(print "WARNING: signal %s has too many parameters, skipping" % s.name)?
byte-compiling build/bdist.linux-x86_64/egg/codegen_glibmm/parser.py to parser.cpython-36.pyc
byte-compiling build/bdist.linux-x86_64/egg/codegen_glibmm/codegen_main.py to codegen_main.cpython-36.pyc
byte-compiling build/bdist.linux-x86_64/egg/codegen_glibmm/dbustypes.py to dbustypes.cpython-36.pyc
File "build/bdist.linux-x86_64/egg/codegen_glibmm/dbustypes.py", line 120
print "Unknown signature: " + self.signature
^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(print "Unknown signature: " + self.signature)?
Hi,
I was successfully generated stubs with methods and signals. I am trying to implement the dbus server using them. As it is quite easy to me to use stubs to implement the methods and call them, I have problem with signals implementation using stubs. I would like to evoke signal when by some external function to populate the string with message that something happened to another process.
Could you please give me any hint how to play with that?
This is part generated stub.cpp I am using:
<signal name="EventNotification">
<arg name="EventString" type="s"/>
</signal>
void com::my::busname::Processor::EventNotification_emitter(std::string EventString) {
std::vector<Glib::VariantBase> paramsList;
paramsList.push_back(Glib::Variant<Glib::ustring >::create((EventString)));;
m_connection->emit_signal(
"/com/my/busname/Processor",
"com.my.busname.Processor",
"EventNotification",
Glib::ustring(),
Glib::Variant<std::vector<Glib::VariantBase> >::create_tuple(paramsList));
}
I am trying to call : EventNotification_emmiter("Sample STRING");
This compile but after execution I have Segmentation fault (problem with memory).
EDIT:
void com::my::busname::Processor::EventNotification_emitter(std::string EventString) {
std::vector<Glib::VariantBase> paramsList;
paramsList.push_back(Glib::Variant<Glib::ustring >::create((EventString)));;
std::cout << "tu jestem" << std::endl;
m_connection->emit_signal(
"/com/my/busname/Processor",
"com.my.busname.Processor",
"EventNotification",
Glib::ustring(),
Glib::Variant<std::vector<Glib::VariantBase> >::create_tuple(paramsList));
}
It seems that the debuger point those line as problematic:
Glib::Variant<std::vector<Glib::VariantBase> >::create_tuple(paramsList));
In Glib docs I am unable to find such a member function like create_tuple().
BR,
Krzysztof
As e.g. GLib (and GTK does). Only <glib.h> is supposed to be included and all other headers are guarded by:
#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
#error "Only <glib.h> can be included directly."
#endif
commoh.h.templ currently contains *TypeWrap and Error if any error annotations are specified in introspection XML. *TypeWrap is not meant to be used externally (if I have understood things correctly) while Error is.
Could put *TypeWrap in common_private.h.templ and require FOO_BAR_OR_SOMETHING to be defined before it is included. Error would still stay in commoh.h.templ.
Currently, proxies can only choose between the system and the session bus. In order for them to be able to operate on a p2p connection, a factory method analog to Gio::DBus::Proxy::create()
needs to be added.
A quick try at it is here:
https://github.com/mardy/gdbus-codegen-glibmm/tree/proxy-on-any-connection
Eventually I will clean it up and propose a MR, if no one else gets there faster.
When clang++ is converted to g++, compilation does not proceed. Can you tell me why?
The glib library is not referenced.
Perhaps not that bad for a string, but e.g. have a signal that results in something like this in:
*_proxy.h:
sigc::signal<void, Glib::DBusObjectPathString, std::map<Glib::ustring,Glib::VariantBase>> Foo_signal;
*_proxy.cpp:Proxy::handle_signal():
if (parameters.get_n_children() != 2) return;
Glib::Variant<Glib::DBusObjectPathString> base_arg1;
parameters.get_child(base_arg1, 0);
Glib::DBusObjectPathString p_arg1;
p_arg1 = base_arg1.get();
if (parameters.get_n_children() != 2) return;
Glib::Variant<std::map<Glib::ustring,Glib::VariantBase>> base_arg2;
parameters.get_child(base_arg2, 1);
std::map<Glib::ustring,Glib::VariantBase> p_arg2;
p_arg2 = base_properties.get();
Foo_signal.emit((p_arg1), (p_arg2));
*_stub.cpp:
void Foo_emitter(Glib::DBusObjectPathString, std::map<Glib::ustring,Glib::VariantBase>);
sigc::signal<void, Glib::DBusObjectPathString, std::map<Glib::ustring,Glib::VariantBase>> Foo_signal;
void Stub::Foo_emitter(Glib::DBusObjectPathString arg1, std::map<Glib::ustring,Glib::VariantBase> arg2)
{
std::vector<Glib::VariantBase> paramsList;
paramsList.push_back(Glib::Variant<Glib::DBusObjectPathString>::create((arg1)));;
paramsList.push_back(Glib::Variant<std::map<Glib::ustring,Glib::VariantBase>>::create((arg2)));;
...
}
Should perhaps add const & or && and std::move for non simple types where applicable.
Not sure what the policy for backwards compatibility is, hence this issue instead of a pull request.
It is confusing to have it in the generated code.
Or perhaps maybe rework it? I guess the original intention was to hide the Gio::DBus::own_name() call from the user but the current implementation has some shortcomings (not possible to register multiple objects, nothing is done in name lost callback etc.) so register_object() was added in 92d9f83 .
But perhaps it makes sense to have some convenience API for Gio::DBus::own_name()? It just has to be more flexible?
gdbus-codegen supports file descriptors as the following anntation and GUnixFDList.
<annotation name = "org.gtk.GDBus.C.UnixFD" value = "true" />
It would be nice if gdbus-codegen-glibmm also supports file descriptors with the same annotation and Gio::UnixFDList.
I'm using glibmm's low API because the generator doesn't support it right now, so the code is unnatural.
If I try to include interfaces named like A.B
and A.B.C
at the same time, the B
is defined as both a class and a namespace :(
panel/320e00e@@n9-panel@exe/org.freedesktop.UPower.Device_proxy.h:9:11: error: redefinition of 'UPower' as different kind of symbol
namespace UPower {
^
panel/320e00e@@n9-panel@exe/org.freedesktop.UPower_proxy.h:10:7: note: previous definition is here
class UPower : public Glib::ObjectBase {
^
For now I'm using --cpp-namespace
as a workaround, but I wonder if a better solution is possible…
The body of the {{signal.name}}_emitter
in the stub.cpp.templ suggests that signals can't be simply broadcasted to be picked up by whoever client which has subscribed for signals via AddMatch.
The destinations for a signal should be known beforehand for emitter function to be able to emit targeted signals which IMHO is kind of in contrast with the message bus concept of signals.
I suggest to make the destination bus names optional and in case of empty list simply emit a signal without a destination.
Gio::DBus::Proxy::get_cached_property() returns an empty (bool operator returns false) variant if property is not cached. That is, this:
{{ prop.cpptype_out }} {{ class_name_with_namespace }}::{{ prop.name }}_get()
{
std::vector<Glib::ustring> props = m_proxy->get_cached_property_names();
Glib::Variant<{{ prop.variant_type }}> b;
if (std::find(props.begin(), props.end(), "{{ prop.name }}") != props.end()) {
m_proxy->get_cached_property(b, "{{ prop.name }}");
} else {
g_print("Todo: lookup value\n");
}
could be changed to something like:
{{ prop.cpptype_out }} {{ class_name_with_namespace }}::{{ prop.name }}_get()
{
Glib::Variant<{{ prop.variant_type }}> b;
m_proxy->get_cached_property(b, "{{ prop.name }}");
if (!b) {
g_print("Todo: lookup value\n");
}
I think... :)
There is a problem with the generation of the following interface.
<interface name="org.xxx.xxx.TestInterface"> <signal name="onTest"/> </interface>
Please consider applying the patch below.
support_signal_with_no_arg.txt
Thank you
Due to the design of Glib::Error
, the developer needs to have a way to retrieve the error domain associated with the generated error classes.
We should offer a static method which returns the GQuark
.
Meanwhile, if RTTI is enabled, one can use dynamic_cast
, with some pain.
I try to use type="ay", but it will generage std::string.
Would simplify certain use cases (e.g. interactive command line tools) where D-Bus methods are called or properties are set but it is not important to be responsive while calls are pending.
If we do not want to generate sync versions all the time a command line option could be added to optionally turn it on.
Glib::RefPtr and Glib::RefPtr wrapped helper classes should probably not be passed by value. A reference will be taken at call site, and in most cases object will just be dereferenced directly again when the call is done.
For instance, having the D-Bus method Test generates something similar to:
virtual void Test(FooMessageHelper msg) = 0;
in the stub. And FooMessageHelper has a RefPtr member variable.
A const & to the RefPtr (or simply a reference to the wrapped object) would probably be preferable.
Unsure why they are put in the global namespace.
Could namespace or perhaps better yet, nest TypeWrap in proxy and MessageHelper in stub.
Is it OK to change this? (Do not know what policy is with regards to backwards compatibility.) I can send a patch if it's OK and you tell me what you prefer.
I think nesting is better. I do not see why they are in common.h.templ. Not used in both proxy and stub. Am I missing something?
In fact, it is not a generator bug or limitation.
DBus signal is used by connecting xxx_emitter to sigc::signal, but sigc::signal can only use up to 7 arguments. So, if it exceeds the allowed number of arguments, it will not compile.
I think it may be helpful to output a warning message if there are too many arguments of the signal during code generation.
The link that is supposed to direct to the manual of Setuptools is broken.
Currently the <property name>_get()
function only handles the case where the property is already in the local cache. The local cache population is started during the creation of the proxy (by calling GetAll asyncronously), but is not guaranteed to be finished before the proxy is complete. Therefore the users of the proxy might call a property's get() method when the value is not in the cache, which will just print a todo message.
This can be problematic since there's no way to tell if a proper value was read or not, at least not for e.g. a bool where the returned value will be false and there's no way of telling that the value is not reflecting the actual property value. You will however see some internal glib messages:
GLib-CRITICAL **: 09:11:41.658: g_variant_get_type: assertion 'value != NULL' failed
GLib-CRITICAL **: 09:11:41.658: g_variant_type_is_subtype_of: assertion 'g_variant_type_check (type)' failed
GLib-CRITICAL **: 09:11:41.658: g_variant_get_boolean: assertion 'g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN)' failed
I'm not really sure what the best approach here is:
Hi, I saw this line at the bottom of the README:
"Source code licensed under the LGPL 2.1 (please see source code headers for more.)"
Is this applicable to the generated cpp source/header files? (Because there is no copyright notice in the generated files)
Would LGPL 2.1 mean I have to publish the generated sources?
I think it might be helpful to add a paragraph explaining licensing to the README.
Currently, our createForBus()
factory methods are not cancellable, but they must be.
As part of the process for a customer, we need to identify a maintainer.
Hi,
the problematic thing was to generate the method that get int as input argument, and output (si) - variant containing string and integer.
My solution:
In my code I overloaded the ret function in _common.h file to the following:
void ret(Glib::VariantContainerBase& p0)
{
m_message->return_value(p0);
}
then in my working class I implemented my example function as that:
virtual void myFunction (gint32 InArg, ProcessorMessageHelper msg)
{
std::cout << "HERE THE InArg IS: " << InArg << std::endl;
Glib::VariantContainerBase::CType outArg = NULL;
unsigned int outArg2 = InArg + 100;
std::string outArg1 = "Example: " + std::to_string(InArg) + " VALUE IS: ";
outArg = g_variant_new("(si)", outArg1.c_str(), outArg2);
Glib::Variant<unsigned int> outVar(outArg);
Glib::VariantContainerBase response = Glib::VariantContainerBase::create_tuple(outVar);
msg.ret(response);
}
I hope this can help someone to get the solution before the generator will be capable to solve that.
BTW: the example function is definied in XML as:
<method name="myFunction">
<arg name="InArg" direction="in" type="i"/>
<arg name="OutArg" direction="out" type="(si)"/>
</method>
BR
Krzysztof
Having the version of the code generator as a comment in each generated file will help debugging issues with the code generator.
It would be nice if the code generator supported file descriptors as arguments (signature 'h'). Currently get_type() will return None, triggering an assertion during generation.
At least it looks like it to me:
guint {{ class_name_with_namespace }}::register_object(...)
{
...
Gio::DBus::InterfaceVTable *interface_vtable =
new Gio::DBus::InterfaceVTable(
sigc::mem_fun(this, &{{ interface.cpp_class_name }}::on_method_call),
sigc::mem_fun(this, &{{ interface.cpp_class_name }}::on_interface_get_property),
sigc::mem_fun(this, &{{ interface.cpp_class_name }}::on_interface_set_property));
guint id = 0;
try {
id = connection->register_object(object_path,
introspection_data->lookup_interface("{{ interface.name }}"),
*interface_vtable); // NOTE: register_object() takes const InterfaceVTable &
m_connection = connection;
m_objectPath = object_path;
} catch(const Glib::Error &ex) {
g_warning("Registration of object failed");
}
// NOTE: interface_vtable leaked...
return id;
}
The documentation says:
"The only correct use of this class is to declare a global instance of it (or an instance local to the main function) and pass pointers to the instance to the methods that require such a parameter. The instance can be used for multiple registrations and the memory it uses will be freed at the end of execution. Any other use (like creating an instance local to a function and using that) may cause memory leaks or errors (if the instance is destroyed too early)."
Bad for a long running service if objects are created and removed dynamically and each creation leaks.
Do not see a simple fix though since we cannot have a single instance and use sigc::mem_fun for the slots.
While not very common, there are cases where one might want to export the very same object over two different object paths. Also, especially when dealing with clients connecting directly to the service over a socket connection (bypassing the D-Bus daemon), it should be possible to export the same object over two different connections (on the same or on a different object path).
I got a problem with a single closing tag.
" <node name="bluetooth"/> "
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.