static VALUE interface_s_properties(int argc, VALUE* argv, VALUE self) { guint n_properties; GParamSpec** props; VALUE inherited_too; VALUE ary = rb_ary_new(); guint i; gpointer ginterface; GType gtype = CLASS2GTYPE(self); if (rb_scan_args(argc, argv, "01", &inherited_too) == 0) inherited_too = Qtrue; if (!G_TYPE_IS_INTERFACE(gtype)) rb_raise(rb_eTypeError, "%s isn't interface module", rb_class2name(self)); /* XXX: g_type_default_interface_ref(G_TYPE_INTERFACE) causes SEGV. */ if (gtype == G_TYPE_INTERFACE) return ary; ginterface = g_type_default_interface_ref(gtype); props = g_object_interface_list_properties(ginterface, &n_properties); for (i = 0; i < n_properties; i++){ if (RVAL2CBOOL(inherited_too) || GTYPE2CLASS(props[i]->owner_type) == self) rb_ary_push(ary, rb_str_new2(props[i]->name)); } g_free(props); g_type_default_interface_unref(ginterface); return ary; }
static VALUE interface_s_property(VALUE self, VALUE property_name) { gpointer ginterface; const char* name; GParamSpec* prop; VALUE result; GType gtype = CLASS2GTYPE(self); if (SYMBOL_P(property_name)) name = rb_id2name(SYM2ID(property_name)); else name = StringValuePtr(property_name); if (!G_TYPE_IS_INTERFACE(gtype)) rb_raise(rb_eTypeError, "%s isn't interface module", rb_class2name(self)); /* XXX: g_type_default_interface_ref(G_TYPE_INTERFACE) causes SEGV. */ if (gtype == G_TYPE_INTERFACE) { rb_raise(rb_const_get(mGLib, rb_intern("NoPropertyError")), "No such property: %s", name); } ginterface = g_type_default_interface_ref(gtype); prop = g_object_interface_find_property(ginterface, name); if (!prop){ g_type_default_interface_unref(ginterface); rb_raise(rb_const_get(mGLib, rb_intern("NoPropertyError")), "No such property: %s", name); } result = GOBJ2RVAL(prop); g_type_default_interface_unref(ginterface); return result; }
gpointer _g_type_struct_ref (GType the_type) { if (G_TYPE_IS_INTERFACE (the_type)) return g_type_default_interface_ref (the_type); else if (G_TYPE_IS_OBJECT (the_type)) return g_type_class_ref (the_type); else g_return_val_if_reached (NULL); }
static void test_dynamic_iface (void) { TestDynamicIfaceClass *dynamic_iface; test_module_new (module_register); /* Not loaded until we call ref for the first time */ dynamic_iface = g_type_default_interface_peek (TEST_TYPE_DYNAMIC_IFACE); g_assert (dynamic_iface == NULL); /* Ref loads */ dynamic_iface = g_type_default_interface_ref (TEST_TYPE_DYNAMIC_IFACE); g_assert (dynamic_iface_init); g_assert (dynamic_iface && dynamic_iface->val == 42); /* Peek then works */ dynamic_iface = g_type_default_interface_peek (TEST_TYPE_DYNAMIC_IFACE); g_assert (dynamic_iface && dynamic_iface->val == 42); /* Unref causes finalize */ g_type_default_interface_unref (dynamic_iface); #if 0 g_assert (!dynamic_iface_init); #endif /* Peek returns NULL */ dynamic_iface = g_type_default_interface_peek (TEST_TYPE_DYNAMIC_IFACE); #if 0 g_assert (dynamic_iface == NULL); #endif /* Ref reloads */ dynamic_iface = g_type_default_interface_ref (TEST_TYPE_DYNAMIC_IFACE); g_assert (dynamic_iface_init); g_assert (dynamic_iface && dynamic_iface->val == 42); /* And Unref causes finalize once more*/ g_type_default_interface_unref (dynamic_iface); #if 0 g_assert (!dynamic_iface_init); #endif }
bool gjs_define_interface_class(JSContext *context, JS::HandleObject in_object, GIInterfaceInfo *info, GType gtype, JS::MutableHandleObject constructor) { Interface *priv; const char *constructor_name; const char *ns; JS::RootedObject prototype(context); ns = gjs_get_names_from_gtype_and_gi_info(gtype, (GIBaseInfo *) info, &constructor_name); if (!gjs_init_class_dynamic(context, in_object, JS::NullPtr(), ns, constructor_name, &gjs_interface_class, gjs_interface_constructor, 0, /* props of prototype */ &gjs_interface_proto_props[0], /* funcs of prototype */ &gjs_interface_proto_funcs[0], /* props of constructor, MyConstructor.myprop */ NULL, /* funcs of constructor, MyConstructor.myfunc() */ NULL, &prototype, constructor)) { g_error("Can't init class %s", constructor_name); } GJS_INC_COUNTER(interface); priv = g_slice_new0(Interface); priv->info = info == NULL ? NULL : g_base_info_ref((GIBaseInfo *) info); priv->gtype = gtype; priv->vtable = (GTypeInterface *) g_type_default_interface_ref(gtype); JS_SetPrivate(prototype, priv); /* If we have no GIRepository information, then this interface was defined * from within GJS and therefore has no C static methods to be defined. */ if (priv->info) gjs_define_static_methods(context, constructor, priv->gtype, priv->info); JS::RootedObject gtype_obj(context, gjs_gtype_create_gtype_wrapper(context, priv->gtype)); JS_DefineProperty(context, constructor, "$gtype", gtype_obj, JSPROP_PERMANENT); return true; }
static VALUE interface_s_install_property(VALUE self, VALUE pspec_obj) { const RGObjClassInfo* cinfo = rbgobj_lookup_class(self); gpointer ginterface; GParamSpec* pspec; if (cinfo->klass != self) rb_raise(rb_eTypeError, "%s isn't registered class", rb_class2name(self)); pspec = G_PARAM_SPEC(RVAL2GOBJ(pspec_obj)); ginterface = g_type_default_interface_ref(cinfo->gtype); g_object_interface_install_property(ginterface, pspec); g_type_default_interface_unref(ginterface); /* FIXME: define accessor methods */ return Qnil; }
static void add_all_interfaces (GType iface_type, GPtrArray *type_structs) { GType *prereq; guint n_prereq; guint i; g_ptr_array_add (type_structs, g_type_default_interface_ref (iface_type)); prereq = g_type_interface_prerequisites (iface_type, &n_prereq); for (i = 0; i < n_prereq; ++i) { if (G_TYPE_IS_INTERFACE (prereq[i])) add_all_interfaces (prereq[i], type_structs); } g_free (prereq); }
static void test_static_iface (void) { TestStaticIfaceClass *static_iface; /* Not loaded until we call ref for the first time */ static_iface = g_type_default_interface_peek (TEST_TYPE_STATIC_IFACE); g_assert (static_iface == NULL); /* Ref loads */ static_iface = g_type_default_interface_ref (TEST_TYPE_STATIC_IFACE); g_assert (static_iface && static_iface->val == 42); /* Peek then works */ static_iface = g_type_default_interface_peek (TEST_TYPE_STATIC_IFACE); g_assert (static_iface && static_iface->val == 42); /* Unref does nothing */ g_type_default_interface_unref (static_iface); /* And peek still works */ static_iface = g_type_default_interface_peek (TEST_TYPE_STATIC_IFACE); g_assert (static_iface && static_iface->val == 42); }
std::string get_signals(GType gtype, GTypeIsAPointerFunc is_a_pointer_func) { std::string strResult; std::string strObjectName = g_type_name(gtype); gpointer gclass_ref = nullptr; gpointer ginterface_ref = nullptr; if (G_TYPE_IS_OBJECT(gtype)) gclass_ref = g_type_class_ref(gtype); // Ensures that class_init() is called. else if (G_TYPE_IS_INTERFACE(gtype)) ginterface_ref = g_type_default_interface_ref(gtype); // install signals. // Get the list of signals: guint iCount = 0; guint* pIDs = g_signal_list_ids(gtype, &iCount); // Loop through the list of signals: if (pIDs) { for (guint i = 0; i < iCount; i++) { guint signal_id = pIDs[i]; // Name: std::string strName = g_signal_name(signal_id); strResult += "(define-signal " + strName + "\n"; strResult += " (of-object \"" + strObjectName + "\")\n"; // Other information about the signal: GSignalQuery signalQuery = { 0, nullptr, 0, GSignalFlags(0), 0, 0, nullptr, }; g_signal_query(signal_id, &signalQuery); // Return type: std::string strReturnTypeName = get_type_name_signal(signalQuery.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE, is_a_pointer_func); // The type is mangled with a flag. Hacky. // bool bReturnTypeHasStaticScope = (signalQuery.return_type & G_SIGNAL_TYPE_STATIC_SCOPE) == // G_SIGNAL_TYPE_STATIC_SCOPE; strResult += " (return-type \"" + strReturnTypeName + "\")\n"; // Flags: std::string strFlags; add_signal_flag_if(strFlags, "Run First", signalQuery, G_SIGNAL_RUN_FIRST); add_signal_flag_if(strFlags, "Run Last", signalQuery, G_SIGNAL_RUN_LAST); add_signal_flag_if(strFlags, "Run Cleanup", signalQuery, G_SIGNAL_RUN_CLEANUP); add_signal_flag_if(strFlags, "No Recurse", signalQuery, G_SIGNAL_NO_RECURSE); add_signal_flag_if(strFlags, "Action", signalQuery, G_SIGNAL_ACTION); add_signal_flag_if(strFlags, "No Hooks", signalQuery, G_SIGNAL_NO_HOOKS); add_signal_flag_if(strFlags, "Must Collect", signalQuery, G_SIGNAL_MUST_COLLECT); strResult += " (flags \"" + strFlags + "\")\n"; if (signalQuery.signal_flags & G_SIGNAL_DETAILED) strResult += " (detailed #t)\n"; // Default: not detailed if (signalQuery.signal_flags & G_SIGNAL_DEPRECATED) strResult += " (deprecated #t)\n"; // Default: not deprecated // Loop through the list of parameters: const GType* pParameters = signalQuery.param_types; if (pParameters) { strResult += " (parameters\n"; for (unsigned j = 0; j < signalQuery.n_params; j++) { GType typeParamMangled = pParameters[j]; // Parameter name: // We can't get the real parameter name from the GObject system. It's not registered with // g_signal_new(). gchar* pchNum = g_strdup_printf("%d", j); std::string strParamName = "p" + std::string(pchNum); g_free(pchNum); pchNum = nullptr; // Just like above, for the return type: std::string strTypeName = get_type_name_signal(typeParamMangled & ~G_SIGNAL_TYPE_STATIC_SCOPE, is_a_pointer_func); // The type is mangled with a flag. Hacky. // bool bTypeHasStaticScope = (typeParamMangled & G_SIGNAL_TYPE_STATIC_SCOPE) == // G_SIGNAL_TYPE_STATIC_SCOPE; strResult += " '(\"" + strTypeName + "\" \"" + strParamName + "\")\n"; } strResult += " )\n"; // close (parameters } strResult += ")\n\n"; // close (define-signal } } g_free(pIDs); if (gclass_ref) g_type_class_unref(gclass_ref); // to match the g_type_class_ref() above. else if (ginterface_ref) g_type_default_interface_unref(ginterface_ref); // for interface ref above. return strResult; }
// Until the glib bug https://bugzilla.gnome.org/show_bug.cgi?id=465631 // is fixed, get_properties() must be called for a GObject before it's // called for a GInterface. std::string get_properties(GType gtype) { std::string strResult; std::string strObjectName = g_type_name(gtype); // Get the list of properties: GParamSpec** ppParamSpec = nullptr; guint iCount = 0; if (G_TYPE_IS_OBJECT(gtype)) { GObjectClass* pGClass = G_OBJECT_CLASS(g_type_class_ref(gtype)); ppParamSpec = g_object_class_list_properties(pGClass, &iCount); g_type_class_unref(pGClass); if (!ppParamSpec) { strResult += ";; Warning: g_object_class_list_properties() returned NULL for " + std::string(g_type_name(gtype)) + "\n"; } } else if (G_TYPE_IS_INTERFACE(gtype)) { gpointer pGInterface = g_type_default_interface_ref(gtype); if (pGInterface) { ppParamSpec = g_object_interface_list_properties(pGInterface, &iCount); g_type_default_interface_unref(pGInterface); if (!ppParamSpec) { strResult += ";; Warning: g_object_interface_list_properties() returned NULL for " + std::string(g_type_name(gtype)) + "\n"; } } else strResult += ";; Warning: g_type_default_interface_ref() returned NULL for " + std::string(g_type_name(gtype)) + "\n"; } // This extra check avoids an occasional crash if (!ppParamSpec) iCount = 0; for (guint i = 0; i < iCount; i++) { GParamSpec* pParamSpec = ppParamSpec[i]; // Generate the property if the specified gtype actually owns the property. // (Generally all properties, including any base classes' properties are // retrieved by g_object_interface_list_properties() for a given gtype. // The base classes' properties should not be generated). if (pParamSpec && pParamSpec->owner_type == gtype) { strResult += get_property_with_node_name(pParamSpec, strObjectName, "define-property"); } } g_free(ppParamSpec); return strResult; }
void rbgobj_define_property_accessors(VALUE klass) { GType gtype; GParamSpec** pspecs = NULL; guint i; GString* source; guint n_properties = 0; gtype = CLASS2GTYPE(klass); if (G_TYPE_IS_INTERFACE(gtype)){ #if GLIB_CHECK_VERSION(2,4,0) gpointer iface = g_type_default_interface_ref(gtype); pspecs = g_object_interface_list_properties(iface, &n_properties); g_type_default_interface_unref(iface); #endif } else { GObjectClass* oclass = G_OBJECT_CLASS(g_type_class_ref(gtype)); pspecs = g_object_class_list_properties(oclass, &n_properties); g_type_class_unref(oclass); } if (n_properties == 0) return; source = g_string_new(NULL); for (i = 0; i < n_properties; i++){ GParamSpec* pspec = pspecs[i]; char* buf; char* prop_name; char* p; if (pspec->owner_type != gtype) continue; buf = g_strdup(pspec->name); for (p = buf; *p; p++) if (*p == '-') *p = '_'; if (!strncmp(buf, "is_", 3)) prop_name = buf + 3; else prop_name = buf; if (g_hash_table_lookup(prop_exclude_list, prop_name)){ g_free(buf); continue; } if (pspec->flags & G_PARAM_READABLE){ g_string_append_printf( source, "def %s%s; get_property('%s'); end\n", prop_name, (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_BOOLEAN) ? "?" : "", pspec->name); } if (IS_FLAG(pspec->flags, G_PARAM_WRITABLE) && !IS_FLAG(pspec->flags, G_PARAM_CONSTRUCT_ONLY)){ g_string_append_printf(source, "def set_%s(val); set_property('%s', val); end\n", prop_name, pspec->name); #ifdef HAVE_NODE_ATTRASGN g_string_append_printf(source, "alias %s= set_%s\n", prop_name, prop_name); #else g_string_append_printf(source, "def %s=(val); set_property('%s', val); val; end\n", prop_name, pspec->name); #endif } g_free(buf); } if (source->len > 0) rb_funcall(klass, id_module_eval, 1, rb_str_new2(source->str)); g_string_free(source, TRUE); }