gobject.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. // no code generation is needed
  2. // all required functionality is required by the basic code
  3. #include <gi/gi.hpp>
  4. #include <iostream>
  5. namespace GObject_ = gi::repository::GObject;
  6. // class must be a ObjectImpl to support properties and signals
  7. class Person : public GObject_::impl::ObjectImpl
  8. {
  9. private:
  10. // the implementation/definition part of the properties
  11. // (could also be constructed here, but let's do that in constructor below)
  12. // this provides interface to set/get the actual value
  13. gi::property<int> prop_age_;
  14. gi::property<std::string> prop_firstname_;
  15. gi::property<std::string> prop_lastname_;
  16. public:
  17. // likewise for signal
  18. // public because there is no extra interface for owning class
  19. // (both owner and outside can connect and/or emit)
  20. // btw, using Person in this signature would not be the way to go,
  21. // should stick to a plain wrapped type
  22. gi::signal<void(GObject_::Object, int)> signal_trigger;
  23. // std::string also works here,
  24. // but that would cost an extra allocation during invocation
  25. gi::signal<void(GObject_::Object, gi::cstring_v)> signal_example;
  26. public:
  27. Person()
  28. : ObjectImpl(this),
  29. // the setup parameters shadow the corresponding g_param_spec_xxx
  30. // so in practice define the property (name, nick, description)
  31. // along with min, max, default and so (where applicable)
  32. prop_age_(this, "age", "age", "age", 0, 100, 10),
  33. prop_firstname_(this, "firstname", "firstname", "firstname", ""),
  34. prop_lastname_(this, "lastname", "lastname", "lastname", ""),
  35. signal_trigger(this, "trigger"), signal_example(this, "example")
  36. {}
  37. // the public counterpart providing the same interface
  38. // as with any wrapped object's predefined properties
  39. gi::property_proxy<int> prop_age() { return prop_age_.get_proxy(); }
  40. gi::property_proxy<std::string> prop_firstname()
  41. {
  42. return prop_firstname_.get_proxy();
  43. }
  44. gi::property_proxy<std::string> prop_lastname()
  45. {
  46. return prop_lastname_.get_proxy();
  47. }
  48. void action(int id)
  49. {
  50. std::cout << "Changing the properties of 'p'" << std::endl;
  51. prop_firstname_ = "John";
  52. prop_lastname_ = "Doe";
  53. prop_age_ = 43;
  54. std::cout << "Done changing the properties of 'p'" << std::endl;
  55. // we were triggered after all
  56. signal_trigger.emit(id);
  57. }
  58. };
  59. void on_firstname_changed(GObject_::Object, GObject_::ParamSpec)
  60. {
  61. std::cout << "- firstname changed!" << std::endl;
  62. }
  63. void on_lastname_changed(GObject_::Object, GObject_::ParamSpec)
  64. {
  65. std::cout << "- lastname changed!" << std::endl;
  66. }
  67. void on_age_changed(GObject_::Object, GObject_::ParamSpec)
  68. {
  69. std::cout << "- age changed!" << std::endl;
  70. }
  71. int
  72. main(int /*argc*/, char ** /*argv*/)
  73. {
  74. Person p;
  75. // register some handlers that will be called when the values of the
  76. // specified parameters are changed
  77. p.prop_firstname().signal_notify().connect(&on_firstname_changed);
  78. p.prop_lastname().signal_notify().connect(on_lastname_changed);
  79. p.prop_age().signal_notify().connect(&on_age_changed);
  80. // now change the properties and see that the handlers get called
  81. p.action(0);
  82. // (derived) object can be constructed on stack for simple cases
  83. // but in other (real) cases it is recommended that it is heap based.
  84. // so as not to have a naked ptr, it can be managed by a (special) shared
  85. // ptr that uses the GObject refcount for (shared) ownership tracking
  86. auto dp = gi::make_ref<Person>();
  87. // however, the GObject world has no knowledge of the subclass
  88. // (each instance is 1-to-1 with Person instance though).
  89. // so when we get something from that world, we can (sort-of dynamic)
  90. // cast to the subclass
  91. auto l = [](GObject_::Object ob, int id) {
  92. std::cout << " - triggered id " << id << std::endl;
  93. // obtain Person
  94. auto lp = gi::ref_ptr_cast<Person>(ob);
  95. if (lp)
  96. std::cout << " - it was a person!" << std::endl;
  97. // it really should be ...
  98. assert(lp);
  99. };
  100. dp->signal_trigger.connect(l);
  101. dp->action(1);
  102. return 0;
  103. }