object.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. #ifndef GI_OBJECT_HPP
  2. #define GI_OBJECT_HPP
  3. #include "callback.hpp"
  4. #include "container.hpp"
  5. #include "exception.hpp"
  6. #include "objectbase.hpp"
  7. #include "paramspec.hpp"
  8. #include "value.hpp"
  9. namespace gi
  10. {
  11. namespace detail
  12. {
  13. // helper
  14. // signal argument connect/emit helper;
  15. // turn (C++) argument into a GType or GValue
  16. // most arguments are inputs (with specific GType),
  17. // but some arguments are used as output with G_TYPE_POINTER (e.g. int*)
  18. // which are mapped to (e.g.) int* or int& in C++ signature
  19. template<typename Arg, bool DECAY>
  20. struct signal_arg
  21. {
  22. static GType get_type() { return traits::gtype<Arg>::get_type(); }
  23. static detail::Value make(Arg arg)
  24. {
  25. return detail::Value(std::forward<Arg>(arg));
  26. }
  27. };
  28. // re-route e.g. const std::string& cases
  29. template<typename Arg>
  30. struct signal_arg<const Arg &, false> : public signal_arg<const Arg &, true>
  31. {};
  32. template<typename Arg>
  33. struct signal_arg<Arg &, false>
  34. {
  35. static GType get_type() { return G_TYPE_POINTER; }
  36. static detail::Value make(Arg &arg)
  37. {
  38. return signal_arg<Arg *, false>::make(&arg);
  39. }
  40. };
  41. template<typename Arg>
  42. struct signal_arg<Arg *, false>
  43. {
  44. static GType get_type() { return G_TYPE_POINTER; }
  45. static detail::Value make(Arg *arg)
  46. {
  47. // (size of) wrapper argument should match wrappee
  48. static_assert(sizeof(typename traits::ctype<Arg>::type) == sizeof(Arg), "");
  49. // the above should suffice for proper handling
  50. // however, in these output cases, transfer should also be considered,
  51. // which is not (yet) available here
  52. // (but could be passed along similar to callback argument info)
  53. // so, restrict to plain cases for now
  54. static_assert(traits::is_plain<Arg>::value, "");
  55. return detail::Value(gpointer(arg));
  56. }
  57. };
  58. // returns -size if signed numeric, +size if unsigned numeric, otherwise 0
  59. inline int
  60. get_number_size_signed(GType type)
  61. {
  62. // note; these are generally lower (absolute) bounds
  63. // at least it works in the context where it is used below
  64. #define GI_HANDLE_TYPE_SWITCH(cpptype, g_type, factor) \
  65. case g_type: \
  66. return factor * int(sizeof(cpptype));
  67. switch (type) {
  68. GI_HANDLE_TYPE_SWITCH(gchar, G_TYPE_CHAR, -1)
  69. GI_HANDLE_TYPE_SWITCH(guchar, G_TYPE_UCHAR, 1)
  70. GI_HANDLE_TYPE_SWITCH(gint, G_TYPE_INT, -1)
  71. GI_HANDLE_TYPE_SWITCH(guint, G_TYPE_UINT, 1)
  72. GI_HANDLE_TYPE_SWITCH(glong, G_TYPE_LONG, -1)
  73. GI_HANDLE_TYPE_SWITCH(gulong, G_TYPE_ULONG, 1)
  74. GI_HANDLE_TYPE_SWITCH(gint64, G_TYPE_INT64, -1)
  75. GI_HANDLE_TYPE_SWITCH(guint64, G_TYPE_UINT64, 1)
  76. }
  77. #undef GI_HANDLE_TYPE_SWITCH
  78. return 0;
  79. }
  80. // glib type systems treats G_TYPE_INT64 as distinct from the other types
  81. // in practice, however, quite likely C gint64 == long
  82. inline bool
  83. compatible_type(GType expected, GType actual)
  84. {
  85. if (expected == G_TYPE_BOOLEAN)
  86. return std::abs(get_number_size_signed(actual)) == sizeof(gboolean);
  87. auto ssa_e = get_number_size_signed(expected);
  88. auto ssa_a = get_number_size_signed(actual);
  89. return ssa_e == ssa_a;
  90. }
  91. inline void
  92. check_signal_type(GType tp, const gi::cstring_v name, GType return_type,
  93. GType *param_types, guint n_params)
  94. {
  95. const char *errmsg("expected ");
  96. auto check_types = [tp, &name, &errmsg](const std::string &desc,
  97. GType expected, GType actual) {
  98. // normalize
  99. expected &= ~G_SIGNAL_TYPE_STATIC_SCOPE;
  100. actual &= ~G_SIGNAL_TYPE_STATIC_SCOPE;
  101. if (expected == actual || compatible_type(expected, actual) ||
  102. g_type_is_a(expected, actual))
  103. return;
  104. std::string msg = errmsg;
  105. msg += desc + " type ";
  106. msg += detail::make_string(g_type_name(expected)) + " != ";
  107. msg += detail::make_string(g_type_name(actual));
  108. detail::try_throw(invalid_signal_callback_error(tp, name, msg));
  109. };
  110. // determine signal (detail)
  111. guint id;
  112. GQuark detail;
  113. if (!g_signal_parse_name(name.c_str(), tp, &id, &detail, false) || (id == 0))
  114. detail::try_throw(unknown_signal_error(tp, name));
  115. // get signal info
  116. GSignalQuery query;
  117. g_signal_query(id, &query);
  118. // check
  119. if (n_params != query.n_params + 1) {
  120. auto msg = std::string(errmsg) + "argument count ";
  121. msg += std::to_string(query.n_params);
  122. msg += " != " + std::to_string(n_params);
  123. detail::try_throw(invalid_signal_callback_error(tp, name, msg));
  124. }
  125. check_types("return", query.return_type, return_type);
  126. check_types("instance", query.itype, param_types[0]);
  127. const std::string arg("argument ");
  128. for (guint i = 0; i < query.n_params; ++i)
  129. check_types(
  130. arg + std::to_string(i + 1), query.param_types[i], param_types[i + 1]);
  131. }
  132. template<typename G>
  133. struct signal_type;
  134. template<typename R, typename... Args>
  135. struct signal_type<R(Args...)>
  136. {
  137. static void check(GType tp, const gi::cstring_v name)
  138. {
  139. // capture type info and delegate
  140. const int argcount = sizeof...(Args);
  141. GType ti[] = {signal_arg<Args, false>::get_type()...};
  142. check_signal_type(tp, name, traits::gtype<R>::get_type(), ti, argcount);
  143. }
  144. };
  145. // like GParameter, but with extra Value trimming
  146. struct Parameter
  147. {
  148. const char *name;
  149. detail::Value value;
  150. };
  151. #ifdef GI_OBJECT_NEWV
  152. GI_DISABLE_DEPRECATED_WARN_BEGIN
  153. static_assert(sizeof(Parameter) == sizeof(GParameter), "");
  154. GI_DISABLE_DEPRECATED_WARN_END
  155. #endif
  156. inline void
  157. fill_parameters(Parameter *)
  158. {
  159. // no-op
  160. }
  161. template<typename Arg, typename... Args>
  162. inline void
  163. fill_parameters(Parameter *param, const char *name, Arg &&arg, Args &&...args)
  164. {
  165. param->name = name;
  166. param->value.init<typename std::remove_reference<Arg>::type>();
  167. set_value(&param->value, std::forward<Arg>(arg));
  168. fill_parameters(param + 1, std::forward<Args>(args)...);
  169. }
  170. } // namespace detail
  171. #if GLIB_CHECK_VERSION(2, 54, 0)
  172. #define GI_GOBJECT_PROPERTY_VALUE 1
  173. #endif
  174. namespace repository
  175. {
  176. /* if you have arrived here due to an ambiguous GObject reference
  177. * (both the C typedef GObject and this namespace)
  178. * then that can be worked-around by:
  179. * + using _GObject (struct name instead)
  180. * + adjust 'using namespace' style imports e.g. alias
  181. * namespace GObject_ = gi::GObject;
  182. * or simply do not mention GObject at all and simply use the wrappers ;-)
  183. */
  184. namespace GObject
  185. {
  186. typedef std::vector<detail::Parameter> construct_params;
  187. template<typename... Args>
  188. construct_params
  189. make_construct_params(Args &&...args)
  190. {
  191. const int nparams = sizeof...(Args) / 2;
  192. construct_params parameters;
  193. parameters.resize(nparams);
  194. detail::fill_parameters(parameters.data(), std::forward<Args>(args)...);
  195. return parameters;
  196. }
  197. class Object : public detail::ObjectBase
  198. {
  199. typedef Object self;
  200. typedef detail::ObjectBase super_type;
  201. public:
  202. typedef ::GObject BaseObjectType;
  203. Object(std::nullptr_t = nullptr) : super_type() {}
  204. BaseObjectType *gobj_() { return (BaseObjectType *)super_type::gobj_(); }
  205. const BaseObjectType *gobj_() const
  206. {
  207. return (const BaseObjectType *)super_type::gobj_();
  208. }
  209. BaseObjectType *gobj_copy_() const
  210. {
  211. return (BaseObjectType *)super_type::gobj_copy_();
  212. }
  213. // class type
  214. static GType get_type_() { return G_TYPE_OBJECT; }
  215. // instance type
  216. GType gobj_type_() const { return G_OBJECT_TYPE(gobj_()); }
  217. // type-erased generic object creation
  218. // transfer full return
  219. static gpointer new_(GType gtype, const construct_params &params)
  220. {
  221. #ifdef GI_OBJECT_NEWV
  222. GI_DISABLE_DEPRECATED_WARN_BEGIN
  223. auto result =
  224. g_object_newv(gtype, params.size(), (GParameter *)params.data());
  225. GI_DISABLE_DEPRECATED_WARN_END
  226. #else
  227. std::vector<const char *> names;
  228. std::vector<GValue> values;
  229. names.reserve(params.size());
  230. values.reserve(params.size());
  231. // ownership remains in params
  232. for (auto &&p : params) {
  233. names.push_back(p.name);
  234. values.emplace_back(p.value);
  235. }
  236. auto result = g_object_new_with_properties(
  237. gtype, params.size(), names.data(), values.data());
  238. #endif
  239. // GIR says transfer full, but let's be careful and really make it so
  240. // if likely still floating, then we assume ownership
  241. // but if it is no longer, then it has already been stolen (e.g.
  242. // GtkWindow), and we need to add one here
  243. if (g_type_is_a(gtype, G_TYPE_INITIALLY_UNOWNED))
  244. g_object_ref_sink(result);
  245. return result;
  246. }
  247. // type-based generic object creation
  248. template<typename TYPE, typename... Args>
  249. static TYPE new_(Args &&...args)
  250. {
  251. auto parameters = make_construct_params(std::forward<Args>(args)...);
  252. typename TYPE::BaseObjectType *result =
  253. (typename TYPE::BaseObjectType *)new_(TYPE::get_type_(), parameters);
  254. return gi::wrap(result, transfer_full);
  255. }
  256. // property stuff
  257. // generic type unsafe
  258. template<typename V>
  259. self &set_property(ParamSpec _pspec, V &&val)
  260. {
  261. // additional checks
  262. // allows for basic conversion between arithmetic types
  263. // without worrying about those details
  264. auto pspec = _pspec.gobj_();
  265. detail::Value v(std::forward<V>(val));
  266. detail::Value dest;
  267. GValue *p = &v;
  268. if (G_VALUE_TYPE(&v) != pspec->value_type) {
  269. g_value_init(&dest, pspec->value_type);
  270. if (!g_value_transform(&v, &dest))
  271. detail::try_throw(
  272. detail::transform_error(pspec->value_type, pspec->name));
  273. p = &dest;
  274. }
  275. g_object_set_property(gobj_(), pspec->name, p);
  276. return *this;
  277. }
  278. template<typename V>
  279. self &set_property(const gi::cstring_v propname, V &&val)
  280. {
  281. return set_property<V>(find_property(propname, true), std::forward<V>(val));
  282. }
  283. template<typename V>
  284. self &set_properties(const gi::cstring_v propname, V &&val)
  285. {
  286. return set_property<V>(propname, std::forward<V>(val));
  287. }
  288. // set a number of props
  289. template<typename V, typename... Args>
  290. self &set_properties(const gi::cstring_v propname, V &&val, Args... args)
  291. {
  292. g_object_freeze_notify(gobj_());
  293. #if GI_CONFIG_EXCEPTIONS
  294. try {
  295. #endif
  296. set_property(propname, std::forward<V>(val));
  297. set_properties(std::forward<Args>(args)...);
  298. #if GI_CONFIG_EXCEPTIONS
  299. } catch (...) {
  300. g_object_thaw_notify(gobj_());
  301. throw;
  302. }
  303. #endif
  304. g_object_thaw_notify(gobj_());
  305. return *this;
  306. }
  307. #ifdef GI_GOBJECT_PROPERTY_VALUE
  308. self &set_property(const gi::cstring_v propname, Value val)
  309. {
  310. g_object_set_property(gobj_(), propname.c_str(), val.gobj_());
  311. return *this;
  312. }
  313. #endif
  314. template<typename V>
  315. V get_property(const char *propname) const
  316. {
  317. // this would return a ref to what is owned by stack-local v below
  318. static_assert(!traits::is_reftype<V>::value, "dangling ref");
  319. detail::Value v;
  320. v.init<V>();
  321. // the _get_ already tries to transform
  322. // also close enough to const
  323. g_object_get_property(const_cast<::GObject *>(gobj_()), propname, &v);
  324. return detail::get_value<V>(&v);
  325. }
  326. template<typename V>
  327. V get_property(const gi::cstring_v propname) const
  328. {
  329. return get_property<V>(propname.c_str());
  330. }
  331. #ifdef GI_GOBJECT_PROPERTY_VALUE
  332. Value get_property(const gi::cstring_v propname) const
  333. {
  334. Value result;
  335. const gchar *name = propname.c_str();
  336. GValue *val = result.gobj_();
  337. g_object_getv(const_cast<::GObject *>(gobj_()), 1, &name, val);
  338. return result;
  339. }
  340. #endif
  341. ParamSpec find_property(
  342. const gi::cstring_v propname, bool _throw = false) const
  343. {
  344. GParamSpec *spec;
  345. if (g_type_is_a(gobj_type_(), G_TYPE_INTERFACE)) {
  346. // interface should be loaded if we have an instance here
  347. auto vtable = g_type_default_interface_peek(gobj_type_());
  348. spec = g_object_interface_find_property(vtable, propname.c_str());
  349. } else {
  350. spec = g_object_class_find_property(
  351. G_OBJECT_GET_CLASS(gobj_()), propname.c_str());
  352. }
  353. if (_throw && !spec)
  354. detail::try_throw(
  355. detail::unknown_property_error(gobj_type_(), propname.c_str()));
  356. return gi::wrap(spec, transfer_none);
  357. }
  358. gi::Collection<gi::DSpan, GParamSpec *, gi::transfer_container_t>
  359. list_properties() const
  360. {
  361. GParamSpec **specs;
  362. guint nspecs = 0;
  363. if (g_type_is_a(gobj_type_(), G_TYPE_INTERFACE)) {
  364. // interface should be loaded if we have an instance here
  365. auto vtable = g_type_default_interface_peek(gobj_type_());
  366. specs = g_object_interface_list_properties(vtable, &nspecs);
  367. } else {
  368. specs =
  369. g_object_class_list_properties(G_OBJECT_GET_CLASS(gobj_()), &nspecs);
  370. }
  371. return wrap_to<
  372. gi::Collection<gi::DSpan, GParamSpec *, gi::transfer_container_t>>(
  373. specs, nspecs, transfer_container);
  374. }
  375. // signal stuff
  376. private:
  377. template<typename F, typename Functor>
  378. gulong connect_data(
  379. const gi::cstring_v signal, Functor &&f, GConnectFlags flags)
  380. {
  381. // runtime signature check
  382. detail::signal_type<F>::check(gobj_type_(), signal);
  383. auto w = new detail::transform_signal_wrapper<F>(std::forward<Functor>(f));
  384. // mind gcc's -Wcast-function-type
  385. return g_signal_connect_data(gobj_(), signal.c_str(),
  386. (GCallback)&w->wrapper, w, (GClosureNotify)(GCallback)&w->destroy,
  387. flags);
  388. }
  389. public:
  390. template<typename F, typename Functor>
  391. gulong connect(const gi::cstring_v signal, Functor &&f)
  392. {
  393. return connect_data<F, Functor>(
  394. signal, std::forward<Functor>(f), (GConnectFlags)0);
  395. }
  396. template<typename F, typename Functor>
  397. gulong connect_after(const gi::cstring_v signal, Functor &&f)
  398. {
  399. return connect_data<F, Functor>(
  400. signal, std::forward<Functor>(f), G_CONNECT_AFTER);
  401. }
  402. // TODO the object variants ??
  403. // in case of unsupported signal signature
  404. // connect using a plain C signature without check/transform (wrap/unwrap)
  405. template<typename F, typename Functor>
  406. gulong connect_unchecked(
  407. const gi::cstring_v signal, Functor &&f, GConnectFlags flags = {})
  408. {
  409. auto w = new detail::callback_wrapper<F>(std::forward<Functor>(f));
  410. // mind gcc's -Wcast-function-type
  411. return g_signal_connect_data(gobj_(), signal.c_str(),
  412. (GCallback)&w->wrapper, w, (GClosureNotify)(GCallback)&w->destroy,
  413. flags);
  414. }
  415. void disconnect(gulong id) { g_signal_handler_disconnect(gobj_(), id); }
  416. // Args... may be explicitly specified or deduced
  417. // if deduced; arrange to decay/strip reference below
  418. // if not deduced; may need to considere specified type as-is
  419. template<typename R, bool DECAY = true, typename... Args>
  420. R emit(const gi::cstring_v signal, Args &&...args)
  421. {
  422. // static constexpr bool DECAY = true;
  423. guint id;
  424. GQuark detail;
  425. if (!g_signal_parse_name(signal.c_str(), gobj_type_(), &id, &detail, true))
  426. detail::try_throw(std::out_of_range(std::string("unknown signal name: ") +
  427. detail::make_string(signal.c_str())));
  428. detail::Value values[] = {detail::Value(*this),
  429. detail::signal_arg<Args, DECAY>::make(std::forward<Args>(args))...};
  430. detail::Value retv;
  431. retv.init<R>();
  432. g_signal_emitv(values, id, detail, &retv);
  433. return detail::get_value<R>(&retv);
  434. }
  435. void handler_block(gulong handler_id)
  436. {
  437. g_signal_handler_block(gobj_(), handler_id);
  438. }
  439. void handler_unblock(gulong handler_id)
  440. {
  441. g_signal_handler_unblock(gobj_(), handler_id);
  442. }
  443. bool handler_is_connected(gulong handler_id)
  444. {
  445. return g_signal_handler_is_connected(gobj_(), handler_id);
  446. }
  447. void stop_emission(guint id, GQuark detail)
  448. {
  449. g_signal_stop_emission(gobj_(), id, detail);
  450. }
  451. void stop_emission_by_name(const gi::cstring_v signal)
  452. {
  453. g_signal_stop_emission_by_name(gobj_(), signal.c_str());
  454. }
  455. };
  456. } // namespace GObject
  457. template<>
  458. struct declare_cpptype_of<::GObject>
  459. {
  460. typedef repository::GObject::Object type;
  461. };
  462. namespace GLib
  463. {
  464. // predefined
  465. typedef detail::callback<void(), gi::transfer_none_t> DestroyNotify;
  466. } // namespace GLib
  467. } // namespace repository
  468. // type safe signal connection
  469. template<typename T, typename Base = repository::GObject::Object>
  470. class signal_proxy;
  471. template<typename R, typename Instance, typename... Args, typename Base>
  472. class signal_proxy<R(Instance, Args...), Base>
  473. {
  474. protected:
  475. typedef R(CppSig)(Instance, Args...);
  476. Base object_;
  477. gi::cstring name_;
  478. public:
  479. typedef CppSig function_type;
  480. typedef detail::connectable<function_type> slot_type;
  481. signal_proxy(Base owner, gi::cstring name)
  482. : object_(owner), name_(std::move(name))
  483. {}
  484. template<typename Functor>
  485. gulong connect(Functor &&f)
  486. {
  487. return object_.template connect<CppSig>(name_, std::forward<Functor>(f));
  488. }
  489. template<typename Functor>
  490. gulong connect_after(Functor &&f)
  491. {
  492. return object_.template connect_after<CppSig>(
  493. name_, std::forward<Functor>(f));
  494. }
  495. R emit(Args... args)
  496. {
  497. return object_.template emit<R, false, Args...>(
  498. name_, std::forward<Args>(args)...);
  499. }
  500. template<typename Functor>
  501. slot_type slot(Functor &&f)
  502. {
  503. return slot_type(std::forward<Functor>(f));
  504. }
  505. };
  506. // type safe property setting
  507. template<typename T, typename Base = repository::GObject::Object>
  508. class property_proxy
  509. {
  510. typedef property_proxy self;
  511. typedef repository::GObject::ParamSpec ParamSpec;
  512. protected:
  513. Base object_;
  514. ParamSpec pspec_;
  515. public:
  516. property_proxy(Base owner, ParamSpec pspec) : object_(owner), pspec_(pspec) {}
  517. property_proxy(Base owner, const gi::cstring_v name)
  518. : property_proxy(owner, owner.find_property(name, true))
  519. {}
  520. void set(T v) { object_.set_property(pspec_, std::move(v)); }
  521. self &operator=(T v)
  522. {
  523. set(v);
  524. return *this;
  525. }
  526. T get() const
  527. {
  528. return object_.template get_property<T>(pspec_.gobj_()->name);
  529. }
  530. ParamSpec param_spec() const { return pspec_; }
  531. signal_proxy<void(Base, ParamSpec)> signal_notify() const
  532. {
  533. return signal_proxy<void(Base, ParamSpec)>(
  534. object_, gi::cstring_v("notify::") + gi::cstring_v(pspec_.name_()));
  535. }
  536. };
  537. template<typename T, typename Base = repository::GObject::Object>
  538. class property_proxy_read : private property_proxy<T, Base>
  539. {
  540. typedef property_proxy<T, Base> super;
  541. public:
  542. using super::get;
  543. using super::property_proxy;
  544. };
  545. template<typename T, typename Base = repository::GObject::Object>
  546. class property_proxy_write : private property_proxy<T, Base>
  547. {
  548. typedef property_proxy<T, Base> super;
  549. public:
  550. using super::property_proxy;
  551. using super::set;
  552. using super::operator=;
  553. };
  554. // interface (ptr) is wrapped the same way,
  555. // as it is essentially a ptr to implementing object
  556. // TODO use other intermediate base ??
  557. using InterfaceBase = repository::GObject::Object;
  558. namespace repository
  559. {
  560. namespace GObject
  561. {
  562. // connection helpers
  563. namespace internal
  564. {
  565. class SignalConnection : public detail::connection_impl
  566. {
  567. public:
  568. SignalConnection(gulong id, detail::connection_status s, Object object)
  569. : connection_impl(id, s), object_(object)
  570. {}
  571. void disconnect() { object_.disconnect(id_); }
  572. private:
  573. Object object_;
  574. };
  575. } // namespace internal
  576. using SignalConnection = detail::connection<internal::SignalConnection>;
  577. using SignalScopedConnection = detail::scoped_connection<SignalConnection>;
  578. } // namespace GObject
  579. } // namespace repository
  580. // connection callback type
  581. template<typename G>
  582. using slot = detail::connectable<G>;
  583. template<typename G>
  584. inline repository::GObject::SignalConnection
  585. make_connection(
  586. gulong id, const gi::slot<G> &s, repository::GObject::Object object)
  587. {
  588. using repository::GObject::SignalConnection;
  589. return SignalConnection(id, s.connection(), object);
  590. }
  591. } // namespace gi
  592. #endif // GI_OBJECT_HPP