/* $Id$ */ /* generate_extra_defs.cc * * Copyright (C) 2001 The Free Software Foundation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "generate_extra_defs.h" #include // 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 = 0; 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) { //Name and type: const std::string strName = g_param_spec_get_name(pParamSpec); const std::string strTypeName = G_PARAM_SPEC_TYPE_NAME(pParamSpec); const gchar* pchBlurb = g_param_spec_get_blurb(pParamSpec); std::string strDocs = (pchBlurb) ? pchBlurb : ""; // Quick hack to get rid of nested double quotes: std::replace(strDocs.begin(), strDocs.end(), '"', '\''); strResult += "(define-property " + strName + "\n"; strResult += " (of-object \"" + strObjectName + "\")\n"; strResult += " (prop-type \"" + strTypeName + "\")\n"; strResult += " (docs \"" + strDocs + "\")\n"; //Flags: GParamFlags flags = pParamSpec->flags; bool bReadable = (flags & G_PARAM_READABLE) == G_PARAM_READABLE; bool bWritable = (flags & G_PARAM_WRITABLE) == G_PARAM_WRITABLE; bool bConstructOnly = (flags & G_PARAM_CONSTRUCT_ONLY) == G_PARAM_CONSTRUCT_ONLY; //#t and #f aren't documented, but I guess that it's correct based on the example in the .defs spec. const std::string strTrue = "#t"; const std::string strFalse = "#f"; strResult += " (readable " + (bReadable ? strTrue : strFalse) + ")\n"; strResult += " (writable " + (bWritable ? strTrue : strFalse) + ")\n"; strResult += " (construct-only " + (bConstructOnly ? strTrue : strFalse) + ")\n"; strResult += ")\n\n"; //close (define-property } } g_free(ppParamSpec); return strResult; } bool gtype_is_a_pointer(GType gtype) { return (g_type_is_a(gtype, G_TYPE_OBJECT) || g_type_is_a(gtype, G_TYPE_BOXED)); } std::string get_type_name(GType gtype, GTypeIsAPointerFunc is_a_pointer_func) //Adds a * if necessary. { std::string strTypeName = g_type_name(gtype); if (is_a_pointer_func && is_a_pointer_func(gtype)) strTypeName += "*"; //Add * to show that it's a pointer. else if( g_type_is_a(gtype, G_TYPE_STRING) ) strTypeName = "gchar*"; //g_type_name() returns "gchararray". return strTypeName; } std::string get_type_name_parameter(GType gtype, GTypeIsAPointerFunc is_a_pointer_func) { std::string strTypeName = get_type_name(gtype, is_a_pointer_func); //All signal parameters that are registered as GTK_TYPE_STRING are actually const gchar*. if(strTypeName == "gchar*") strTypeName = "const-gchar*"; return strTypeName; } std::string get_type_name_signal(GType gtype, GTypeIsAPointerFunc is_a_pointer_func) { return get_type_name_parameter(gtype, is_a_pointer_func); //At the moment, it needs the same stuff. } std::string get_signals(GType gtype, GTypeIsAPointerFunc is_a_pointer_func) { std::string strResult; std::string strObjectName = g_type_name(gtype); gpointer gclass_ref = 0; gpointer ginterface_ref = 0; 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, 0, 0, GSignalFlags(0), 0, 0, 0, }; 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"; //When: { bool bWhenFirst = (signalQuery.signal_flags & G_SIGNAL_RUN_FIRST) == G_SIGNAL_RUN_FIRST; bool bWhenLast = (signalQuery.signal_flags & G_SIGNAL_RUN_LAST) == G_SIGNAL_RUN_LAST; std::string strWhen = "unknown"; if(bWhenFirst && bWhenLast) strWhen = "both"; else if(bWhenFirst) strWhen = "first"; else if(bWhenLast) strWhen = "last"; strResult += " (when \"" + strWhen + "\")\n"; } //Loop through the list of parameters: const GType* pParameters = signalQuery.param_types; if(pParameters) { strResult += " (parameters\n"; for(unsigned i = 0; i < signalQuery.n_params; i++) { GType typeParamMangled = pParameters[i]; //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", i); std::string strParamName = "p" + std::string(pchNum); g_free(pchNum); pchNum = 0; //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; } std::string get_defs(GType gtype, GTypeIsAPointerFunc is_a_pointer_func) { std::string strObjectName = g_type_name(gtype); std::string strDefs; if(G_TYPE_IS_OBJECT(gtype) || G_TYPE_IS_INTERFACE(gtype)) { strDefs = ";; From " + strObjectName + "\n\n"; strDefs += get_signals(gtype, is_a_pointer_func); strDefs += get_properties(gtype); } else strDefs = ";; " + strObjectName + " is neither a GObject nor a GInterface. Not checked for signals and properties.\n\n"; return strDefs; }