# High level gobject-introspection based GTK4/GTK3 bindings for the Nim programming language # nimpretty --maxLineLen:130 gen.nim # v 0.9.9 2022-OCT-28 # (c) S. Salewski 2018, 2019, 2020, 2021, 2022, 2023 # https://gnome.pages.gitlab.gnome.org/gobject-introspection/girepository/ # usefull for finding death code: # https://forum.nim-lang.org/t/5898 # https://wiki.gnome.org/Projects/GObjectIntrospection # https://developer.gnome.org/gi/stable/ # https://mail.gnome.org/archives/gtk-devel-list/2005-April/msg00095.html # https://ptomato.wordpress.com/2018/11/06/taking-out-the-garbage/ # /usr/share/gir-1.0/GLib-2.0.gir # you may also compare the currently unmaintained work of # https://github.com/jdmansour/nim-smartgi # This module itself is still based on the low level GTK 3.22 wrappers at # https://github.com/StefanSalewski/oldgtk3 # as those were created with c2nim and work for 32/64 bit and linux, windows and macos # Currently we intentionally do not free any resources in this generator script! # First goal was creating low level bindings similar to current oldgtk3. #XXX DONE # Then we added the high level wrapper similar as done in Nim's libui wrapper. #XXX Mostly DONE # What remains is carefully inspecting the generated code, adding special like list/array results # and of course a lot of testing. # Known gobject-introspection related issues: # - gFieldInfoGetSize() is always zero, so we have no bitfield support yet. # - ParamSpec is reported as object, but has no parent # not really a bug, gst has more gobjects without parent # - gBaseInfoGetName() is "" for g_iconv() #XXX fixed # - dirSep is wrong for unix -- that is an already reported gi bug # missing nullable flag for some functions, see https://discourse.gnome.org/t/missing-nullable-tag-as-in-gtk-css-section-get-file/2814 # - well there are more than 140 open issues about gobject introspection in gnome bugzilla :-( # This module is really ugly currently -- the first goal was to get a working gi solution # NOTE: Currently we support subclassing only for constructor functions like gtk_button_new() # CAUTION: some procs are advertised as constructor but do not construct new objects, # they just return existing ones as gdk_cursor_new_from_name() # {.warning[CStringConv]: off.} # does not work with older compilers # isRegisteredTypeInfo(info) was never used before v0.9.5, but may be useful! from os import `/`, paramCount import gir, gobject, glib import strutils import sequtils import streams import sets import bitops import tables import algorithm import std/editdistance import maxby from parseutils import skipUntil #from sugar import dup from combinatorics import combinations template isCallbackInfo(info: untyped): untyped = gBaseInfoGetType(info) == GIInfoType.Callback template isFunctionInfo(info: untyped): untyped = gBaseInfoGetType(info) == GIInfoType.Function template isTypeInfo(info: untyped): untyped = gBaseInfoGetType(info) == GIInfoType.Type #define GI_IS_TYPE_INFO(info) \ # (g_base_info_get_type((GIBaseInfo*)info) == GI_INFO_TYPE_TYPE) const WriteFields = false # starting with v0.5.3 we do not write the objectfields any more! libprag = "libprag" EM = "*" RecSep = "!" # Record separator for entries in gisup.nim, also defined in gimpl.nim UnnamedArrayCandidates = ["uint8", "int32", "uint32"] #UnnamedArrays = UnnamedArrayCandidates.mapIt(it & "Array") #NamedArrays = ["TargetEntry00Array", "PageRangeArray", "KeymapKeyArray"] #NamedArrayCandidates = NamedArrays.mapIt(it.replace("00Array").replace("Array")) StringArrayName = "fs469n23" # for seq -- cstringArray conversion StringArrayEntries = 256 # initial 16, but that was too small for VTE environGetenv(). Stack allocated pointer array -- replace by heap or global? keywords = """ addr and as asm bind block break case cast concept const continue converter defer discard distinct div do elif else end enum except export finally for from func if import in include interface is isnot iterator let macro method mixin mod nil not notin object of or out proc ptr raise ref return shl shr static template try tuple type using var when while xor yield """.split nims = """ int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 float float32 float64 pointer false true string char bool """.split import dynlib type AdwInit = proc (argc: ptr cint; argv: ptr ptr cstring) {.cdecl.} proc tryInitAdw(): LibHandle = # echo "Try to init gst" when defined(windows): const AdwLibName = "adwaita-1-0.dll" elif defined(macosx): const AdwLibName = "libadwaita-1.dylib" else: const AdwLibName = "libadwaita-1.so(|.0)" let adwLib = loadLibPattern(AdwLibName) # dlopen if adwLib != nil: let adwInit = cast[AdwInit](adwLib.symAddr("adw_init")) if adwInit != nil: adwInit(nil, nil) else: echo "Can't init adw library!" else: echo "Can't load adw library!" return adwLib # unloadLib(adwLib) type GstInit = proc (argc: ptr cint; argv: ptr ptr cstring) {.cdecl.} proc tryInitGst(): LibHandle = # echo "Try to init gst" when defined(windows): const GstLibName = "gstreamer-1.0-0.dll" elif defined(macosx): const GstLibName = "libgstreamer-1.0.dylib" else: const GstLibName = "libgstreamer-1.0.so(|.0)" let gstLib = loadLibPattern(GstLibName) # dlopen if gstLib != nil: let gstInit = cast[GstInit](gstLib.symAddr("gst_init")) if gstInit != nil: gstInit(nil, nil) else: echo "Can't init gst library!" else: echo "Can't load gst library!" return gstLib # unloadLib(gstLib) type Gtk3Init = proc (argc: ptr cint; argv: ptr ptr cstring) {.cdecl.} proc tryInitGtk3(): LibHandle = # echo "Try to init gtk3" when defined(windows): const Gtk3LibName = "libgtk-3-0.dll" elif defined(macosx): const Gtk3LibName = "libgtk-3.dylib" else: const Gtk3LibName = "libgtk-3.so(|.0)" let gtk3Lib = loadLibPattern(Gtk3LibName) # dlopen if gtk3Lib != nil: let gtk3Init = cast[Gtk3Init](gtk3Lib.symAddr("gtk_init")) if gtk3Init != nil: gtk3Init(nil, nil) else: echo "Can't init gtk3 library!" else: echo "Can't load gtk3 library!" return gtk3Lib type Gtk4Init = proc () {.cdecl.} proc tryInitGtk4(): LibHandle = # echo "Try to init gtk4" when defined(windows): const Gtk4LibName = "libgtk-4-0.dll" elif defined(macosx): const Gtk4LibName = "libgtk-4.dylib" else: const Gtk4LibName = "libgtk-4.so(|.0)" let gtk4Lib = loadLibPattern(Gtk4LibName) # dlopen if gtk4Lib != nil: let gtk4Init = cast[Gtk4Init](gtk4Lib.symAddr("gtk_init")) if gtk4Init != nil: gtk4Init() else: echo "Can't init gtk4 library!" else: echo "Can't load gtk4 library!" return gtk4Lib proc unCap(s: var string) = s[0] = s[0].toLowerAscii proc unCap(s: string): string = result = s result[0] = result[0].toLowerAscii proc unCaped(s: string): string = result = s result[0] = result[0].toLowerAscii proc firstPart(s: var string) = while s.len > 0 and s[^1].isLowerAscii: s.setLen(s.len - 1) assert(s.len > 1) s.setLen(s.len - 1) proc startsWith(s: string; x: varargs[string]): bool = for i in x: if s.startsWith(i): return true proc endsWith(s: string; x: varargs[string]): bool = for i in x: if s.endsWith(i): return true proc isplit(s: string; start: int): string = result = newStringOfCap(s.len * 2) var j = start for c in s: inc(j) result.add(c) if j > 70 and c == ';': j = 0 result.add("\n ") # hope that will work reliable proc cut(s: var StringStream; pos: int) = assert(pos >= 0 and pos <= s.getPosition) s.setPosition(pos) s.data.setLen(pos) s.setPosition(pos) proc myCamelToSnake(s: cstring): string = result.add(s[0].toLowerAscii) for i in 1 .. s.high: if s[i].isUpperAscii and not s[i - 1].isUpperAscii: result.add('_') result.add(s[i].toLowerAscii) proc mysnakeToCamel(s: cstring): string = var i, j: int result = newString(s.len) if s[i] == '_': inc(i) while true: if s[i] == '_' and (s[i + 1] == '\0' or s[i + 1] == '_'): inc(i) elif (s[i] == '_' or s[i] == '-') and s[i + 1].isLowerAscii and not s[i - 1].isUpperAscii: inc(i) result[j] = toUpperAscii(s[i]) inc(i) inc(j) else: result[j] = s[i] inc(i) inc(j) if s[i] == '\0': result.setLen(j) break if result[0] == '\0': # this may result, so we emit a dummy name as marker result = "QQQ" #assert(false) proc renumber(s: var string; i: int) = # only in use when WriteFields if s[^1].isDigit: s.insert($i, s.high) else: s.add($i) var moduleNamespace: string var defaultParameters: Table[string, string] var fixedProcNames: Table[string, string] var fixedDestroyNames: Table[string, string] var mangledNames: Table[string, string] var mangledTypes: Table[string, string] var allSyms: HashSet[string] var droppedSyms: HashSet[string] var privStr: HashSet[string] var processedFunctions: HashSet[string] var useTempProcessedFunctions: bool var tempProcessedFunctions: seq[string] var knownSyms: HashSet[string] var gdkKeys: Table[string, seq[string]] var provInt: Table[string, seq[string]] var interfaceProvider: Table[string, seq[string]] var priList: seq[string] var delayedMethods: seq[(GIBaseInfo, GIFunctionInfo)] var classList: seq[GIBaseInfo] var ct: CountTable[string] #var callerAlloc: HashSet[string] var xcallerAlloc: HashSet[string] var ISGTK3: bool var suppressType = false var suppressRaise = false var cairoProvidesRectangle = false # ugly fix for legacy Debian Buster, CairoRectangle was missing # fixedDestroyNames.add("gdk_window_create_similar_surface", "cairo.destroy") # fixedDestroyNames.add("gdk_window_create_similar_image_surface", "cairo.destroy") # fixedDestroyNames.add("gdk_cairo_region_create_from_surface", "cairo.destroy") # fixedDestroyNames.add("gdk_cairo_surface_create_from_pixbuf", "cairo.destroy") fixedProcNames["gst_video_color_matrix_from_iso"] = "colorMatrixFromIso" fixedProcNames["gst_video_color_primaries_from_iso"] = "colorPrimariesFromIso" fixedProcNames["gst_video_transfer_function_from_iso"] = "transferFunctionFromIso" fixedProcNames["gtk_popover_menu_new_from_model"] = "newPopoverMenu" # FromModel" fixedProcNames["gtk_button_new_with_label"] = "newButton" fixedProcNames["gtk_check_button_new_with_label"] = "newCheckButton" fixedProcNames["gtk_toggle_button_new_with_label"] = "newToggleButton" fixedProcNames["gtk_link_button_new_with_label"] = "newLinkButton" fixedProcNames["pango_font_description_from_string"] = "newFontDescription" fixedProcNames["pango_language_from_string"] = "languageFromString" fixedProcNames["atk_role_register"] = "registerAtkRole" fixedProcNames["atk_state_type_register"] = "registerStateType" fixedProcNames["atk_relation_type_register"] = "registerRelationType" fixedProcNames["atk_text_attribute_register"] = "registerTextAttribute" fixedProcNames["atk_role_for_name"] = "roleForName" fixedProcNames["atk_state_type_for_name"] = "stateTypeForName" fixedProcNames["atk_relation_type_for_name"] = "relationTypeForName" fixedProcNames["atk_text_attribute_for_name"] = "textAttributeForName" fixedProcNames["gtk_settings_get_for_screen"] = "getSettingsForScreen" fixedProcNames["gtk_icon_theme_get_for_screen"] = "getIconThemeForScreen" fixedProcNames["gtk_requisition_new"] = "newRequisition" fixedProcNames["gtk_text_attributes_new"] = "newTextAttributes" fixedProcNames["pango_script_for_unichar"] = "scriptForUnichar" fixedProcNames["pango_bidi_type_for_unichar"] = "bidiTypeForUnichar" fixedProcNames["gsk_shadow_node_get_child"] = "shadowNodeGetChild" fixedProcNames["gsk_transform_node_get_child"] = "transformNodeGetChild" fixedProcNames["gtk_settings_get_for_display"] = "getSettingsForDisplay" fixedProcNames["gtk_icon_theme_get_for_display"] = "getIconThemeForDisplay" fixedProcNames["gst_element_factory_find"] = "findElementFactory" fixedProcNames["gtk_shortcut_action_parse_string"] = "shortcutActionParseString" fixedProcNames["gtk_shortcut_trigger_parse_string"] = "shortcutTriggerParseString" fixedProcNames["g_main_context_default"] = "defaultMainContext" fixedProcNames["gst_value_list_init"] = "listInit" # or initList ? fixedProcNames["gst_value_array_init"] = "arrayInit" # or initArray ? fixedProcNames["gdk_gl_context_get_current"] = "getCurrentGLContext" fixedProcNames["gdk_visual_get_best"] = "getBestVisual" fixedProcNames["gdk_visual_get_best_depth"] = "getBestDepth" fixedProcNames["gdk_visual_get_system"] = "getSystemVisual" fixedProcNames["gdk_visual_get_best_type"] = "getBestType" fixedProcNames["gdk_pixbuf_get_formats"] = "getPixbufFormats" fixedProcNames["gst_gl_base_memory_init_once"] = "baseMemoryInitOnce" fixedProcNames["gst_gl_renderbuffer_init_once"] = "renderbufferInitOnce" fixedProcNames["gst_gl_buffer_init_once"] = "bufferInitOnce" fixedProcNames["gst_gl_memory_init_once"] = "memoryInitOnce" fixedProcNames["gst_gl_memory_pbo_init_once"] = "memoryPboInitOnce" fixedProcNames["g_memory_monitor_dup_default"] = "dupDefaultMemoryMonitor" fixedProcNames["g_power_profile_monitor_dup_default"] = "dupDefaultPowerProfileMonitor" defaultParameters["gtk_window_new"] = "`type` WindowType WindowType.toplevel" defaultParameters["gtk_application_new"] = "flags gio.ApplicationFlags {}" defaultParameters["gtk_builder_new_from_string"] = "length int64 -1" defaultParameters["gtk_box_new"] = "spacing int 0" defaultParameters["gtk_grid_attach"] = "width int 1|height int 1" defaultParameters["gtk_adjustment_new"] = "pageSize cdouble 1.0" defaultParameters["pango_layout_set_text"] = "length int -1" # proc pango_layout_set_text(self: ptr Layout00; text: cstring; length: int32) for i in keywords: mangledNames[i] = '`' & i & '`' mangledNames["object"] = "obj" mangledNames["CSET_A_2_Z"] = "CSET_A_2_Z_U" mangledNames["CSET_a_2_z"] = "CSET_a_2_z_L" mangledNames["2big"] = "tooBig" mangledNames["2buttonPress"] = "twoButtonPress" mangledNames["3buttonPress"] = "threeButtonPress" mangledNames["result"] = "resu" mangledNames["3d"] = "d3" mangledNames["2d"] = "d2" mangledNames["2dAffine"] = "d2Affine" mangledNames["2dTranslate"] = "d2Translate" mangledNames["true"] = "true1" mangledNames["false"] = "false0" const someEvent: HashSet[string] = """" EventAny EventKey EventButton EventTouch EventScroll EventMotion EventExpose EventVisibility EventCrossing EventFocus EventConfigure EventProperty EventSelection EventDND EventProximity EventWindowState EventSetting EventOwnerChange EventGrabBroken EventTouchpadSwipe EventTouchpadPinch EventPadButton EventPadAxis EventPadGroupMode """.split.toHashSet proc fixedModName(s: string): string = result = s if not ISGTK3 and (s == "gdk" or s == "gtk" or s == "gdkx11"): result &= "4" if not ISGTK3 and (s == "javascriptcore" or s == "webkit2" or s == "webkit2webextension"): result &= "5" if not ISGTK3 and (s == "gtksource"): result &= "5" if not ISGTK3 and (s == "libsoup"): result &= "3" proc gBaseInfoGetQualifiedName(info: GIBaseInfo; modPrefix: bool = false): string = if modPrefix: result = ($gBaseInfoGetNamespace(info)).toLowerAscii.fixedModName & "." & $(gir.gBaseInfoGetName(info)) if result == "gio.Application": result = "gio.GApplication" if result == "gio.File": result = "gio.GFile" else: result = $(gir.gBaseInfoGetName(info)) let h = $(gir.gBaseInfoGetNamespace(info)) if h == "Gio" and result == "Application": result = "GApplication" if h == "Gio" and result == "File": result = "GFile" proc gBaseInfoGetName(info: GIBaseInfo): string = result = $(gir.gBaseInfoGetName(info)) let h = $(gir.gBaseInfoGetNamespace(info)) if h == "Gio" and result == "Application": result = "GApplication" if h == "Gio" and result == "File": result = "GFile" proc mangleName(s: cstring): string = result = mysnakeToCamel(s) result = mangledNames.getOrDefault(result, result) if result == "``": # assert(false) result = "xxx" # XXX mangledTypes["gint8"] = "int8" mangledTypes["gint16"] = "int16" mangledTypes["gint32"] = "int32" mangledTypes["gint64"] = "int64" mangledTypes["guint8"] = "uint8" mangledTypes["guint16"] = "uint16" mangledTypes["guint32"] = "uint32" mangledTypes["guint64"] = "uint64" mangledTypes["gfloat"] = "cfloat" mangledTypes["gdouble"] = "cdouble" mangledTypes["ptr void"] = "pointer" mangledTypes["ptr filename"] = "cstring" mangledTypes["ptr error"] = "ptr glib.Error" mangledTypes["ptr ghash"] = "ptr HashTable00" mangledTypes["ptr glist"] = "ptr pointer" mangledTypes["ptr gslist"] = "ptr pointer" mangledTypes["ptr utf8"] = "cstring" #utf8StringArrays.incl("g_strv_length") # bugs in GIR files # TODO needs investigation #utf8StringArrays.incl("g_strfreev") #utf8StringArrays.incl("g_option_context_add_main_entries") # wrong, but not a string array #utf8StringArrays.incl("g_option_group_add_entries") #utf8StringArrays.incl("g_strjoinv") # two cstrings! # utf8StringArrays.incl("g_strv_contains") # two cstrings! droppedSyms.incl("MININT8") droppedSyms.incl("MININT16") droppedSyms.incl("MININT32") droppedSyms.incl("MININT64") # we may have to add digits to avoid name conflicts due to inheritance privStr.incl("privat") privStr.incl("priv") privStr.incl("padding") privStr.incl("pad") privStr.incl("unused") privStr.incl("privateData") # These objects are plain structs like GtkTextIter containing only fundamental data types like uint32. # They are generally allocated on the stack, so there is no alloc or free function offered by gtk. # If all these conditions are met, then we do not need a proxy object. Caution, some objects like # TextAttribute has bitfields, which is difficult to map to Nim. Watch for cstrings too! # For these objects we have to always write the fields. These names are found manually! const manCallerAlloc = """ gobject.Value gobject.ValueDataUnion atk.Rectangle pango.Color gtk.PageRange gdk.KeymapKey glib.Error glib.MarkupParser glib.TimeVal gtk.TextIter gdk.Rectangle gobject.SignalQuery gobject.TypeQuery gtk.TreeIter gtk.StockItem glib.String rsvg.PositionData rsvg.DimensionData gdk.Color gdk.Geometry gtk.Border atk.TextRectangle gdk.RGBA pango.Rectangle gtk.Requisition graphene.Size graphene.Point graphene.Point3D graphene.Rect graphene.Box graphene.Sphere graphene.Vec2 graphene.Vec3 graphene.Vec4 graphene.Quaternion graphene.Quad graphene.Matrix graphene.Plane graphene.Ray graphene.Euler cairo.Rectangle cairo.RectangleInt gsk.RoundedRect glib.Mutex glib.Cond gdk.ToplevelSize pango.GlyphInfo pango.GlyphVisAttr pango.GlyphGeometry pango.AttrIterator gsk.ColorStop gsk.Shadow gtk.BitsetIter gdk.TimeCoord gtk.IMContextInfo glib.StatBuf glib.Once graphene.Simd4X4F glib.RecMutex gdk.Point gst.PollFD gtksource.RegionIter gio.OutputVector gst.TimedValue glib.DebugKey glib.DoubleIEEE754 gtk.BindingArg gtk.PadActionEntry glib.FloatIEEE754 gst.StaticCaps gobject.WeakRef glib.SequenceIter rsvg.Length gtk.TargetPair gtk.RequestedSize gtk.TableChild glib.Dir glib.LogField glib.Data glib.OptionEntry gobject.EnumValue glib.PollFD gobject.FlagsClass gtk.RecentFilterInfo gobject.TypeInfo gtk.FileFilterInfo rsvg.Rectangle gtk.BindingSignal gtk.RcProperty glib.RWLock gio.DBusErrorEntry gio.IOSchedulerJob gio.FileAttributeInfo glib.HashTableIter gtk.AccelKey gobject.ObjectConstructParam gio.StaticResource gobject.TypeCValue gtk.SettingsValue gobject.FlagsValue gobject.EnumClass gtk.RecentData glib.SList glib.List nice.Address gst.MapInfo gstvideo.VideoAlignment gstvideo.VideoRectangle gstrtsp.RTSPRange gstrtsp.RTSPTimeRange gstrtsp.RTSPTime gstrtsp.RTSPTime2 gtk.CssLocation gstvideo.VideoFrame gstvideo.VideoMeta gstvideo.VideoFormatInfo gstvideo.VideoMasteringDisplayInfo gstvideo.VideoCaptionMeta gstvideo.VideoCropMeta gstvideo.VideoTimeCodeConfig gstvideo.VideoContentLightLevel gstvideo.VideoAncillary gstvideo.VideoColorimetry gstvideo.VideoMetaTransform gstvideo.VideoResampler gstsdp.MIKEYEncryptInfo gstsdp.MIKEYPayloadKEMAC gstsdp.SDPAttribute gstsdp.MIKEYPayloadSP gstsdp.MIKEYPayloadRAND gstsdp.MIKEYPayloadKeyData gstsdp.MIKEYPayloadPKE gstrtp.RTCPPacket gstrtp.RTCPBuffer gstrtp.RTPBuffer gstcheck.StreamConsistency gstcheck.HarnessThread gstcheck.CheckABIStruct gstcheck.Harness """ const autoCallerAlloc = """ """ const noCallerAlloc = """ glib.SourceCallbackFuncs xlib.XEvent glib.TokenValue gobject.ObjectClass xlib.Display gst.ReferenceTimestampMeta gst.BufferPoolAcquireParams glib.IOFuncs glib.MemVTable gst.ParamSpecArray gst.MetaTransformCopy gst.PluginDesc gio.InputVector pango.Analysis gio.IOExtensionPoint gst.CustomMeta gio.ActionEntry gtk.ActionEntry xlib.XConfigureEvent gst.PadProbeInfo glib.HookList gobject.TypeValueTable glib.Node gst.DebugMessage gst.ParentBufferMeta fontconfig.CharSet freetype2.Library gtk.TextBTree xlib.Screen gst.ProtectionMeta gobject.ClosureNotifyData gmodule.Module xlib.XFontStruct xlib.Visual graphene.Simd4F glib.Scanner gtk.ThemeEngine xlib.XVisualInfo glib.Array gtk.BindingSet xlib.XTrapezoid gtk.LabelSelectionInfo xlib.XImage gtk.TableRowCol freetype2.Face atk.Attribute gst.ValueTable glib.TestSuite gtk.TextAppearance gtk.RadioActionEntry gtk.BindingEntry gobject.Parameter glib.SourceFuncs gst.TypeFind atk.Implementor glib.TestCase glib.Timer fontconfig.Pattern freetype2.Bitmap gobject.TypePluginClass atk.KeyEventStruct glib.TrashStack gobject.TypeFundamentalInfo gobject.InterfaceInfo gobject.CClosure gtk.WindowGeometryInfo gtk.AccelGroupEntry gtk.FixedChild xlib.XEvent atk.PropertyValues gobject.TypeInterface atk.ObjectClass glib.TokenValue gst.ParamSpecFraction atk.TextRange xlib.XWindowAttributes gtk.RcContext gtk.ToggleActionEntry gst.FormatDefinition gdk.WindowRedirect gobject.SignalInvocationHint gdk.WindowAttr glib.TestConfig gst.StaticPadTemplate glib.ScannerConfig gobject.ParamSpecTypeInfo gobject.ParamSpecPool gtk.BuildableParseContext gtk.CssStyleChange gtk.BuildableParser gst.ClockEntry gio.IOExtension gio.IOStreamAdapter gio.DBusSubtreeVTable gio.DBusInterfaceVTable vte.CharAttributes gst.MetaInfo gtk.Clipboard gdk.DrawingContext gio.UnixMountEntry pango.AttrClass glib.PtrArray gobject.TypeInstance nice.PseudoTcpCallbacks gst.ObjectClass pango.AttrColor pango.AttrSize pango.AttrShape pango.AttrFontFeatures pango.AttrFontDesc pango.AttrFloat pango.Attribute pango.AttrString pango.AttrLanguage pango.AttrInt pango.LogAttr pango.Language pango.Map pango.MapEntry pango.IncludedModule pango.EngineInfo pango.EngineScriptInfo nice.InputMessage nice.OutputMessage gio.InputMessage gio.OutputMessage gstvideo.VideoTimeCodeMeta gstvideo.VideoGLTextureUploadMeta gstvideo.VideoAFDMeta gstvideo.VideoOverlayCompositionMeta gstvideo.VideoRegionOfInterestMeta gstvideo.VideoAffineTransformationMeta gstvideo.VideoColorPrimariesInfo gstmpegts.T2DeliverySystemCellExtension gstmpegts.SatelliteDeliverySystemDescriptor gstmpegts.AtscEITEvent gstmpegts.AtscStringSegment gstmpegts.AtscETT gstmpegts.BAT gstmpegts.EIT gstmpegts.DvbMultilingualNetworkNameItem gstmpegts.ISO639LanguageDescriptor gstmpegts.LogicalChannelDescriptor gstmpegts.BATStream gstmpegts.AtscVCT gstmpegts.DVBLinkageEvent gstmpegts.T2DeliverySystemCell gstmpegts.TOT gstmpegts.ExtendedEventItem gstmpegts.ComponentDescriptor gstmpegts.AtscMultString gstmpegts.DVBLinkageMobileHandOver gstmpegts.TerrestrialDeliverySystemDescriptor gstsdp.SDPBandwidth gstsdp.SDPAttribute gstsdp.SDPConnection gstsdp.MIKEYPayloadSPParam gstsdp.SDPZone gstsdp.SDPTime gstsdp.MIKEYMapSRTP gstsdp.SDPOrigin gstsdp.SDPKey gstrtp.RTPPayloadInfo gstrtp.RTPSourceMeta soup.MessageHeadersIter soup.Range soup.Connection soup.MessageQueueItem soup.MessageQueue gstgl.GLMemory gstgl.GLFuncs gstgl.GLRenderbuffer gstgl.GLSyncMeta gstgl.GLBuffer gstgl.GLMemoryPBO gstsdp.MIKEYDecryptInfo gstsdp.MIKEYPayloadT javascriptcore.ClassVTable gstaudio.AudioRingBufferSpec gstaudio.AudioDownmixMeta gstaudio.AudioCdSrcTrack gstaudio.AudioClippingMeta gstaudio.AudioMeta gstaudio.AudioBuffer gstaudio.AudioSinkClassExtension gstaudio.AudioFormatInfo gdkpixbuf.PixbufModulePattern gdkpixbuf.PixbufModule glib.TreeNode glib.UriParamsIter gstvideo.VideoBarMeta gstvideo.VideoMasteringDisplayInfoCoordinates gstnet.NetControlMessageMeta gstnet.NetAddressMeta gstbase.CollectData gstrtsp.RTSPWatchFuncs gstcheck.CheckLogFilter gtk.PrintBackend gsk.ParseLocation """" # some structs like glib.TreeNode are hard, as some functions returns pointers to that struct, and still we need field access! # same for gtk.PrintBackend var callerAlloc = (manCallerAlloc & autoCallerAlloc).split.toHashSet #var callerAlloc = (autoCallerAlloc).split.toHashSet for s in noCallerAlloc.split: callerAlloc.excl(s) type UndefEx = object of CatchableError proc mangleType(s: cstring): string = result = mangleName(s) result = mangledTypes.getOrDefault(result, result) if allSyms.contains(result) and not knownSyms.contains(result): if not suppressRaise: priList.add(result) raise newException(UndefEx, "forward declaration") else: echo "!!!", result var output: StringStream var supmod3: StringStream var supmod4: StringStream var methodBuffer: StringStream var signalBuffer: StringStream proc isString(t: GITypeInfo): bool = let tag = gTypeInfoGetTag(t) tag == GITypeTag.UTF8 or tag == GITypeTag.FILENAME type GenRecRes = enum none cstrA intA0 glist gslist namedAX intAX type RecResFlag = enum array zeroTerminated namedA unamedA cstringA RecResFlags = set[RecResFlag] type RecRes = tuple name: string res: GenRecRes childName: string infoType: GIInfoType namePlain: string namePlainNS: string name00: string name00NS: string flags: RecResFlags optOut: bool type GPars = tuple plist: string arglist: string replist: TableRef[string, (string, RecRes)] arrLex: string blex: string tempRes: string tempResFree: string implRef: string tmpoutgobjectarg: string outgobjectargname: string outgobjectargisoptional: bool outgobjectargmaybenull: bool proc genPars(info: GICallableInfo; genProxy = false; binfo: GIBaseInfo = nil; genArrayMark = false; tryOut2Ret: bool = false; modPrefix: bool = false): GPars proc fixedgTypeInfoIsPointer(t: GITypeInfo): bool = var p = gTypeInfoIsPointer(t) if not p: let tag = gTypeInfoGetTag(t) if tag == GITypeTag.INTERFACE: let iface = gTypeInfoGetInterface(t) if gBaseInfoGetNamespace(iface) == "freetype2" and gBaseInfoGetName(iface) == "Face": p = true # see issue https://discourse.gnome.org/t/the-gintro-nim-bindings-do-not-compile-with-latest-harfbuzz-4-4-1/10408 return p # recursive investigate that type -- resolve Arrays and Interfaces proc newGenRec(t: GITypeInfo; genProxy = false): RecRes = result[1] = GenRecRes.none result[3] = GIInfoType.INVALID var rawmark = "" var cAlloc = false var newrawmark = "" var proxyResult = false var p = fixedgTypeInfoIsPointer(t) let tag = gTypeInfoGetTag(t) if tag == GITypeTag.GLIST: let arrayType = gTypeInfoGetParamType(t, 0) let atag = gTypeInfoGetTag(arrayType) # INTERFACE or UTF8 if atag == GITypeTag.INTERFACE: let aface = gTypeInfoGetInterface(arrayType) result[3] = gBaseInfoGetType(aface) var rus = newGenRec(arrayType, genProxy = true) var child = rus.namePlain # [0] child = mangleType(mangleName(child)) result[0] = "ptr glib.List" result[1] = glist result[2] = child result.namePlain = result[0] result.namePlainNS = rus.namePlainNS # does not work result.namePlainNS = result[0] # this is the old one, which is not really correct but works result.name00 = result[0] result.name00NS = rus.name00NS return if tag == GITypeTag.GSLIST: let arrayType = gTypeInfoGetParamType(t, 0) let atag = gTypeInfoGetTag(arrayType) # INTERFACE or UTF8 if atag == GITypeTag.INTERFACE: let aface = gTypeInfoGetInterface(arrayType) result[3] = gBaseInfoGetType(aface) var rus = newGenRec(arrayType, genProxy = true) #var child = newGenRec(arrayType, genProxy = true).namePlain # [0] var child = rus.namePlain child = mangleType(mangleName(child)) result[0] = "ptr glib.SList" result[1] = gslist result[2] = child result.namePlain = result[0] result.namePlainNS = rus.namePlainNS # does not work result.namePlainNS = result[0] result.name00 = result[0] #result.name00NS = result[0] # TODO as above! result.name00NS = rus.name00NS return if tag == GITypeTag.ARRAY: result.flags.incl(RecResFlag.array) let toa = gTypeInfoGetArrayType(t) # type of array if toa == GIArrayType.ARRAY: result[0] = "GArray00" elif toa == GIArrayType.PTR_ARRAY: result[0] = "PtrArray00" elif toa == GIArrayType.BYTE_ARRAY: result[0] = "ByteArray00" elif toa == GIArrayType.C: let arrayType = gTypeInfoGetParamType(t, 0) let arrayFixedSize = gTypeInfoGetArrayFixedSize(t) var rus = newGenRec(arrayType) var child = rus.name00 # [0] child = mangleType(mangleName(child)) if arrayFixedSize != -1: result[0] = "array[$1, $2]" % [$arrayFixedSize, child] else: result[0] = "ptr " & child result.namePlain = result[0] result.namePlainNS = result[0] result.name00 = result[0] result.name00NS = "ptr " & rus.name00NS # "ptr " & fixedModName(ns) & '.' & #echo result.name00NS #assert result.name00NS.find('.') > 0 if gTypeInfoIsZeroTerminated(t): result.flags.incl(RecResFlag.zeroTerminated) result[1] = intA0 if child in UnnamedArrayCandidates: result[1] = intA0 # yes we need this # but is wrong, see g_base64_decode if not gTypeInfoIsZeroTerminated(t): result[1] = intAX result.flags.incl(RecResFlag.unamedA) if child in ["TargetEntry00", "PageRange", "KeymapKey"]: result.flags.incl(RecResFlag.namedA) if result[0] == "ptr cstring": result.flags.incl(RecResFlag.cstringA) return elif tag == GITypeTag.INTERFACE: let iface = gTypeInfoGetInterface(t) var ns = ($gBaseInfoGetNamespace(iface)).toLowerAscii if gBaseInfoGetType(iface) == GIInfoType.CALLBACK: if gBaseInfoGetName(iface)[0].isLowerAscii: result[0] = "proc" & genPars(iface)[0] & " {.cdecl.}" else: result[0] = mangleName(gBaseInfoGetName(iface)) else: result[0] = mangleName($gBaseInfoGetName(iface)) cAlloc = callerAlloc.contains(ns & '.' & result[0]) if gBaseInfoGetType(iface) in {GIInfoType.INTERFACE, Object, STRUCT, UNION} and not callerAlloc.contains(ns & '.' & result[0]): newrawmark = "00" if gBaseInfoGetType(iface) in {GIInfoType.INTERFACE, Object, STRUCT, UNION}: proxyResult = genProxy if not (genProxy or callerAlloc.contains(ns & '.' & result[0])): rawmark = "00" result.namePlainNS = fixedModName(ns) & '.' & result[0] result.name00NS = result.namePlainNS if ns != moduleNamespace: #fullQualified or ns != moduleNamespace: result[0] = fixedModName(ns) & '.' & result[0] else: result[0] = $gTypeTagToString(tag) result[0] = mangleType(result[0]) result.namePlain = result[0] if result.namePlainNS.len == 0: result.namePlainNS = result.namePlain result.name00NS = result.namePlainNS if p and newrawmark.len == 0 and not cAlloc: result.namePlain = "ptr " & result.namePlain result.namePlainNS = "ptr " & result.namePlainNS result.namePlain = mangleType(result.namePlain) result.namePlainNS = mangleType(result.namePlainNS) result.name00 = result[0] # & newrawmark if p: result.name00 = "ptr " & result.name00 result.name00 = mangleType(result.name00) result.name00 = result.name00 & newrawmark if p: result.name00NS = "ptr " & result.name00NS result.name00NS = mangleType(result.name00NS) result.name00NS = result.name00NS & newrawmark if p and (not proxyResult): result[0] = "ptr " & result[0] result[0] = mangleType(result[0]) & rawmark proc modPrefix(t: GITypeInfo; sym: string; full = true): string = if sym in ["gtk_renderer_cell_accessible_new", "gtk_mount_operation_new", "gtk_notebook_page_accessible_new"]: # return fixedModName("gtk") & "." #if sym == "gtk_mount_operation_new": # return fixedModName("gtk") & "." #if sym == "gtk_notebook_page_accessible_new": return fixedModName("gtk") & "." if sym in ["gtk_source_view_new", "gtk_source_view_new_with_buffer", "gtk_source_map_new", "gtk_source_style_scheme_chooser_widget_new", "gtk_source_style_scheme_chooser_button_new", "gtk_source_tag_new"]: return fixedModName("gtksource") & "." if full: result = fixedModName(moduleNamespace) & "." let tag = gTypeInfoGetTag(t) if tag == GITypeTag.INTERFACE: let iface = gTypeInfoGetInterface(t) assert(gBaseInfoGetType(iface) != GIInfoType.CALLBACK) var ns = ($gBaseInfoGetNamespace(iface)).toLowerAscii if ns != moduleNamespace: result = fixedModName(ns) & "." proc isProxyCandidate(t: GITypeInfo): bool = let tag = gTypeInfoGetTag(t) if tag == GITypeTag.INTERFACE: let iface = gTypeInfoGetInterface(t) let ns = ($gBaseInfoGetNamespace(iface)).toLowerAscii if callerAlloc.contains(ns & '.' & $gBaseInfoGetName(iface)): return false result = gBaseInfoGetType(iface) in {GIInfoType.INTERFACE, OBJECT, STRUCT, UNION} proc needProxyProc(info: GICallableInfo): bool = if gCallableInfoIsMethod(info): return true if manglename(gBaseInfoGetName(info)) in ["free", "unref"]: # we need this for finalizerFree() currently return true let m = gCallableInfoGetNArgs(info) - 1 for j in 0.cint .. m: let arg = gCallableInfoGetArg(info, j) let t = gArgInfoGetType(arg) if isProxyCandidate(t): return true var ret = gCallableInfoGetReturnType(info) assert(ret != nil) if isFunctionInfo(info): if (gFunctionInfoGetFlags(info).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) != 0: let h = gBaseInfoGetContainer(info) if gBaseInfoGetType(h) == GIInfoType.OBJECT: return true return isProxyCandidate(ret) proc needTypeConv(str: string; r: RecRes): bool = if str in "uint32 int32 cstring gboolean".split: return true if RecResFlag.array in r.flags: var s = str s.removeSuffix("Array") s.removePrefix("ptr ") if s in "uint32 int32 cstring uint8 TargetEntry00 KeymapKey PageRange".split: return true proc doTypeConv(str: string; r: RecRes): string = if RecResFlag.array in r.flags: var s = str s.removePrefix("ptr ") s.removeSuffix("Array") result = case s of "cstring": "seq[string]" of "int32": "seq[int32]" of "uint32": "seq[uint32]" of "uint8": "seq[uint8]" of "TargetEntry00": "seq[TargetEntry]" of "KeymapKey": "seq[KeymapKey]" of "PageRange": "seq[PageRange]" else: "" else: result = case str of "uint32": "int" of "int32": "int" of "cstring": "string" of "gboolean": "bool" else: "" proc doCt3nt(str: string; r: RecRes): string = if RecResFlag.array in r.flags: var s = str s.removeSuffix("Array") s.removePrefix("ptr ") result = case s of "cstring": "cstringArrayToSeq" of "TargetEntry00": "targetEntryArrayToSeq" of "KeymapKey": "keymapKeyArrayToSeq" of "PageRange": "pageRangeArrayToSeq" else: "" else: result = case str of "cstring": "$" of "gboolean": "toBool" else: "" if result.len == 0: result = doTypeConv(str, r) if result.len == 0: result = str proc fixedName(s: string): string = if s.startsWith("Ptr "): result = s.replace("Ptr ") result = result.capitalizeAscii & "Array" else: return s proc fixedName2(s: string): string = if s.startsWith("ptr "): result = s.replace("ptr ") result = result & "Array" else: return s proc genPars(info: GICallableInfo; genProxy = false; binfo: GIBaseInfo = nil; genArrayMark = false; tryOut2Ret: bool = false; modPrefix: bool = false): GPars = proc makePList(s: seq[(string, string)]; self, r: string): string = result = self for i in s: result.add(i[0] & ": " & i[1] & "; ") if result[^1] == ' ': result.setLen(result.len - 2) result.add(")") result.add(r) var self: string = "(" var resusres: string var resus: seq[(string, string)] var resusLen = -1 var resusIn: bool result.replist = newTable[string, (string, RecRes)]() var lastName: string let m = gCallableInfoGetNArgs(info) - 1 var sym = "" if isFunctionInfo(info): sym = $gFunctionInfoGetSymbol(info) if binfo.isNil or not gCallableInfoIsMethod(info): result.arglist = "(" else: var ns = ($gBaseInfoGetNamespace(binfo)).toLowerAscii if callerAlloc.contains(ns & '.' & manglename(gBaseInfoGetName(binfo))): # self = "(self: " & manglename(gBaseInfoGetQualifiedName(binfo)) & "; " self = "(self: " & manglename(gBaseInfoGetName(binfo)) & "; " result.arglist = "(self" else: var refFunc: string = "" # default if genProxy and gCallableInfoGetInstanceOwnershipTransfer(info) == GITransfer.EVERYTHING: if callerAlloc.contains(($gBaseInfoGetNamespace(binfo)).toLowerAscii & "." & $gBaseInfoGetName(binfo)): discard elif false: # r == "gobject.Value": discard elif gBaseInfoGetType(binfo) in [GIInfoType.Enum, GIInfoType.Flags]: discard elif gBaseInfoGetType(binfo) == GIInfoType.Object: if gObjectInfoGetFundamental(binfo) == GFalse: refFunc = "g_object_ref(" else: refFunc = $gObjectInfoGetRefFunction(binfo) & '(' elif gRegisteredTypeInfoGetGType(binfo) == G_TYPE_NONE: assert(gBaseInfoGetType(binfo) == GIInfoType.Struct) # result.implRef = " result.ignoreFinalizer = true # !!!" # echo "aaa", sym # g_strv_builder_unref or g_strv_builder_unref, we ignore that for now elif gRegisteredTypeInfoGetGType(binfo) != G_TYPE_NONE: if gTypeFundamental(gRegisteredTypeInfoGetGType(binfo)) == G_TYPE_INTERF: refFunc = "g_object_ref(" elif gTypeFundamental(gRegisteredTypeInfoGetGType(binfo)) == G_TYPE_BOXED: var getTypeProc = $gRegisteredTypeInfoGetTypeInit(binfo) refFunc = "g_boxed_copy(" & getTypeProc & "(), " else: # echo "bbb" discard#result.implRef = " result.ignoreFinalizer = true # GVariant" ## only for very few procs the instance variable itself can be NULL in GTK. We assume non NULL and may provide an overload. var arg0: string if refFunc != "": arg0 = refFunc & "self.impl))" else: arg0 = "self.impl)" result.arglist = "(cast[ptr " & manglename(gBaseInfoGetName(binfo)) & "00](" & arg0 #result.arglist = "(cast[ptr " & manglename(gBaseInfoGetQualifiedName(binfo)) & "00](" & arg0 # "self.impl)" # https://discourse.gnome.org/t/g-arg-info-may-be-null-for-the-instace-itself/3284/7 # arglist = "(if self.isNil: nil else: cast[ptr " & manglename(gBaseInfoGetName(binfo)) & "00](" & "self.impl)" if genProxy: var h = manglename(gBaseInfoGetQualifiedName(binfo, modPrefix)) let provider = interfaceProvider.getOrDefault(h, @[]) if provider.len > 0: for i in provider: discard mangleType(i) h = h & " | " & provider.join(" | ") self = "(self: " & h & "; " else: self = "(self: ptr " & manglename(gBaseInfoGetQualifiedName(binfo, modPrefix)) & "00" & "; " #self = "(self: ptr " & manglename(gBaseInfoGetName(binfo)) & "00" & "; " if m >= 0: result.arglist.add(", ") var num = "" for j in 0 .. m: let arg = gCallableInfoGetArg(info, j) var argName = mangleName(gBaseInfoGetName(arg)) var isGObject = false let tt = gArgInfoGetType(arg) let tag = gTypeInfoGetTag(tt) if tag == GITypeTag.INTERFACE: let iface = gTypeInfoGetInterface(tt) if gBaseInfoGetType(iface) == GIInfoType.INTERFACE or (gBaseInfoGetType(iface) == GIInfoType.Object and gObjectInfoGetFundamental(iface) == GFalse): # v0.9.4 # https://github.com/StefanSalewski/gintro/issues/172 #if gBaseInfoGetType(iface) == GIInfoType.Object and gObjectInfoGetFundamental(iface) == GFalse: # does not work for gtk_tree_selection_get_selected() if gArgInfoGetDirection(arg) == GIDirection.OUT: isGObject = true var refFunc: string = "" # default var nameimpl: string if genProxy and tag == GITypeTag.INTERFACE and ((gArgInfoGetOwnershipTransfer(arg) == GITransfer.EVERYTHING and gArgInfoGetDirection(arg) == GIDirection.IN) or (gArgInfoGetOwnershipTransfer(arg) == GITransfer.NOTHING and gArgInfoGetDirection(arg) == GIDirection.OUT)): let iface = gTypeInfoGetInterface(tt) if callerAlloc.contains(($gBaseInfoGetNamespace(iface)).toLowerAscii & "." & $gBaseInfoGetName(iface)): discard elif gBaseInfoGetType(iface) in [GIInfoType.Enum, GIInfoType.Flags]: discard elif gBaseInfoGetType(iface) == GIInfoType.Object: if gObjectInfoGetFundamental(iface) == GFalse: refFunc = "g_object_ref(" else: refFunc = $gObjectInfoGetRefFunction(iface) & '(' elif gRegisteredTypeInfoGetGType(iface) == G_TYPE_NONE: assert(gBaseInfoGetType(iface) == GIInfoType.Struct) # echo "xxx", sym #result.implRef = " result.ignoreFinalizer = true # !!!" elif gRegisteredTypeInfoGetGType(iface) != G_TYPE_NONE: if gTypeFundamental(gRegisteredTypeInfoGetGType(iface)) == G_TYPE_INTERF: refFunc = "g_object_ref(" elif gTypeFundamental(gRegisteredTypeInfoGetGType(iface)) == G_TYPE_BOXED: var getTypeProc = $gRegisteredTypeInfoGetTypeInit(iface) refFunc = "g_boxed_copy(" & getTypeProc & "(), " else: discard # echo "yyy", sym#result.implRef = " result.ignoreFinalizer = true # GVariant" if refFunc.len > 0: nameimpl = refFunc & "$1.impl)" else: nameimpl = "$1.impl" var out2Ret = false if tryOut2Ret: let match = if gCallableInfoIsMethod(info): 1 else: 0 out2ret = (gCallableInfoGetNArgs(info) + match) == 2 and (j + match) == 1 and gTypeInfoGetTag(gCallableInfoGetReturnType(info)) == GITypeTag.VOID and gArgInfoGetDirection(arg) == GIDirection.OUT if out2ret:# and genProxy: argName = "result" let t = gArgInfoGetType(arg) let mayBeNil = gArgInfoMayBeNull(arg) var ngr = newGenRec(t, true) var str: string if genProxy and not gArgInfoIsCallerAllocates(arg): if modPrefix: str = ngr.namePlainNS else: str = ngr.namePlain#NS else: if modPrefix: str = ngr.name00NS else: str = ngr.name00#NS if genProxy and ngr.res == glist: result.tempRes = " var tempResGL = seq2GList($1)\n" % [argname] if gArgInfoGetOwnershipTransfer(arg) == GITransfer.NOTHING: result.tempResFree = " g_list_free(tempResGL)\n" if str.startsWith("var "): str = "var seq[$1]" % [ngr.childname] else: str = "seq[$1]" % [ngr.childname] if genProxy and ngr.res == gslist: result.tempRes = " var tempResGL = seq2GSList($1)\n" % [argName] if gArgInfoGetOwnershipTransfer(arg) == GITransfer.NOTHING: result.tempResFree = " g_slist_free(tempResGL)\n" if str.startsWith("var "): str = "var seq[$1]" % [ngr.childname] else: str = "seq[$1]" % [ngr.childname] if (ngr.flags * {RecResFlag.unamedA, namedA} != {}) and genProxy and not gTypeInfoIsZeroTerminated(t): assert ngr.flags.contains(RecResFlag.array) assert not (ngr.flags.contains(RecResFlag.zeroTerminated)) resusLen = gTypeInfoGetArrayLength(t) if resusLen >= 0: resusIn = gArgInfoGetDirection(gCallableInfoGetArg(info, resusLen.cint)) == GIDirection.IN lastName = argName if (sym.startsWith("gtk_widget_set_events", "gtk_widget_add_events")) and str == "int32": str = fixedModName("gdk") & ".EventMask" if isSignalInfo(info) and isProxyCandidate(t) and not genProxy: str.insert("ptr ") var userAlloc: bool var hhh = ngr.namePlainNS if hhh.startsWith("gtk4", "gdk4"): hhh.delete(3, 3) if callerAlloc.contains(hhh): userAlloc = true if modPrefix: str = ngr.namePlainNS else: str = ngr.namePlain if genProxy: let tag = gTypeInfoGetTag(t) if tag == GITypeTag.INTERFACE: let iface = gTypeInfoGetInterface(t) if gBaseInfoGetType(iface) == GIInfoType.INTERFACE: if interfaceProvider.contains(str): let provider = interfaceProvider[str] for i in provider: discard mangleType(i) str = str & " | " & provider.join(" | ") if gArgInfoGetDirection(arg) in {GIDirection.OUT, GIDirection.INOUT}: str.insert("(") str.add(")") # if utf8StringArrays.contains(sym): # https://discourse.gnome.org/t/my-impression-is-that-some-entries-in-the-gir-files-are-just-wrong/1265 if sym in ["g_strv_length", "g_strfreev"]: # wrong but we don't fix it, as with fix str would not match flags discard #echo str, " xxxxxxxxxxxxxxxxx" #str = "cstringArray" var name = argName#mangleName(gBaseInfoGetName(arg)) if isProxyCandidate(t) and not gArgInfoIsCallerAllocates(arg) and not userAlloc: if mayBeNil and gArgInfoGetDirection(arg) != GIDirection.OUT: # result.arglist.add("if " & name & ".isNil: nil else: cast[" & ngr.name00 & "](" & name & ".impl)") result.arglist.add("if " & name & ".isNil: nil else: cast[" & ngr.name00 & "](" & (nameimpl % [name]) & ")") else: if isGobject: if gArgInfoIsOptional(arg): result.arglist.add("cast[var " & ngr.name00 & "](if addr(" & name & ") == nil: nil else: addr tmpoutgobjectarg)") else: result.arglist.add("tmpoutgobjectarg") result.tmpoutgobjectarg = " var tmpoutgobjectarg: " & ngr.name00 & "\n" result.outgobjectargname = argName result.outgobjectargisoptional = gArgInfoIsOptional(arg) result.outgobjectargmaybenull = gArgInfoMayBeNull(arg) elif gArgInfoGetDirection(arg) == GIDirection.OUT and gArgInfoGetOwnershipTransfer(arg) == GITransfer.NOTHING: if gArgInfoIsOptional(arg): # INOUT i.e. for gst_gl_ensure_element_data result.arglist.add("cast[var " & ngr.name00 & "](if addr(" & name & ") == nil: nil else: addr " & name & ".impl)") else: result.arglist.add("cast[var " & ngr.name00 & "](addr " & name & ".impl)") result.tempResFree.add(" " & name & ".impl = cast[" & ngr.name00 & "](" & (nameimpl % [name]) & ")\n") elif gArgInfoGetDirection(arg) == GIDirection.OUT or gArgInfoGetDirection(arg) == GIDirection.INOUT: if gArgInfoIsOptional(arg): # INOUT i.e. for gst_gl_ensure_element_data result.arglist.add("cast[var " & ngr.name00 & "](if addr(" & name & ") == nil: nil else: addr " & name & ".impl)") else: result.arglist.add("cast[var " & ngr.name00 & "](addr " & name & ".impl)") else: #assert false # result.arglist.add("cast[" & ngr.name00 & "](" & name & ".impl)") result.arglist.add("cast[" & ngr.name00 & "](" & (nameimpl % [name]) & ")") else: if ngr.res == glist: result.arglist.add("tempResGL") elif ngr.res == gslist: result.arglist.add("tempResGL") elif ngr.flags.contains(RecResFlag.unamedA) and (gArgInfoGetDirection(arg) == GIDirection.IN or gArgInfoIsCallerAllocates(arg)): assert ngr.flags.contains(RecResFlag.array) result.arglist.add("cast[" & ngr.name00 & "](unsafeaddr($1[0]))" % name) elif (ngr.flags * {RecResFlag.namedA, cstringA} != {}) and gArgInfoGetDirection(arg) == GIDirection.IN: assert ngr.flags.contains(RecResFlag.array) result.arglist.add("seq2$1" % [str.replace("00").capitalizeAscii.fixedName] & '(' & name & ", " & StringArrayName & "$1)" % [num]) num = "2" elif needTypeConv(str, ngr) and gArgInfoGetDirection(arg) in {GIDirection.OUT, GIDirection.INOUT}: result.arglist.add(name.strip(chars = {'`'}) & "_00") elif needTypeConv(str, ngr): if str == "cstring" and mayBeNil: # result.arglist.add("safeStringToCString" & '(' & name & ')') result.arglist.add(name) # v0.9.4 else: if str != "string" and str != "cstring": result.arglist.add(str & '(' & name & ')') else: result.arglist.add(name) else: result.arglist.add(name) if not genProxy and needTypeConv(str, ngr) and (str != "cstring" or gArgInfoGetDirection(arg) in {GIDirection.OUT, INOUT}): result.replist[$name] = (fixedName2($str), ngr) var needVar = true if gArgInfoGetDirection(arg) in {GIDirection.OUT, INOUT} and not (ngr.flags.contains(RecResFlag.unamedA) and gArgInfoIsCallerAllocates(arg)): needVar = true if sym in ["nice_agent_recv", "nice_agent_recv_nonblocking"] and name == "bufLen": # https://discourse.gnome.org/t/nice-agent-recv/5747/2 needVar = false if genProxy and needTypeConv(str, ngr): if gArgInfoGetDirection(arg) in {GIDirection.OUT, INOUT} and (not gArgInfoIsCallerAllocates(arg) or (str in ["int32", "uint32", "ptr cstring", "cstring"])): if gArgInfoGetDirection(arg) in {GIDirection.OUT}: ngr.optOut = true result.replist[$name] = (fixedName2($str), ngr) if gArgInfoGetDirection(arg) in {GIDirection.OUT, INOUT} or str != "cstring": # new in 0.4.11 -- allow passing cstring if not a var str = doTypeConv(str, ngr) if ngr.flags.contains(RecResFlag.unamedA) and gArgInfoGetDirection(arg) in {GIDirection.OUT, INOUT}: str.insert("var ") needVar = false if needVar and gArgInfoGetDirection(arg) in {GIDirection.OUT, INOUT} and not (ngr.flags.contains(RecResFlag.unamedA) and gArgInfoIsCallerAllocates(arg)): str.insert("var ") if genProxy and defaultParameters.contains(sym): for hhh in defaultParameters[sym].split('|'): var h1, h2, h3: string (h1, h2, h3) = hhh.split if name == h1 and str == h2: str.add(" = " & h3) #if genProxy and (str == "string" or str == "cstring") and mayBeNil and not sym.contains("_button_new_with_label"): # str.add(" = \"\"") # v0.9.4 if genProxy and (str == "string") and mayBeNil and not sym.contains("_button_new_with_label"): str.add(" = \"\"") if genProxy and (str == "cstring") and mayBeNil and not sym.contains("_button_new_with_label"): str.add(" = nil") if genProxy and m == 0: if sym.contains("_set_") and str == "bool": str.add(" = true") if genProxy and isProxyCandidate(t) and mayBeNil and gArgInfoGetDirection(arg) notin {GIDirection.OUT, INOUT}: let h = str.split(" | ") if h.len > 1:# echo "aaaaaaaaaaa ", h[0], " ", str str.add(" = " & h[0] & "(nil)") else: str.add(" = nil") # provider when false: if genProxy and gArgInfoIsOptional(arg) and gArgInfoGetDirection(arg) == GIDirection.INOUT: # very few like argc and argv -- we ignore them for now echo ">>>", sym, " ", mangleName(gBaseInfoGetName(arg)) if genProxy and gArgInfoIsOptional(arg) and gArgInfoGetDirection(arg) in {GIDirection.OUT} and not sym.startsWith("gdk_event_get"): # https://github.com/nim-lang/Nim/issues/15895 assert(str.startsWith("var ")) var h = str[4 .. ^1] let l = h.find('|') if l > 0: h.setlen(l - 1) h = h[1 .. ^1] # str.add(" = cast[ptr $1](nil)[]" % [h]) str.add(" = cast[var $1](nil)" % [h]) # same, see https://forum.nim-lang.org/t/7117 if (genProxy or sym == "pango_extents_to_pixels") and isFunctionInfo(info) and (gFunctionInfoGetFlags(info).int and GIFunctionInfoFlags.WRAPS_VFUNC.ord) == 0: if userAlloc and mayBeNil: # or (sym == "gdk_window_set_geometry_hints" and str == "Geometry"): # gir bug! var h = str h.removePrefix("var ") # str.add(" = cast[ptr " & h & "](nil)[]") str.add(" = cast[var " & h & "](nil)") # the same as above #if str == "var seq[string]": no var varargs support! if str == "seq[string]": if j == m: str = "varargs[string, `$`]" else: str = "openArray[string]" if str == "seq[uint8]": # allow to pass a string for a seq[uint8] argument too # str = "seq[uint8] | openArray[char]" # maybe also seq[int8] and seq[char] ? # https://github.com/nim-lang/Nim/issues/15128 str = "seq[uint8] | string" if str == "var seq[uint8]": # allow to pass a string for a seq[uint8] argument too str = "var (seq[uint8] | string)" # str = "var (seq[uint8] | openArray[char])" # https://github.com/nim-lang/Nim/issues/15128 if genArrayMark and ngr.flags.contains(RecResFlag.array) and str.startsWith("ptr "): str.removePrefix("ptr ") str.add("Array") if not out2Ret:#(out2ret and genProxy): resus.add((name, str)) else: var h = str let i = h.find('=') if i > 0: h.setLen(i) # well i - 1 , try find(" =") h.removePrefix("var ") resusres = ": " & h#str.dup(removePrefix("var ")) if j < m: result.arglist.add(", ") if not genProxy and gCallableInfoCanThrowGerror(info): resus.add(("error", "ptr ptr glib.Error = nil")) result.arglist.add(')') var ret = gCallableInfoGetReturnType(info) assert(ret != nil) if resusLen < 0 and not gTypeInfoIsZeroTerminated(ret): resusLen = gTypeInfoGetArrayLength(ret) if isFunctionInfo(info): if (gFunctionInfoGetFlags(info).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) != 0: let h = gBaseInfoGetContainer(info) if gBaseInfoGetType(h) == GIInfoType.OBJECT: if genProxy: resusres = ": " & mangleType(mangleName(gBaseInfoGetQualifiedName(h, modPrefix))) #resusres = ": " & mangleType(mangleName(gBaseInfoGetName(h))) else: resusres = ": ptr " & mangleType(mangleName(gBaseInfoGetQualifiedName(h, modPrefix))) & "00" #resusres = ": ptr " & mangleType(mangleName(gBaseInfoGetName(h))) & "00" if resusLen >= 0: result.blex = resus[resusLen][0] assert(resusIn) let h = resus[resusLen][1].replace("var ", "") result.arrLex = " let $1 = $2($3.len)\n" % [resus[resusLen][0], h, lastName] resus.delete(resusLen) result.plist = makePList(resus, self, resusres).isplit(sym.len + "proc".len) return result var ngrRet = newGenRec(ret, true) var r: string if genProxy: r = ngrRet.namePlain else: r = ngrRet.name00 if genProxy and ngrRet.res == glist: r = "seq[$1]" % [ngrRet.childname] if genProxy and ngrRet.res == gslist: r = "seq[$1]" % [ngrRet.childname] var hhh = ngrRet.namePlainNS var refFunc: string = "" # default if genProxy and gTypeInfoGetTag(ret) != GITypeTag.VOID: var tag = gTypeInfoGetTag(ret) if genProxy and tag == GITypeTag.INTERFACE: let iface = gTypeInfoGetInterface(ret) if callerAlloc.contains(($gBaseInfoGetNamespace(iface)).toLowerAscii & "." & $gBaseInfoGetName(iface)): discard elif r == "gobject.Value": discard elif gBaseInfoGetType(iface) in [GIInfoType.Enum, GIInfoType.Flags]: discard elif gBaseInfoGetType(iface) == GIInfoType.Object: if gObjectInfoGetFundamental(iface) == GFalse: refFunc = "g_object_ref(" else: refFunc = $gObjectInfoGetRefFunction(iface) & '(' elif gRegisteredTypeInfoGetGType(iface) == G_TYPE_NONE: assert(gBaseInfoGetType(iface) == GIInfoType.Struct) result.implRef = " result.ignoreFinalizer = true" elif gRegisteredTypeInfoGetGType(iface) != G_TYPE_NONE: if gTypeFundamental(gRegisteredTypeInfoGetGType(iface)) == G_TYPE_INTERF: refFunc = "g_object_ref(" elif gTypeFundamental(gRegisteredTypeInfoGetGType(iface)) == G_TYPE_BOXED: var getTypeProc = $gRegisteredTypeInfoGetTypeInit(iface) refFunc = "g_boxed_copy(" & getTypeProc & "(), " else: result.implRef = " result.ignoreFinalizer = true # GVariant" if refFunc.len > 0: result.implRef = (" result.impl = cast[typeof(result.impl)](" & refFunc & "result.impl))") if hhh.startsWith("gtk4", "gdk4"): hhh.delete(3, 3) #if gTypeInfoIsPointer(ret) and callerAlloc.contains(hhh) and (not r.startsWith("ptr")): if fixedgTypeInfoIsPointer(ret) and callerAlloc.contains(hhh) and (not r.startsWith("ptr")): r = "ptr " & r if isSignalInfo(info) and isProxyCandidate(ret) and not genProxy and (not r.startsWith("ptr")): # for v0.9.9 r.insert("ptr ") #echo "aaaaaaaaaaaaaaaaaaaaaa ", r if r != "void": if genProxy: let h = doTypeConv(r, ngrRet) if h.len > 0: r = h resusres = ": " & r if resusLen >= 0: result.blex = resus[resusLen][0] if resusIn: let h = resus[resusLen][1].replace("var ", "") result.arrLex = " let $1 = $2($3.len)\n" % [resus[resusLen][0], h, lastName] resus.delete(resusLen) else: result.arrLex = "" result.plist = makePList(resus, self, resusres).isplit(sym.len + "proc".len) # see also template findFreeProc() # g_object_unref proc findFreeObject(info: GIBaseInfo): string = assert(gBaseInfoGetType(info) == GIInfoType.Object or gBaseInfoGetType(info) == GIInfoType.INTERFACE) #assert(gObjectInfoGetFundamental(info) == GTrue) var parent = info while true: let h = g_object_info_get_parent(parent) if h == nil: break parent = h var f = $g_object_info_get_unref_function(parent) if f == "g_param_spec_uref": f = "g_param_spec_unref" return f # empty string for all true gobjects, only not empty for GParamSpec and a few more, see grep "unref-func" /usr/share/gir-1.0/* proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo) = template checkForGerror(): untyped = methodBuffer.write(pars.tempResFree) if gCallableInfoCanThrowGerror(minfo): methodBuffer.writeLine(" if gerror != nil:") methodBuffer.writeLine(" let msg = $gerror.message") methodBuffer.writeLine(" g_error_free(gerror[])") methodBuffer.writeLine(" raise newException(GException, msg)") # new for v0.8.8 template dothegobjectargmagic(): untyped = if pars.outgobjectargisoptional: methodBuffer.writeLine(""" if addr($1) != nil: $1 = nil """ % [pars.outgobjectargname]) elif pars.outgobjectargmaybenull: methodBuffer.writeLine(" $1 = nil" % [pars.outgobjectargname]) if pars.outgobjectargisoptional or pars.outgobjectargmaybenull: methodBuffer.writeLine(""" if tmpoutgobjectarg != nil: let argqdata = g_object_get_qdata(tmpoutgobjectarg, Quark) if argqdata != nil: $1 = cast[type($1)](argqdata) assert($1.impl == tmpoutgobjectarg) else: fnew($1, $2.finalizeGObject) $1.impl = tmpoutgobjectarg GC_ref($1) if g_object_is_floating($1.impl).int != 0: discard g_object_ref_sink($1.impl) g_object_add_toggle_ref($1.impl, toggleNotify, addr($1[])) g_object_unref($1.impl) assert(g_object_get_qdata($1.impl, Quark) == nil) g_object_set_qdata($1.impl, Quark, addr($1[])) """ % [pars.outgobjectargname, fixedModName(moduleNamespace)]) else: methodBuffer.writeLine(""" let argqdata = g_object_get_qdata(tmpoutgobjectarg, Quark) if argqdata != nil: $1 = cast[type($1)](argqdata) assert($1.impl == tmpoutgobjectarg) else: fnew($1, $2.finalizeGObject) $1.impl = tmpoutgobjectarg GC_ref($1) if g_object_is_floating($1.impl).int != 0: discard g_object_ref_sink($1.impl) g_object_add_toggle_ref($1.impl, toggleNotify, addr($1[])) g_object_unref($1.impl) assert(g_object_get_qdata($1.impl, Quark) == nil) g_object_set_qdata($1.impl, Quark, addr($1[])) """ % [pars.outgobjectargname, fixedModName(moduleNamespace)]) # new for v0.7.8: we ref all gobjects now, even if transfer is none. So result.ignoreFinalizer = false always for gobjects! template gobjectTemp(): untyped = assert sym notin ["g_object_ref_sink", "g_object_ref"] assert(gCallableInfoGetCallerOwns(minfo) in {GITransfer.NOTHING, EVERYTHING}) # both occur methodBuffer.write(pars.tempRes) methodBuffer.writeLine(" let gobj = " & sym & pars.arglist) checkForGerror() if gCallableInfoMayReturnNull(minfo): methodBuffer.writeLine(" if gobj.isNil:") methodBuffer.writeLine(" return nil") # https://github.com/StefanSalewski/gintro/issues/63 methodBuffer.writeLine(" let qdata = g_object_get_qdata(gobj, Quark)") methodBuffer.writeLine(" if qdata != nil:") # gtk_widget_get_toplevel, gdk_display_get_default, gtk_widget_get_window #if (gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) != 0: # methodBuffer.writeLine(" assert false") # constructors should always allocate new objects -- lets verify that # no, will fail i.e. for gdk_cursor_new_from_name() methodBuffer.writeLine(" result = cast[type(result)](qdata)") methodBuffer.writeLine(" assert(result.impl == gobj)") methodBuffer.writeLine(" else:") #assert((gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) != 0 or # gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING) methodBuffer.writeLine(" fnew(result, $1finalizeGObject)" % [mprefix]) methodBuffer.writeLine(" result.impl = gobj") methodBuffer.writeLine(" GC_ref(result)") if sym in ["gtk_window_new", "gtk_application_window_new"]: # GC_ref() so we never free the main window! methodBuffer.writeLine(" GC_ref(result)") methodBuffer.writeLine(" result.ignoreFinalizer = true") elif gCallableInfoGetCallerOwns(minfo) == GITransfer.NOTHING: methodBuffer.writeLine(" discard g_object_ref_sink(result.impl)") else: methodBuffer.writeLine(" if g_object_is_floating(result.impl).int != 0:") methodBuffer.writeLine(" discard g_object_ref_sink(result.impl)") methodBuffer.writeLine(" g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))") methodBuffer.writeLine(" g_object_unref(result.impl)") methodBuffer.writeLine(" assert(g_object_get_qdata(result.impl, Quark) == nil)") methodBuffer.writeLine(" g_object_set_qdata(result.impl, Quark, addr(result[]))") # prefer gboxed_free() but fall back for GVariant template findFreeProc(info: GIBaseInfo; noWarning: bool): untyped = if gBaseInfoGetType(info) == GIInfoType.UNION or gBaseInfoGetType(info) == GIInfoType.STRUCT: if gBaseInfoGetType(info) == GIInfoType.UNION: # assert false executed for gtk3 freeMe = gUnionInfoFindMethod(info, "free") if freeMe.isNil: freeMe = gUnionInfoFindMethod(info, "unref") else: assert gBaseInfoGetType(info) == GIInfoType.STRUCT freeMe = gStructInfoFindMethod(info, "free") if freeMe.isNil: freeMe = gStructInfoFindMethod(info, "unref") if freeMe == nil: if fixedDestroyNames.contains(sym): assert false freeMeName = fixedDestroyNames[sym] else: assert (not fixedDestroyNames.contains(sym)) freeMeName = "finalizer" & $gBaseInfoGetName(freeMe) # puh if gRegisteredTypeInfoGetGType(info) != G_TYPE_NONE and gTypeFundamental(gRegisteredTypeInfoGetGType(info)) == G_TYPE_BOXED: boxedFreeMeName = "gBoxedFree" & $gRegisteredTypeInfoGetTypeName(info) else: boxedFreeMeName = "" if gBaseInfoGetName(info) == "VariantType": # there is no g_variant_get_type() boxedFreeMeName = "" if boxedFreeMeName == "" and not noWarning: if freeMeName == "": if sym notin ["g_enum_complete_type_info", "g_flags_complete_type_info"]: # see https://discourse.gnome.org/t/what-is-wrong-with-g-enum-complete-type-info-and/4489 echo "Caution: No free/unref found for ", ' ', " (", sym, ')' else: #if gBaseInfoGetName(info) notin ["Variant", "VariantType"]: # seems for glib.GVariant we have to guess -- or maybe just know if gBaseInfoGetName(info) notin ["Variant", "VariantType"] and # looks ugly, so hide for v0.8.7, investigate later... sym notin ["soup_xmlrpc_parse_request", "gst_audio_resampler_new", "gst_rtsp_connection_accept", "gst_rtsp_connection_create_from_socket", "gst_rtsp_connection_create", "gst_sdp_media_copy", "gst_sdp_media_new"]: echo "Caution: Do guess free/unref for ", ' ', " (", sym, ')' if boxedFreeMeName == "gBoxedFreeGVariantType": # this does not work assert false if gBaseInfoGetType(info) == GIInfoType.Object: assert(gObjectInfoGetFundamental(info) == GTrue) var parent = info while true: let h = g_object_info_get_parent(parent) if h == nil: break parent = h boxedFreeMeName = "" var hf = $g_object_info_get_unref_function(parent) if hf == "g_param_spec_uref": hf = "g_param_spec_unref" freeMeName = "generic_" & hf # $g_object_info_get_unref_function(parent) assert(freeMeName != "") template block8(prochead: string; errorcheckadd: bool; tryOut2Ret: bool): untyped = if isProxyCandidateret2: assert (gCallableInfoGetCallerOwns(minfo) in {GITransfer.NOTHING, GITransfer.EVERYTHING}) # both occur if asym == "newFromStreamAsync" and sym.startsWith("gdk_pixbuf_animation_new"): asym = "newAnimationFromStreamAsync" if prochead.len == 0: methodBuffer.writeLine("\nproc " & asym & EM & pars.plist & " =") else: methodBuffer.writeLine(prochead) if not isProxyCandidateret2: methodBuffer.write(pars.tempRes) methodBuffer.write(pars.arrLex) methodBuffer.write(sss) var freeMeName{.inject.}: string var boxedFreeMeName{.inject.}: string for j in 0.cint ..< gCallableInfoGetNArgs(minfo): freeMeName = "" boxedFreeMeName = "" let arg = gCallableInfoGetArg(minfo, j) let t = gArgInfoGetType(arg) var ngrt = newGenRec(t) var isGObject = false let tt = gArgInfoGetType(arg) let tag = gTypeInfoGetTag(tt) if tag == GITypeTag.INTERFACE: let iface = gTypeInfoGetInterface(tt) #if gBaseInfoGetType(iface) == GIInfoType.Object and gObjectInfoGetFundamental(iface) == GFalse: # before v0.9.4 if gBaseInfoGetType(iface) == GIInfoType.INTERFACE or (gBaseInfoGetType(iface) == GIInfoType.Object and gObjectInfoGetFundamental(iface) == GFalse): if gArgInfoGetDirection(arg) == GIDirection.OUT: isGObject = true if false: # for v0.9.3 we use g_object_ref(), g_boxed_copy and such, see https://discourse.gnome.org/t/get-ref-function-for-none-gobject-classes-like-gtkexpression/6696/15 #if true: # https://discourse.gnome.org/t/gtk-no-selection-new/6576 #if ((gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) == 0): if gArgInfoGetDirection(arg) == GIDirection.IN and gArgInfoGetOwnershipTransfer(arg) == GITransfer.EVERYTHING and isProxyCandidate(t) and not callerAlloc.contains(ngrt.namePlainNS): # like gtk_widget_add_controller() let n = mangleName(gBaseInfoGetName(arg)) if gArgInfoMayBeNull(arg): # and prochead.len != 0: # wrong to be compatible with 0.8.6 methodBuffer.writeLine(" if " & n & " != nil:") methodBuffer.writeLine(" " & n & ".ignoreFinalizer = true") else: methodBuffer.writeLine(" " & n & ".ignoreFinalizer = true") if isGobject: discard elif gArgInfoGetDirection(arg) == GIDirection.OUT and isProxyCandidate(t) and not callerAlloc.contains(ngrt.namePlainNS) and not gArgInfoIsCallerAllocates(arg): let tag = gTypeInfoGetTag(t) assert(tag == GITypeTag.INTERFACE) assert gArgInfoGetOwnershipTransfer(arg) != GITransfer.CONTAINER if gArgInfoGetOwnershipTransfer(arg) == GITransfer.EVERYTHING or gArgInfoGetOwnershipTransfer(arg) == GITransfer.NOTHING: # pass always the same finalizer for ARC let iface = gTypeInfoGetInterface(t) if gBaseInfoGetType(iface) == GIInfoType.OBJECT: let ttt = gArgInfoGetType(arg) freeMeName = modPrefix(ttt, sym) & "finalizeGObject" # TODO: investigate, we may need the full toggleRef stuff! else: let info = iface var freeMe{.inject.}: GIFunctionInfo findFreeProc(info, gArgInfoGetOwnershipTransfer(arg) == GITransfer.NOTHING) var h2 = mangleName(gBaseInfoGetName(arg)) if tryOut2Ret: let match = if gCallableInfoIsMethod(minfo): 1 else: 0 let out2ret = (gCallableInfoGetNArgs(minfo) + match) == 2 and (j + match) == 1 and gTypeInfoGetTag(gCallableInfoGetReturnType(minfo)) == GITypeTag.VOID and gArgInfoGetDirection(arg) == GIDirection.OUT if out2ret:# and genProxy: h2 = "result" if gArgInfoMayBeNull(arg): nilArgFix.add(h2) if gArgInfoIsOptional(arg): methodBuffer.writeLine(" if addr($2) != nil:" % [ngrt.namePlain, h2]) if boxedFreeMeName != "": methodBuffer.writeLine(" fnew(" & h2 & ", " & boxedFreeMeName & ")") elif freeMeName == "": # never executed methodBuffer.writeLine(" new(" & h2 & ")") else: methodBuffer.writeLine(" fnew(" & h2 & ", " & freeMeName & ")") else: if boxedFreeMeName != "": methodBuffer.writeLine(" fnew(" & h2 & ", " & boxedFreeMeName & ")") elif freeMeName == "": # never executed methodBuffer.writeLine(" new(" & h2 & ")") else: methodBuffer.writeLine(" fnew(" & h2 & ", " & freeMeName & ")") if false: # for v0.9.3 we use g_object_ref(), g_boxed_copy and such, see https://discourse.gnome.org/t/get-ref-function-for-none-gobject-classes-like-gtkexpression/6696/15 # if gArgInfoGetOwnershipTransfer(arg) == GITransfer.NOTHING: if gArgInfoIsOptional(arg): methodBuffer.writeLine(" if addr($2) != nil:" % [ngrt.namePlain, h2]) methodBuffer.writeLine(" " & h2 & ".ignoreFinalizer = true") else: methodBuffer.writeLine(" " & h2 & ".ignoreFinalizer = true") # as we have always to attach one with ARC. if gCallableInfoCanThrowGerror(minfo): methodBuffer.writeLine(" var gerror: ptr glib.Error") if errorcheckadd: pars.arglist.insert(", addr gerror", pars.arglist.high) var multi = "" for k, v in pars.replist: if v[1].flags * {RecResFlag.namedA, cstringA} != {}: assert v[1].flags.contains(RecResFlag.array) methodBuffer.writeLine(" var $1x$2: array[$3, pointer]" % [StringArrayName, multi, $StringArrayEntries]) methodBuffer.writeLine(" var $1$2: cstringArray = cast[cstringArray](addr $1x$2)" % [StringArrayName, multi]) methodBuffer.writeLine(" var $1_00 = seq2$2($3, $4$5)" % [k.strip(chars = {'`'}), v[0].replace("00").capitalizeAscii, k, StringArrayName, multi]) if multi == "": multi = "1" elif v[1].flags.contains(RecResFlag.unamedA): assert v[1].flags.contains(RecResFlag.array) methodBuffer.writeLine(" var $1_00: $2" % [k.strip(chars = {'`'}), v[1].name00]) else: if v[1].optOut: methodBuffer.writeLine(" var $1_00: $2" % [k.strip(chars = {'`'}), v[0], k]) else: methodBuffer.writeLine(" var $1_00 = $2($3)" % [k.strip(chars = {'`'}), v[0], k]) # assert(info != nil) # why can it be nil? # if Lib.len == 0: # xlib, fontconfig, freetype2 # but Lib is local to main(), so let it crash # return assert(isCallableInfo(mInfo)) assert(isFunctionInfo(mInfo)) let sym = $gFunctionInfoGetSymbol(mInfo) #if info != nil and callerAlloc.contains(moduleNamespace & '.' & $gBaseInfoGetName(info)) and sym.endsWith(["_copy", "_assign", "_free", "_alloc"]): # echo sym # return var nilArgFix: seq[string] var pars: GPars let p = methodBuffer.getPosition let symIsDeprecated = gBaseInfoIsDeprecated(mInfo).int != 0 var depStr = "" if symIsDeprecated: depStr = " {.deprecated.} " if sym[^1] == '_': return if sym.contains("__"): return if processedFunctions.contains(sym): return if gBaseInfoGetName(mInfo).len == 0: # return # The following functions work with arrays, we should check each carefully -- some may not compile... #if sym == "g_io_channel_read_to_end": return # fix later if sym == "g_file_enumerator_iterate": return # two gobject var out parameters, hard to support if sym == "g_boxed_free": return # this is manually added at early position already if sym == "gst_param_spec_fraction": return # fix later if sym == "gst_param_spec_array": return # fix later if sym == "gst_message_new_state_changed": return # fix later if sym == "gst_mini_object_replace": return # fix later if sym == "gst_mini_object_take": return # fix later if sym == "gst_object_replace": return # fix later if sym == "g_base64_decode_inplace": return # fix later if sym == "g_base64_encode_close": return # fix later if sym == "g_base64_encode_step": return # fix later if sym == "g_compute_hmac_for_data": return # fix later if sym == "g_file_get_contents": return # fix later if sym == "g_spawn_command_line_sync": return # fix later if sym == "g_spawn_sync": return # fix later ###if sym == "g_file_load_contents": return # fix later #if sym == "g_file_load_contents_finish": return # fix later if sym == "g_file_load_partial_contents_finish": return # fix later if sym == "g_converter_convert": return # fix later if sym == "gdk_pixbuf_save_to_bufferv": return # fix later if sym == "pango_font_face_list_sizes": return # fix later #if sym == "pango_layout_line_get_x_ranges": return # fix later if sym == "pango_tab_array_get_tabs": return # too complicated! if sym == "pango_coverage_to_bytes": return # fix later if sym == "gdk_property_get": return # hard, length before array if sym == "gdk_query_depths": return # fix later if sym == "gtk_icon_set_get_sizes": return # fix later if sym == "gtk_list_store_insert_with_valuesv": return # fix later if sym == "gtk_list_store_set_valuesv": return # fix later if sym == "gtk_tree_store_insert_with_valuesv": return # fix later if sym == "gtk_tree_store_set_valuesv": return # fix later if sym == "gtk_accelerator_parse_with_keycode": return # zero terminated uint32Array if sym == "gdk_keymap_get_entries_for_keycode": return # var uint32Array if sym == "gtk_text_iter_copy": return if sym == "gtk_widget_destroyed": return if sym == "g_error_new_literal": return if sym == "gtk_selection_data_get_targets": return if sym == "g_strfreev": return if sym == "g_signal_emitv": return #if sym == "g_object_ref": return # supress Hint: 'g_object_ref' is declared but not used if sym == "gtk_container_get_focus_chain": return # GList transfer CONTAINER, hard, deprecated if sym == "gst_structure_from_string": return # constructor with out param, not supported yet. if sym == "gst_structure_take": return # first parameter is var but can be nil? See trouble at the bottom of this file. if sym == "gst_bit_writer_free_and_get_data": return # see https://discourse.gnome.org/t/gst-bit-writer-free-and-get-data/5304/2 if sym == "gst_bit_writer_reset_and_get_data": return if sym == "gst_byte_reader_dup_string_utf32": return if sym == "gst_byte_writer_reset_and_get_data": return if sym == "gst_gl_filter_add_rgba_pad_templates": return if sym == "nice_agent_get_selected_pair": return # was very wrong, fixed manually if sym == "g_hash_table_destroy": return if sym == "g_variant_ref_sink": return # we need this early, so add manually early try: for tryOut2Ret in [false, true]: if tryOut2Ret: var ret2 = gCallableInfoGetReturnType(minfo) let match = if gCallableInfoIsMethod(minfo): 1 else: 0 let arg = gCallableInfoGetArg(minfo, (1 - match).cint) let out2ret = (gCallableInfoGetNArgs(minfo) + match) == 2 and gTypeInfoGetTag(ret2) == GITypeTag.VOID and gArgInfoGetDirection(arg) == GIDirection.OUT if not out2Ret: break pars = genPars(mInfo, false, info)#, tryOut2Ret = tryOut2Ret) processedFunctions.incl(sym) if not (sym.startsWith("g_param_spec_uref") or sym.startsWith("g_param_spec_unref") or sym.startsWith("g_param_spec_get_name")): # v0.9.8, uref/unref fix in latest gobject if sym.startsWith("g_param_spec_", "g_type_interface_", "g_object_interface_"): return if sym in ["gtk_widget_class_find_style_property", "gtk_container_class_find_child_property", "gtk_cell_area_class_find_cell_property"]: return var asym = manglename(gBaseInfoGetName(mInfo)) # this does not really help, we have to fix some names manually if not gCallableInfoIsMethod(minfo) and gCallableInfoGetNArgs(minfo) == 0 and (gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) == 0: var h = sym if h.find('_') > 0: h = h.split('_', 1)[1] if h.endsWith("_get"): h.removeSuffix("_get") h = "get_" & h h = h.mysnakeToCamel #asym = h if asym == "errorQuark" or asym == "quark": return if (moduleNameSpace == "gst" and asym in ["appendAndTakeValue", "appendValue", "getSize", "getValue", "prependValue"]) or asym in ["get", "getDefault", "from", "fromString", "getInfo", "listFree", "register", "find", "getList"]: # or # maybe we should relax this later a bit for the case that first parameter type == gBaseInfoGetName(info) asym.add($manglename(gBaseInfoGetName(info))) if sym == "gtk_buildable_get_name": asym = "buildableGetName" # conflict with gtk_widget_get_name() if sym == "gtk_buildable_set_name": asym = "buildableSetName" if keywords.contains(asym) or nims.contains(asym): asym.add('P') var ret2 = gCallableInfoGetReturnType(minfo) var ngrRet = newGenRec(ret2) let mprefix = modPrefix(ret2, sym) if moduleNameSpace == "graphene" and gCallableInfoGetNArgs(minfo) == 0 and not gCallableInfoIsMethod(minfo): asym.add($manglename(gBaseInfoGetName(info))) for run in 0 .. 1: if run == 1: # try without get prefix and replace set prefix with `=` if fixedProcNames.contains(sym): continue if not (asym.startsWith("get", "set")) or asym == "getPlugin" or asym.len < 4: continue if asym.startsWith("get") and gTypeInfoGetTag(ret2) == GITypeTag.VOID: continue if asym.startsWith("get"): let match = if gCallableInfoIsMethod(minfo): 0 else: 1 if gCallableInfoGetNArgs(minfo) != match: continue if asym.startsWith("set"): let match = if gCallableInfoIsMethod(minfo): 1 else: 2 if gCallableInfoGetNArgs(minfo) != match: continue if gTypeInfoGetTag(ret2) != GITypeTag.VOID: continue #plist.replace("", "") we should remove default value from plist for assignments like width = if asym.startsWith("get"): asym = asym[3 .. ^1].unCap if asym.startsWith("set"): asym = asym[3 .. ^1].unCap asym = '`' & asym & '=' & '`' if keywords.contains(asym) or nims.contains(asym): continue if asym == "`tings=`": continue # result of get_settings # the large proxy block BLOCK7 { let b7 = needProxyProc(mInfo) or isString(ret2) or pars.replist.len > 0 or needTypeConv(ngrRet.name00, ngrRet) or gTypeInfoGetTag(ret2) == GITypeTag.GLIST # export only low level symbols that are needed internally -- maybe we should export only a private name for them if run == 0 and not tryOut2Ret: if sym in ["g_quark_from_static_string", "g_error_free", "g_object_get_qdata", "g_object_ref_sink", "g_object_unref", "g_param_spec_ref_sink", "g_timeout_add_full", "g_object_is_floating", "gst_bus_add_watch_full", "g_object_ref", "g_date_time_format", "gdk_event_ref", "g_strdup", "g_type_from_name", "g_type_check_instance_is_a", "g_idle_add_full", "g_quark_try_string", "vte_regex_unref", "gtk_expression_ref", "gtk_builder_get_object", "g_action_map_add_action", "gtk_drawing_area_set_draw_func", "g_io_add_watch_full", "gtk_container_foreach"]: methodBuffer.write("\nproc " & sym & EM & pars.plist) methodBuffer.writeLine(" {.\n importc, ", libprag, ".}") if sym.startsWith("vte_regex_unref"): # this function is special, as it returns the object methodBuffer.writeLine("\nproc unref*(self: Regex) =") methodBuffer.writeLine(" discard vte_regex_unref(cast[ptr Regex00](self.impl))") return elif b7: methodBuffer.write("\nproc " & sym & pars.plist) methodBuffer.writeLine(" {.\n importc, ", libprag, ".}") if sym in ["g_object_ref_sink", "g_object_ref", "gtk_container_foreach"]: return if b7: var isGObject = false let tag = gTypeInfoGetTag(ret2) if tag == GITypeTag.INTERFACE: let iface = gTypeInfoGetInterface(ret2) #if gBaseInfoGetType(iface) == GIInfoType.Object and gObjectInfoGetFundamental(iface) == GFalse: # the same here! if gBaseInfoGetType(iface) == GIInfoType.INTERFACE or (gBaseInfoGetType(iface) == GIInfoType.Object and gObjectInfoGetFundamental(iface) == GFalse): isGObject = true pars = genPars(mInfo, true, info, tryOut2Ret = tryOut2Ret) var sss = "" sss = pars.tmpoutgobjectarg let num = max([pars.arglist.count("seq2CstringArray"), pars.arglist.count("seq2TargetEntryArray"), pars.arglist.count( "seq2PageRangeArray"), pars.arglist.count("seq2KeymapKeyArray")]) for i in 1 .. num: let h = if i == 1: "" else: $i sss &= " var $1$3x: array[$2, pointer]\n" % [StringArrayName, $StringArrayEntries, h] & " var $1$2: cstringArray = cast[cstringArray](addr $1$2x)\n" % [StringArrayName, h] if asym.len > 2 and asym[^2] == '=': pars.plist = pars.plist.replace(": bool = true", ": bool") if (gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) != 0 or isProxyCandidate(ret2): if info != nil: asym = asym.replace("new", "new" & manglename(gBaseInfoGetName(info))) else: # i.e. "pango_attr_background_new" if asym.endsWith("New"): asym.setLen(asym.len - 3) asym[0] = asym[0].toUpperAscii asym = "new" & asym #discard #asym = #if sym == "pango_attr_background_new": echo "sss", info != nil, asym asym = fixedProcNames.getOrDefault(sym, asym) # BLOCKMARK8 : 3 cases: constructor, isProxyCandidate(ret2), plain else let isProxyCandidateret2 = isProxyCandidate(ret2) #else: # BLOCKMARK8 assert gerror if not (isProxyCandidateret2 or isGObject): block8("", true, tryOut2Ret) if isProxyCandidateret2 or isGObject: # BLOCKMARK8 for itt in 0 .. 2: # generate the new(), the new(typedesc) and the init() proc var hhh = "\nproc " & asym & EM & pars.plist if itt == 1: # new(typedesc) let semi = if hhh.contains("()"): "" else: "; " let p = hhh.find("): ") hhh.setLen(p + 1) hhh = hhh.replace("*(", "*(tdesc: typedesc" & semi) hhh.add(": tdesc") if itt == 2: # init(), deprecated let semi = if hhh.contains("()"): "" else: "; " let p = hhh.find("): ") hhh.setLen(p + 1) hhh = hhh.replace("proc new", "proc init") # v0.8.2 hhh = hhh.replace("*(", "*[T](result: var T" & semi) if itt == 2 and ((gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) != 0): depStr = " {.deprecated.}" if itt == 2 or ((gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) != 0): hhh = hhh & depStr & " =" else: hhh = hhh & " =" block8(hhh, itt == 0, tryOut2Ret) if not isGObject: methodBuffer.write(pars.tempRes) # caution, gobjectTemp() may write tempRes too. if itt == 1 or itt == 2: methodBuffer.writeLine(" assert(result is $1)" % [manglename(gBaseInfoGetName(info))]) if isGObject: gobjectTemp() elif gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING or gCallableInfoGetCallerOwns(minfo) == GITransfer.NOTHING: # for ARC we have always to use the same finalizer! let tag = gTypeInfoGetTag(ret2) assert tag == GITypeTag.INTERFACE var iface = gTypeInfoGetInterface(ret2) if gBaseInfoGetType(iface) == GIInfoType.INTERFACE: gobjectTemp() else: assert(gBaseInfoGetType(iface) in {GIInfoType.STRUCT, GIInfoType.UNION, GIInfoType.OBJECT}) var freeMeName: string var freeMe: GIFunctionInfo var boxedFreeMeName: string findFreeProc(iface, gCallableInfoGetCallerOwns(minfo) == GITransfer.NOTHING) if gCallableInfoCanThrowGerror(minfo) or gCallableInfoMayReturnNull(minfo): methodBuffer.writeLine(" let impl0 = " & sym & pars.arglist) # fast return in case of error checkForGerror() if gCallableInfoMayReturnNull(minfo): methodBuffer.writeLine(" if impl0.isNil:") methodBuffer.writeLine(" return nil") if boxedFreeMeName != "": methodBuffer.writeLine(" fnew(result, $1)" % boxedFreeMeName) elif freeMeName == "": # assert false # TODO we have to fix this case manually # echo "xCaution: No free/unref found for ", ' ', gBaseInfoGetName(iface), " (", sym, ')' # check this from time to time! methodBuffer.writeLine(" new(result)") else: methodBuffer.writeLine(" fnew(result, $1)" % freeMeName) var weAppliedThatUglyFix = false if gCallableInfoCanThrowGerror(minfo) or gCallableInfoMayReturnNull(minfo): if pars.implRef.startsWith(" result.impl = cast[typeof(result.impl)](") and pars.implRef.endsWith("result.impl))") and gCallableInfoGetCallerOwns(minfo) == GITransfer.NOTHING and ((gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) == 0): # if we really write pars.implRef # tiny, ugly fix to save some lines of code var parsimplRef = pars.implRef.replace("result.impl))", "impl0))") weAppliedThatUglyFix = true methodBuffer.writeLine(parsimplRef) else: methodBuffer.writeLine(" result.impl = impl0") else: methodBuffer.writeLine(" result.impl = " & sym & pars.arglist) if gCallableInfoGetCallerOwns(minfo) == GITransfer.NOTHING: # for the none gobjects if ((gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) == 0): if not weAppliedThatUglyFix: methodBuffer.writeLine(pars.implRef) ### methodBuffer.writeLine(" result.ignoreFinalizer = true") # as we have always to attach one with ARC. else: assert false if ((gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) != 0 and gBaseInfoGetName(info) == "Variant"): # methodBuffer.writeLine(" result.ignoreFinalizer = true") # before v0.9.5 methodBuffer.writeLine(" discard g_variant_ref_sink(result.impl)") if (gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) == 0: break elif ngrRet.res == glist: var elTransferFull = gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING if gCallableInfoCanThrowGerror(minfo) or gCallableInfoMayReturnNull(minfo) or gCallableInfoGetCallerOwns(minfo) != GITransfer.NOTHING: methodBuffer.writeLine(" let resul0 = " & sym & pars.arglist) checkForGerror() if gCallableInfoMayReturnNull(minfo): methodBuffer.writeLine(" if resul0.isNil:") methodBuffer.writeLine(" return") if ngrRet.infoType == GIInfoType.OBJECT or ngrRet.infoType == GIInfoType.INTERFACE: methodBuffer.writeLine(" result = glistObjects2seq($1, resul0, $2)" % [ngrRet.childName, $elTransferFull]) if ngrRet.infoType == GIInfoType.STRUCT: if gBaseInfoGetName(gTypeInfoGetInterface(gTypeInfoGetParamType(ret2, 0))) notin ["Atom", "Variant", "TimedValue"]: # care later methodBuffer.writeLine(" result = glistStructs2seq[$1](resul0, $2)" % [ngrRet.childName, $(gCallableInfoGetCallerOwns(minfo) != GITransfer.EVERYTHING)]) # caution TimedValue is a "light" entity, so we need a different glistStructs2seq() for that! if gCallableInfoGetCallerOwns(minfo) != GITransfer.NOTHING: methodBuffer.writeLine(" g_list_free(resul0)") # only free the list itself, the elements are moved to the seq else: if ngrRet.infoType == GIInfoType.OBJECT or ngrRet.infoType == GIInfoType.INTERFACE: if ngrRet.infoType != GIInfoType.INTERFACE: assert findFreeObject(gTypeInfoGetInterface(gTypeInfoGetParamType(ret2, 0))).len == 0 methodBuffer.writeLine(" result = glistObjects2seq($1, $2, $3)" % [ngrRet.childName, sym & pars.arglist, $elTransferFull]) elif ngrRet.infoType == GIInfoType.STRUCT: if gBaseInfoGetName(gTypeInfoGetInterface(gTypeInfoGetParamType(ret2, 0))) in ["Atom"]:##notin ["Atom", "Variant", "TimedValue"]: # care later methodBuffer.writeLine(" result = glistStructs2seq[$1]($2, $3)" % [ngrRet.childName, sym & pars.arglist, $(gCallableInfoGetCallerOwns(minfo) != GITransfer.EVERYTHING)]) # caution TimedValue is a "light" entity, so we need a different glistStructs2seq() for that! else: methodBuffer.writeLine(" discard") else: methodBuffer.writeLine(" discard") if gCallableInfoGetCallerOwns(minfo) != GITransfer.NOTHING: methodBuffer.writeLine(" g_list_free(resul0)") # only free the list itself, the elements are moved to the seq assert(gCallableInfoGetCallerOwns(minfo) in {GITransfer.EVERYTHING, GITransfer.NOTHING, GITransfer.CONTAINER}) elif ngrRet.res == gslist: var elTransferFull = gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING if gCallableInfoCanThrowGerror(minfo) or gCallableInfoMayReturnNull(minfo) or gCallableInfoGetCallerOwns(minfo) != GITransfer.NOTHING: methodBuffer.writeLine(" let resul0 = " & sym & pars.arglist) checkForGerror() if gCallableInfoMayReturnNull(minfo): methodBuffer.writeLine(" if resul0.isNil:") methodBuffer.writeLine(" return") if ngrRet.infoType == GIInfoType.OBJECT or ngrRet.infoType == GIInfoType.INTERFACE: methodBuffer.writeLine(" result = gslistObjects2seq($1, resul0, $2)" % [ngrRet.childName, $elTransferFull]) if ngrRet.infoType == GIInfoType.STRUCT: if gBaseInfoGetName(gTypeInfoGetInterface(gTypeInfoGetParamType(ret2, 0))) notin ["Atom", "Variant"]: # care later methodBuffer.writeLine(" result = gslistStructs2seq[$1](resul0, $2)" % [ngrRet.childName, $( gCallableInfoGetCallerOwns(minfo) != GITransfer.EVERYTHING)]) if gCallableInfoGetCallerOwns(minfo) != GITransfer.NOTHING: methodBuffer.writeLine(" g_slist_free(resul0)") # only free the list itself, the elements are moved to the seq else: if ngrRet.infoType == GIInfoType.OBJECT or ngrRet.infoType == GIInfoType.INTERFACE: if ngrRet.infoType != GIInfoType.INTERFACE: assert findFreeObject(gTypeInfoGetInterface(gTypeInfoGetParamType(ret2, 0))).len == 0 methodBuffer.writeLine(" result = gslistObjects2seq($1, $2, $3)" % [ngrRet.childName, sym & pars.arglist, $elTransferFull]) else: methodBuffer.writeLine(" discard") assert(gCallableInfoGetCallerOwns(minfo) in {GITransfer.EVERYTHING, GITransfer.NOTHING, GITransfer.CONTAINER}) elif ngrRet.flags.contains(RecResFlag.unamedA) and ngrRet.res == intAX: # https://discourse.gnome.org/t/g-key-file-get-integer-list-transfer-container/4729 # for fundamental types GITransfer.EVERYTHING and GITransfer.CONTAINER are equivalent var co = gCallableInfoGetCallerOwns(minfo) assert ngrRet.flags.contains(RecResFlag.array) if gCallableInfoCanThrowGerror(minfo) or gCallableInfoMayReturnNull(minfo) or co in {GITransfer.EVERYTHING, CONTAINER}: methodBuffer.writeLine(" let resul0 = " & sym & pars.arglist) checkForGerror() if gCallableInfoMayReturnNull(minfo): methodBuffer.writeLine(" if resul0.isNil:") methodBuffer.writeLine(" return") methodBuffer.writeLine(" result = $1ToSeq(resul0, $2.int)" % [fixedName2(ngrRet.name00), pars.blex]) else: methodBuffer.writeLine(" result = $1ToSeq($3, $2.int)" % [fixedName2(ngrRet.name00), pars.blex, sym & pars.arglist]) assert(co in {GITransfer.EVERYTHING, CONTAINER, NOTHING}) if co in {GITransfer.EVERYTHING, CONTAINER}: methodBuffer.writeLine(" cogfree(resul0)") elif ngrRet.flags.contains(RecResFlag.unamedA) and ngrRet.res == intA0: assert ngrRet.flags.contains(RecResFlag.array) if gCallableInfoCanThrowGerror(minfo) or gCallableInfoMayReturnNull(minfo) or gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING: methodBuffer.writeLine(" let resul0 = " & sym & pars.arglist) checkForGerror() if gCallableInfoMayReturnNull(minfo): methodBuffer.writeLine(" if resul0.isNil:") methodBuffer.writeLine(" return") methodBuffer.writeLine(" result = $1ZT2seq(resul0)" % [unCaped(fixedName2(ngrRet.name))]) else: methodBuffer.writeLine(" result = $1ZT2seq($2)" % [unCaped(fixedName2(ngrRet.name)), sym & pars.arglist]) assert(gCallableInfoGetCallerOwns(minfo) in {GITransfer.EVERYTHING, GITransfer.NOTHING, GITransfer.CONTAINER}) if gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING: methodBuffer.writeLine(" cogfree(resul0)") elif isString(ret2): if gCallableInfoCanThrowGerror(minfo) or gCallableInfoMayReturnNull(minfo) or gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING: methodBuffer.writeLine(" let resul0 = " & sym & pars.arglist) checkForGerror() if gCallableInfoMayReturnNull(minfo): methodBuffer.writeLine(" if resul0.isNil:") methodBuffer.writeLine(" return") methodBuffer.writeLine(" result = $resul0") else: methodBuffer.writeLine(" result = $" & sym & pars.arglist) assert(gCallableInfoGetCallerOwns(minfo) in {GITransfer.EVERYTHING, GITransfer.NOTHING}) if gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING: methodBuffer.writeLine(" cogfree(resul0)") elif RecResFlag.namedA in ngrRet.flags: assert ngrRet.flags.contains(RecResFlag.array) let h = ngrRet.name00 if gCallableInfoCanThrowGerror(minfo) or gCallableInfoMayReturnNull(minfo) or gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING: methodBuffer.writeLine(" let resul0 = " & sym & pars.arglist) checkForGerror() if gCallableInfoMayReturnNull(minfo): methodBuffer.writeLine(" if resul0.isNil:") methodBuffer.writeLine(" return") methodBuffer.writeLine(" result = $1ToSeq(resul0, $2_00.int)" % [fixedName2(h.replace("00")).unCap, pars.blex]) else: methodBuffer.writeLine(" result = $1ToSeq($3, $2_00.int)" % [fixedName2(h.replace("00")).unCap, pars.blex, sym & pars.arglist]) assert(gCallableInfoGetCallerOwns(minfo) in {GITransfer.EVERYTHING, GITransfer.NOTHING}) if gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING: methodBuffer.writeLine(" cogfree(resul0)") #elif (pars.replist.len > 0 or gCallableInfoCanThrowGerror(minfo)) and ngrRet.name != "void" or pars.tmpoutgobjectarg.len != 0: elif (pars.replist.len > 0 or gCallableInfoCanThrowGerror(minfo) or pars.tmpoutgobjectarg.len != 0) and ngrRet.name != "void": # caution dragons like g_key_file_get_locale_string_list() if gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING: discard # echo "Untamed dragon: ", sym if gCallableInfoCanThrowGerror(minfo) or gCallableInfoMayReturnNull(minfo) or gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING: methodBuffer.writeLine(" let resul0 = " & sym & pars.arglist) checkForGerror() if gCallableInfoMayReturnNull(minfo): methodBuffer.writeLine(" if resul0.isNil:") methodBuffer.writeLine(" return") methodBuffer.write(" result = ") if needTypeConv(ngrRet.name, ngrRet): methodBuffer.writeLine(doCt3nt(ngrRet.name, ngrRet) & '(' & "resul0" & ')') else: methodBuffer.writeLine("resul0") else: methodBuffer.write(" result = ") if needTypeConv(ngrRet.name, ngrRet): methodBuffer.writeLine(doCt3nt(ngrRet.name, ngrRet) & '(' & sym & pars.arglist & ')') else: methodBuffer.writeLine(sym & pars.arglist) elif needTypeConv(ngrRet.name, ngrRet): if gCallableInfoCanThrowGerror(minfo) or gCallableInfoMayReturnNull(minfo) or gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING: methodBuffer.writeLine(" let resul0 = " & sym & pars.arglist) checkForGerror() # if gCallableInfoMayReturnNull(minfo): # see https://discourse.gnome.org/t/gtk-selection-data-get-uris-null-result/8867 if gCallableInfoMayReturnNull(minfo) or ngrRet.flags.contains(RecResFlag.array): methodBuffer.writeLine(" if resul0.isNil:") methodBuffer.writeLine(" return") if ngrRet.name == "ptr cstring" and ngrRet.flags.contains(RecResFlag.array) and gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING: methodBuffer.writeLine(" result = cstringArrayToSeq(resul0)") methodBuffer.writeLine(" g_strfreev(resul0)") else: methodBuffer.writeLine(" " & doCt3nt(ngrRet.name, ngrRet) & '(' & "resul0" & ')') else: if nilArgFix.len > 0 or pars.tempResFree != "": # ugly, do we have a better test for this case #if ngrRet.name != "void": methodBuffer.writeLine(" result = " & doCt3nt(ngrRet.name, ngrRet) & '(' & sym & pars.arglist & ')') else: methodBuffer.writeLine(" " & doCt3nt(ngrRet.name, ngrRet) & '(' & sym & pars.arglist & ')') checkForGerror() # i.e. for nice_agent_set_remote_candidates, free GSList else: if gCallableInfoCanThrowGerror(minfo) and ngrRet.name != "void": assert false methodBuffer.writeLine(" let resul0 = " & sym & pars.arglist) elif pars.tempResFree.len > 0 and ngrRet.name != "void": methodBuffer.writeLine(" result = " & sym & pars.arglist) # aha else: methodBuffer.writeLine(" " & sym & pars.arglist) # aha checkForGerror() if gCallableInfoCanThrowGerror(minfo) and ngrRet.name != "void": assert false methodBuffer.writeLine(" resul0 #####") for k, v in pars.replist: if v[1].flags.contains(RecResFlag.unamedA): assert v[1].flags.contains(RecResFlag.array) methodBuffer.writeLine(" $1.setLen($2)" % [k, pars.blex]) methodBuffer.writeLine(" copyMem(unsafeaddr $1[0], $1_00, $2.int * sizeof($1[0]))" % [k.strip(chars = {'`'}), pars.blex]) methodBuffer.writeLine(" cogfree($1_00)" % [k.strip(chars = {'`'})]) elif RecResFlag.namedA in v[1].flags: assert v[1].flags.contains(RecResFlag.array) methodBuffer.writeLine(" $1 = $2($3_00, $4)" % [k, doCt3nt(v[0], v[1]), k.strip(chars = {'`'}), pars.blex]) else: if v[1].optOut: methodBuffer.writeLine(" if $1.addr != nil:" % [k, doCt3nt(v[0], v[1]), k.strip(chars = {'`'})]) methodBuffer.writeLine(" $1 = $2($3_00)" % [k, doCt3nt(v[0], v[1]), k.strip(chars = {'`'})]) else: methodBuffer.writeLine(" $1 = $2($3_00)" % [k, doCt3nt(v[0], v[1]), k.strip(chars = {'`'})]) # BLOCKMARK8 else: # } end of large proxy block BLOCK7 asym = fixedProcNames.getOrDefault(sym, asym) pars = genPars(mInfo, false, info, tryOut2Ret = tryOut2Ret) if asym != "errorQuark" and asym != "getPlugin" and asym != "quark": methodBuffer.write("\nproc " & asym & EM & pars.plist) methodBuffer.writeLine(" {.\n importc: \"", sym, "\", ", libprag, ".}") for n in nilArgFix: # https://github.com/StefanSalewski/gintro/issues/158 methodBuffer.writeLine(" if $1 != nil and $1.impl == nil:" % n) methodBuffer.writeLine(" $1.ignoreFinalizer = true" % n) methodBuffer.writeLine(" $1 = nil" % n) if pars.tmpoutgobjectarg.len != 0: methodBuffer.writeLine("# dothemagic(" & pars.outgobjectargname) dothegobjectargmagic() if info != nil and (gBaseInfoGetType(info) == GIInfoType.UNION or gBaseInfoGetType(info) == GIInfoType.STRUCT) and gCallableInfoGetNArgs(minfo) == (if gCallableInfoIsMethod(minfo): 0 else: 1): #if not callerAlloc.contains(modulenamespace & '.' & $gBaseInfoGetName(info)) and (asym == "free" or asym == "unref"): if not callerAlloc.contains(modulenamespace & '.' & $gBaseInfoGetName(info)) and (asym == "free" or asym == "unref" or asym == "destroy"): # v0.8.6 methodBuffer.writeLine("\nproc finalizer" & asym & EM & "(self: $1) =" % [$gBaseInfoGetName(info)]) methodBuffer.writeLine(" if not self.ignoreFinalizer:") if gTypeInfoGetTag(ret2) != GITypeTag.VOID: # i.e. gst_sdp_media_free() methodBuffer.writeLine(" discard " & sym & "(self.impl)") else: #"(cast[ptr " & manglename(gBaseInfoGetName(binfo)) & "00](" #methodBuffer.writeLine(" " & sym & "(self.impl)") methodBuffer.writeLine(" " & sym & "(cast[ptr " & manglename(gBaseInfoGetName(info)) & "00](self.impl))") if sym == "gtk_window_set_default_size": methodBuffer.writeLine("\nproc `defaultSize=`*(self: Window; dim: tuple[width: int; height: int]) =") methodBuffer.writeLine(" gtk_window_set_default_size(cast[ptr Window00](self.impl), int32(dim[0]), int32(dim[1]))") if sym == "g_object_unref": # methodBuffer.writeLine("\nproc genericGObjectUnref*[T](self: ref T) =") # we do not really need generics here methodBuffer.writeLine("\nproc genericGObjectUnref*(self: Object) =") methodBuffer.writeLine(" if not self.ignoreFinalizer:") methodBuffer.writeLine(" g_object_unref(cast[ptr Object00](self.impl))") if info != nil and gBaseInfoGetType(info) == GIInfoType.Object and gObjectInfoGetFundamental(info) == GTrue and sym.endsWith("unref"): assert false when false: # we can not use baseName, we have to use generics. var parent = info while true: let h = g_object_info_get_parent(parent) if h == nil: break parent = h let baseName = $gBaseInfoGetName(parent) methodBuffer.writeLine("\nproc generic_$1*[T](self: ref T) =" % [sym]) # methodBuffer.writeLine("\nproc generic_$1*(self: $2) =" % [sym, baseName]) # we can not avoid generics here methodBuffer.writeLine(" if not self.ignoreFinalizer:") # methodBuffer.writeLine(" $1(cast[ptr Object00](self.impl))" % [sym]) # we do not need that cast! methodBuffer.writeLine(" $1(self.impl)" % [sym]) if useTempProcessedFunctions: tempProcessedFunctions.add(sym) except UndefEx: processedFunctions.excl(sym) delayedMethods.add((info, minfo)) methodBuffer.cut(p) template genBoxedFree = if not callerAlloc.contains(($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName(info))): if gRegisteredTypeInfoGetGType(info) != G_TYPE_NONE and gTypeFundamental(gRegisteredTypeInfoGetGType(info)) == G_TYPE_BOXED and gBaseInfoGetName(info) != "VariantType": # we have no g_variant_type_get_gtype # For example, GVariant has a GType but is not a boxed type #assert(g_type_fundamental(g_registered_type_info_get_g_type(info)) == G_TYPE_BOXED) if gTypeFundamental(gRegisteredTypeInfoGetGType(info)) != G_TYPE_BOXED: assert false if gBaseInfoGetName(info) != "Variant": #echo moduleNamespace, gBaseInfoGetName(info) assert false output.writeLine("\nproc gBoxedFree" & $gRegisteredTypeInfoGetTypeName(info) & "*(self: " & mangleName(gBaseInfoGetName( info)) & ") =") if moduleNameSpace == "cairo": # we may manually free cairo objects! output.writeLine(" if not self.ignoreFinalizer and self.impl != nil:") output.writeLine(" boxedFree(", getTypeProc, "(), ", "cast[ptr " & mangleName(gBaseInfoGetName(info)) & "00](self.impl))") output.writeLine(" self.impl = nil") else: output.writeLine(" if not self.ignoreFinalizer:") output.writeLine(" boxedFree(", getTypeProc, "(), ", "cast[ptr " & mangleName(gBaseInfoGetName(info)) & "00](self.impl))") #output.writeLine("\nwhen compileOption(\"gc\", \"arc\"):") # the when is not really needed, currently default gc ignores destructor output.writeLine("\nwhen defined(gcDestructors):") output.writeLine(" proc `=destroy`*(self: var typeof(" & mangleName(gBaseInfoGetName(info)) & "()[])) =") output.writeLine(" when defined(gintroDebug):") output.writeLine(" echo \"destroy \", $typeof(self), ' ', cast[int](unsafeaddr self)") output.writeLine(" if not self.ignoreFinalizer and self.impl != nil:") output.writeLine(" boxedFree(", getTypeProc, "(), ", "cast[ptr " & mangleName(gBaseInfoGetName(info)) & "00](self.impl))") output.writeLine(" self.impl = nil") # CAUTION: newWithFinalizer() seems to be rarely used, can we remove it fully? output.writeLine("\nproc newWithFinalizer*(x: var " & mangleName(gBaseInfoGetName(info)) & ") =") output.writeLine(" when defined(gcDestructors):") output.writeLine(" new(x)") output.writeLine(" else:") output.writeLine(" new(x, gBoxedFree" & $gRegisteredTypeInfoGetTypeName(info) & ")") else: if gBaseInfoGetType(info) == GIInfoType.UNION or gBaseInfoGetType(info) == GIInfoType.STRUCT and gBaseInfoGetName(info) != "ObjectClass" and gBaseInfoGetName(info) != "TypeFind": var freeMe: GIFunctionInfo if gBaseInfoGetType(info) == GIInfoType.UNION: freeMe = gUnionInfoFindMethod(info, "free") if freeMe.isNil: freeMe = gUnionInfoFindMethod(info, "unref") else: #if gStructInfoIsGtypeStruct(info) and gBaseInfoGetName(info) != "ObjectClass": assert gBaseInfoGetType(info) == GIInfoType.STRUCT freeMe = gStructInfoFindMethod(info, "free") if freeMe.isNil: freeMe = gStructInfoFindMethod(info, "unref") template genDestroyFreeUnref = if not callerAlloc.contains(($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName(info))): if gRegisteredTypeInfoGetGType(info) == G_TYPE_NONE or gTypeFundamental(gRegisteredTypeInfoGetGType(info)) != G_TYPE_BOXED or gBaseInfoGetName(info) == "VariantType" or gBaseInfoGetName(info) == "Atom": # we have no g_variant_type_get_gtype if gBaseInfoGetType(info) == GIInfoType.UNION or gBaseInfoGetType(info) == GIInfoType.STRUCT and gBaseInfoGetName(info) != "ObjectClass" and gBaseInfoGetName(info) != "TypeFind": var freeMe: GIFunctionInfo if gBaseInfoGetType(info) == GIInfoType.UNION: freeMe = gUnionInfoFindMethod(info, "free") if freeMe.isNil: freeMe = gUnionInfoFindMethod(info, "unref") else: assert gBaseInfoGetType(info) == GIInfoType.STRUCT freeMe = gStructInfoFindMethod(info, "free") if freeMe.isNil: freeMe = gStructInfoFindMethod(info, "unref") if freeMe.isNil: freeMe = gStructInfoFindMethod(info, "destroy") # pango, new in v0.8.5 if freeMe != nil and gCallableInfoGetNArgs(freeMe) == (if gCallableInfoIsMethod(freeMe): 0 else: 1): # methodBuffer.writeLine("\nwhen compileOption(\"gc\", \"arc\"):") methodBuffer.writeLine("\nwhen defined(gcDestructors):") methodBuffer.writeLine(" proc `=destroy`*(self: var typeof(" & mangleName(gBaseInfoGetName(info)) & "()[])) =") methodBuffer.writeLine(" when defined(gintroDebug):") methodBuffer.writeLine(" echo \"destroy \", $typeof(self), ' ', cast[int](unsafeaddr self)") methodBuffer.writeLine(" if not self.ignoreFinalizer and self.impl != nil:") if gTypeInfoGetTag(xret2) == GITypeTag.VOID: methodBuffer.writeLine(" $1(self.impl)" % [$gFunctionInfoGetSymbol(freeMe)]) else: methodBuffer.writeLine(" discard $1(self.impl)" % [$gFunctionInfoGetSymbol(freeMe)]) methodBuffer.writeLine(" self.impl = nil") if freeMe != nil and gCallableInfoGetNArgs(freeMe) == (if gCallableInfoIsMethod(freeMe): 0 else: 1): # new in v0.8.5 # CAUTION: newWithFinalizer() seems to be rarely used, can we remove it fully? methodBuffer.writeLine("\nproc newWithFinalizer*(x: var " & mangleName(gBaseInfoGetName(info)) & ") =") methodBuffer.writeLine(" when defined(gcDestructors):") methodBuffer.writeLine(" new(x)") methodBuffer.writeLine(" else:") # methodBuffer.writeLine(" new(x, $1)" % [$gBaseInfoGetName(freeMe)]) methodBuffer.writeLine(" new(x, finalizer$1)" % [$gBaseInfoGetName(freeMe)]) # for v0.8.6 else: # new for v0.9.7: create dummy newWithFinalizer() for GdkAtom, as there is no free() if $gBaseInfoGetName(info) in ["Atom"]: # actually we need only this one methodBuffer.writeLine("\nproc newWithFinalizer*(x: var " & mangleName(gBaseInfoGetName(info)) & ") =") methodBuffer.writeLine(" new(x)") template writeGetTypeProc = var getTypeProc {.inject.}: string if gRegisteredTypeInfoGetGType(info) != G_TYPE_NONE: getTypeProc = $gRegisteredTypeInfoGetTypeInit(info) if getTypeProc notin ["intern", "g_gstring_get_type"]: var lp = "libprag" if moduleNamespace == "glib": # and getTypeProc != "g_variant_get_type": lp = "gobjectlibprag" output.write("\nproc " & getTypeProc & "*(): GType ") output.writeLine("{.importc, $1.}" % [lp]) proc writeUnion(info: GIUnionInfo) = #if gStructInfoIsGtypeStruct(info) and gBaseInfoGetName(info) != "ObjectClass": # return # we should not need the class and interface structs #if gBaseInfoGetName(info).endsWith("Private"): # since v0.5.3 we do not write private structs # return #output.writeLine("") if not suppressType: output.writeLine("type") if callerAlloc.contains(($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName(info))): output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & EM & " {.pure, byRef, union.} = object") else: output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & "00" & EM & " {.pure, union.} = object") if WriteFields or callerAlloc.contains(($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName(info))): for j in 0.cint ..< info.gUnionInfoGetNFields(): let field = info.gUnionInfoGetField(j) let name = manglename(gBaseInfoGetName(field)) & EM let t = gFieldInfoGetType(field) output.writeLine(" ", name, ": ", newGenRec(t).name) if not callerAlloc.contains(($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName(info))): output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & EM & " = ref object") output.writeLine(" impl*: ptr " & mangleName(gBaseInfoGetName(info)) & "00") output.writeLine(" ignoreFinalizer*: bool") writeGetTypeProc() genBoxedFree() var mseq: seq[GIFunctionInfo] var freePos = -1 for j in 0.cint ..< gUnionInfoGetNMethods(info): mseq.add(gUnionInfoGetMethod(info, j)) if freePos < 0 and gBaseInfoGetName(gUnionInfoGetMethod(info, j)) in ["free", "unref"]: #assert false executed for gtk3 freePos = j if freePos > 0: swap(mseq[0], mseq[freePos]) for i, mInfo in mseq: writeMethod(info, minfo) if i == 0: let xret2 = gCallableInfoGetReturnType(minfo) genDestroyFreeUnref() const TargetEntryProx = """ proc seq2TargetEntryArray(s: openarray[TargetEntry]; a: var cstringArray): ptr TargetEntry00 = assert s.high < $1 let x = cast[ptr UncheckedArray[ptr TargetEntry00]](a) for i, o in s: x[i] = o.impl return cast[ptr TargetEntry00](x) proc newTargetEntry*(target: cstring; flags: int; info: int): TargetEntry proc priv_target_table_free(targets: ptr TargetEntry00; nTargets: int32) {.importc: "gtk_target_table_free", libprag.} proc targetEntryArrayToSeq(s: ptr TargetEntry00; n: int): seq[TargetEntry] = let a = cast[ptr UncheckedArray[ptr TargetEntry00]](s) for i in 0 ..< n: result.add(newTargetEntry(a[i].target, a[i].flags.int, a[i].info.int)) priv_target_table_free(s, n.int32) """ % [$StringArrayEntries] const PageRangeProx = """ proc seq2PageRangeArray(s: openarray[PageRange]; a: var cstringArray): ptr PageRange = assert s.high < $1 let x = cast[ptr UncheckedArray[ptr PageRange]](a) for i in 0 .. s.high: x[i] = unsafeaddr(s[i]) return cast[ptr PageRange](x) proc pageRangeArrayToSeq(s: ptr PageRange; n: int): seq[PageRange] = let a = cast[ptr UncheckedArray[ptr PageRange]](s) for i in 0 ..< n: result.add(a[i][]) cogfree(s) """ % [$StringArrayEntries] const KeymapKeyProx = """ proc seq2KeymapKeyArray(s: openarray[KeymapKey]; a: var cstringArray): ptr KeymapKey = assert s.high < $1 let x = cast[ptr UncheckedArray[ptr KeymapKey]](a) for i in 0 .. s.high: x[i] = unsafeaddr(s[i]) return cast[ptr KeymapKey](x) proc keymapKeyArrayToSeq(s: ptr KeymapKey; n: int): seq[KeymapKey] = let a = cast[ptr UncheckedArray[ptr KeymapKey]](s) for i in 0 ..< n: result.add(a[i][]) cogfree(s) """ % [$StringArrayEntries] proc writeStruct(info: GIStructInfo) = if gBaseInfoGetName(info) in ["_ContextMenu", "_ContextMenuItem"]: return # WebKit2WebExtension-4.0.gir bug if gStructInfoIsGtypeStruct(info) and gBaseInfoGetName(info) != "ObjectClass": return # we should not need the class and interface structs if gBaseInfoGetName(info).endsWith("Private"): # since v0.5.3 we do not write private structs return output.writeLine("") if not suppressType: output.writeLine("type") if mangleName(gBaseInfoGetName(info)) in someEvent: output.writeLine(" " & mangleName(gBaseInfoGetName(info)) & "00" & EM & " = Event00") output.writeLine(" " & mangleName(gBaseInfoGetName(info)) & EM & " = Event") return # https://github.com/StefanSalewski/gintro/issues/176 if gBaseInfoGetName(info) == "Rectangle" and moduleNamespace == "cairo": cairoProvidesRectangle = true if gBaseInfoGetName(info) == "Address" and moduleNamespace == "nice": #import nativesockets # See https://gitlab.freedesktop.org/libnice/libnice/-/blob/master/agent/address.h output.writeLine(" Address* {.pure, byRef, union.} = object") output.writeLine(" `addr`*: SockAddr") output.writeLine(" ip4*: Sockaddr_in") output.writeLine(" ip6*: Sockaddr_in6") elif callerAlloc.contains(($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName(info))): output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & EM & " {.pure, byRef.} = object") else: output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & "00" & EM & " {.pure.} = object") if WriteFields or callerAlloc.contains(($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName( info))) or mangleName(gBaseInfoGetName(info)) == "TargetEntry" or ["gst.Message", "gst.MiniObject", "glib.List", "pango.Attribute", "nice.Address", "nice.Candidate"].contains(( $gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName(info))): #if gBaseInfoGetName(info) == "Address": # echo "kkk", info.gStructInfoGetNFields() for j in 0.cint ..< info.gStructInfoGetNFields(): let field = info.gStructInfoGetField(j) let name = manglename(gBaseInfoGetName(field)) & EM let t = gFieldInfoGetType(field) output.writeLine(" ", name, ": ", newGenRec(t).name) # let tag = gTypeInfoGetTag(t) # XXX: gFieldInfoGetSize() is always zero! #if typeTagIsBasic(tag): # echo "XXXXXXXXXXXXX", gFieldInfoGetOffset(field) # echo "XXXXXXXXXXXXX", gFieldInfoGetSize(field) #if mangleName(gBaseInfoGetName(info)) != "TextIter": if not callerAlloc.contains(($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName(info))): if moduleNameSpace == "cairo": # see https://forum.nim-lang.org/t/8309 output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & EM & " = ref object of RootRef") else: output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & EM & " = ref object") output.writeLine(" impl*: ptr " & mangleName(gBaseInfoGetName(info)) & "00") output.writeLine(" ignoreFinalizer*: bool") writeGetTypeProc() genBoxedFree() var mseq: seq[GIFunctionInfo] var freePos = -1 for j in 0.cint ..< gStructInfoGetNMethods(info): mseq.add(gStructInfoGetMethod(info, j)) if freePos < 0 and gBaseInfoGetName(gStructInfoGetMethod(info, j)) in ["free", "unref"]: freePos = j if freePos < 0: for j in 0.cint ..< gStructInfoGetNMethods(info): if freePos < 0 and gBaseInfoGetName(gStructInfoGetMethod(info, j)) in ["destroy"]: # add destroy for v0.8.5 freePos = j if freePos > 0: swap(mseq[0], mseq[freePos]) if mangleName(gBaseInfoGetName(info)) == "List" and moduleNamespace == "glib": output.writeLine("\nproc g_list_free*(list: ptr glib.List) {.importc: \"g_list_free\", libprag.}") output.writeLine("\nproc g_list_prepend*(list: ptr glib.List; data: pointer): ptr glib.List {.importc: \"g_list_prepend\", libprag.}") if mangleName(gBaseInfoGetName(info)) == "SList" and moduleNamespace == "glib": output.writeLine("\nproc g_slist_free*(list: ptr glib.SList) {.importc: \"g_slist_free\", libprag.}") output.writeLine("\nproc g_slist_prepend*(list: ptr glib.SList; data: pointer): ptr glib.SList {.importc: \"g_slist_prepend\", libprag.}") if mangleName(gBaseInfoGetName(info)) == "TargetEntry": # assert false executed for gtk3 output.writeLine(TargetEntryProx) if mangleName(gBaseInfoGetName(info)) == "KeymapKey": output.writeLine(KeymapKeyProx) if mangleName(gBaseInfoGetName(info)) == "PageRange": output.writeLine(PageRangeProx) if gBaseInfoGetName(info) == "Variant" and moduleNamespace == "glib": # make it available early output.writeLine("\nproc g_variant_ref_sink(self: ptr Variant00): ptr Variant00 {.importc, libprag.}") for i, mInfo in mseq: writeMethod(info, minfo) if i == 0: let xret2 = gCallableInfoGetReturnType(minfo) genDestroyFreeUnref() template writeSignal() = #echo gBaseInfoGetName(signalInfo), gCallableInfoGetNArgs(signalInfo), gTypeInfoGetTag(zzzu) if gCallableInfoGetNArgs(signalInfo) > 0 or gTypeInfoGetTag(zzzu) != GITypeTag.VOID: #echo "aaa", gBaseInfoGetName(signalInfo) var memo = "" memo.addInt(gCallableInfoGetNArgs(signalInfo)) memo.add(RecSep) var plist, arglist: string var replist: TableRef[string, (string, RecRes)] (plist, arglist, replist) = genPars(signalInfo, true, info, genArrayMark = true, modPrefix = true) memo.add(plist) memo.add(RecSep) (plist, arglist, replist) = genPars(signalInfo, false, info, genArrayMark = true, modPrefix = true) memo.add(plist) memo = memo.replace("\n ", " ") memo = memo.replace("\"", "\\\"") if moduleNamespace == "gtk" or moduleNamespace == "gdk" or moduleNamespace == "gdkX11" or moduleNamespace == "gtksource": if ISGTK3: supmod3.writeLine(" \"" & ($gBaseInfoGetName(signalInfo)).replace("-", "_") & RecSep & $gBaseInfoGetQualifiedName(info, true) & RecSep & memo & "\",") else: supmod4.writeLine(" \"" & (gBaseInfoGetName(signalInfo)).replace("-", "_") & RecSep & $gBaseInfoGetQualifiedName(info, true) & RecSep & memo & "\",") else: supmod3.writeLine(" \"" & ($gBaseInfoGetName(signalInfo)).replace("-", "_") & RecSep & $gBaseInfoGetQualifiedName(info, true) & RecSep & memo & "\",") supmod4.writeLine(" \"" & ($gBaseInfoGetName(signalInfo)).replace("-", "_") & RecSep & $gBaseInfoGetQualifiedName(info, true) & RecSep & memo & "\",") if gCallableInfoGetNArgs(signalInfo) > 0: h = h.replace(")", "; xdata: pointer)") else: h = h.replace(")", "xdata: pointer)") var xxx = mangleName(gBaseInfoGetName(info)) let yyy = xxx if interfaceProvider.contains(xxx): let provider = interfaceProvider[xxx] for i in provider: discard mangleType(i) xxx = xxx & " | " & provider.join(" | ") signalbuffer.write("\nproc " & mangleName("sc_" & $gBaseInfoGetName(signalInfo)) & EM & "(self: " & xxx & "; ") if gCallableInfoGetNArgs(signalInfo) > 0 or gTypeInfoGetTag(zzzu) != GITypeTag.VOID: signalbuffer.writeLine(" p: proc (self: ptr " & yyy & "00; " & h & " {.cdecl.}, xdata: pointer, cf: gobject.ConnectFlags): culong =") else: signalbuffer.writeLine(" p: proc (self: ptr gobject.Object00; " & h & " {.cdecl.}, xdata: pointer, cf: gobject.ConnectFlags): culong =") signalbuffer.write(" g_signal_connect_data(self.impl, \"") signalbuffer.write($gBaseInfoGetName(signalInfo)) signalbuffer.writeLine("\", cast[GCallback](p), xdata, nil, cf)") proc writeInterface(info: GIInterfaceInfo) = if not suppressType: output.writeLine("type") # we made interfaces a gobject now... output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & "00" & EM & " = object of gobject.Object00") output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & EM & " = ref object of gobject.Object") let numsig = info.gInterfaceInfoGetNSignals for j in 0.cint ..< numsig: let signalInfo = gInterfaceInfoGetSignal(info, j) #let c = gSignalInfoGetClassClosure(signalInfo) #if not c.isNil: echo "maybe we should process class closures!" #if gBaseInfoGetName(signalInfo) == "notify": # continue # XXX fix later var h = genPars(signalInfo, false)[0][1..^1] let zzzu = gCallableInfoGetReturnType(signalinfo) writeSignal() for j in 0.cint ..< gInterfaceInfoGetNMethods(info): let mInfo = gInterfaceInfoGetMethod(info, j) writeMethod(info, minfo) # write a few of the strange enum sets proc writeModifierType(info: GIEnumInfo) = let we = gBaseInfoGetName(info) assert(we in ["ModifierType", "EventMask", "AccelFlags", "AttachOptions", "MessageType", "WindowHints", "IOCondition", "DragAction", "DestDefaults"]) type T = tuple[v: int64; n: string] var s: seq[T] var alias: seq[string] output.writeLine("type") for j in 0.cint ..< info.gEnumInfoGetNValues(): let value = info.gEnumInfoGetValue(j) var name = mangleName(gBaseInfoGetName(value)) name.removeSuffix("Mask") let v = gValueInfoGetValue(value) if bitops.popCount(v) == 1: s.add((v, name)) s.sort do (x, y: T) -> int: result = cmp(x.v, y.v) if result == 0: result = cmp(x.n, y.n) var tname = mangleName(gBaseInfoGetName(info)) if tname != "WindowHints": firstPart(tname) if we == "IOCondition": tname = "IOC" # as glib already has an IOFlags enum type output.writeLine(" ", tname & "Flag" & EM, " {.size: sizeof(cint), pure.} = enum") if s[0].v != 0 and s[0].v != 1: # flags may start with none = 0 or with flag1 = 1 output.writeLine(" ignoreThisDummyValue = 0") # Nim needs start with 0 for these low level sets var k: T for j in 0 .. s.high: let i = s[j] var val = i.v if j == 0 and val == 0: continue if j > 0 and i.v == k.v: assert false if i.n != k.n: alias.add(" " & tname & i.n.capitalizeAscii & EM & " = " & tname & '.' & k.n) continue val = countTrailingZeroBits(val) output.writeLine(" ", i.n, " = ", val) k = i if alias.len > 0: assert false output.writeLine("\nconst") for i in alias: output.writeLine(i) output.writeLine("\n ", we & EM, " {.size: sizeof(cint).} = set[$1Flag]" % [tname]) if we == "ModifierType": output.writeLine("\nconst ModifierMask* = {ModifierFlag.shift .. ModifierFlag.button5, ModifierFlag.super .. ModifierFlag.meta}") elif we == "EventMask": output.writeLine("\nconst AllEventsMask* = {EventFlag.exposure .. EventFlag.smoothScroll}") for j in 0.cint ..< gEnumInfoGetNMethods(info): let mInfo = gEnumInfoGetMethod(info, j) writeMethod(info, minfo) proc writeEnum(info: GIEnumInfo) = if mangleName(gBaseInfoGetName(info)) in ["ModifierType", "EventMask", "AccelFlags", "AttachOptions", "WindowHints", "IOCondition", "DragAction", "DestDefaults"] or (moduleNameSpace == "gst" and mangleName(gBaseInfoGetName(info)) == "MessageType"): writeModifierType(info) return type T = tuple[v: int64; n: string] var s: seq[T] var alias: HashSet[string] # double entry in gstvideo, see https://discourse.gnome.org/t/gstvideo-1-0-gir-double-entries/5442 var flags = ($gBaseInfoGetName(info)).endsWith("Flags") var flagDefault: string var lags: string output.writeLine("type") let n = info.gEnumInfoGetNValues() for j in 0.cint ..< n: let value = info.gEnumInfoGetValue(j) var name = mangleName(gBaseInfoGetName(value)) if name[0].isDigit: name = "enum" & name # gstvideo, see https://discourse.gnome.org/t/gstvideo-1-0-gir-double-entries/5442 let v = gValueInfoGetValue(value) s.add((v, name)) s.sort do (x, y: T) -> int: result = cmp(x.v, y.v) if result == 0: result = cmp(x.n, y.n) if not flags and s[^1].v > 2: flags = true for j in 0 .. s.high: # v0.9.9, pull in some more flags? if bitops.popCount(s[j].v) > 1: flags = false break for j in 0 .. s.high: if s[j].v < 0: flags = false # if j == 0 and s[j].v == 0: # wrong for GApplicationFlags for glib >= 2.74 if s[j].v == 0: continue if bitops.popCount(s[j].v) != 1: flags = false if s.len <= 1: flags = false var tname = mangleName(gBaseInfoGetName(info)) if flags and tname.endsWith("Flags"): tname = tname[0 .. ^6] lags = "Flags" if flags: output.writeLine(" ", tname & "Flag" & EM, " {.size: sizeof(cint), pure.} = enum") if s[0].v != 0 and s[0].v != 1: # flags may start with none = 0 or with flag1 = 1 output.writeLine(" ignoreThisDummyValue = 0") # Nim needs start with 0 for these low level sets else: output.writeLine(" ", tname & EM, " {.size: sizeof(cint), pure.} = enum") var k: T for j in 0 .. s.high: let i = s[j] var val = i.v if flags and j == 0 and val == 0: # proc c(t: typedesc[B]): B ={} flagDefault = (" " & tname & lags & i.n.capitalizeAscii & EM & " = " & tname & lags & "({})") flagDefault.add("\nproc " & i.n & "*(t: typedesc[" & tname & lags & "]): " & tname & lags & " = " & tname & lags & "({})") #echo flagDefault k = i continue if j > 0 and i.v == k.v: if i.n != k.n: let h = if flags: "Flag" else: "" var vv: string if flags and k.v == 0: vv = tname & lags & "({})" else: vv = tname & h & '.' & k.n alias.incl(" " & tname & i.n.capitalizeAscii & EM & " = " & vv) continue if flags: val = countTrailingZeroBits(val) # firstSetBit(val) output.writeLine(" ", i.n, " = ", val) k = i if flags: output.writeLine("\n ", tname & lags & EM, " {.size: sizeof(cint).} = set[$1Flag]" % [tname]) if alias.len > 0 or flagDefault.len > 0: output.writeLine("\nconst") for i in alias: output.writeLine(i) if flagDefault.len > 0: output.writeLine(flagDefault) for j in 0.cint ..< gEnumInfoGetNMethods(info): let mInfo = gEnumInfoGetMethod(info, j) writeMethod(info, minfo) proc writeObj(info: GIObjectInfo) = if gBaseInfoGetName(info).endsWith("Private"): assert false return assert(gBaseInfoGetType(info) == GIInfoType.OBJECT) let class = gObjectInfoGetClassStruct(info) let parent = gObjectInfoGetParent(info) # nil for Object of module gobject! var pname: string var oof: string var ns: string var cnt: int if parent.isNil: #assert(gBaseInfoGetName(info) == "Object" or gBaseInfoGetName(info) == "ParamSpec") #echo "??? ", gBaseInfoGetName(info) oof = "{.inheritable, pure.} = object" ns = "" pname = "" cnt = 0 else: cnt = 1 oof = " = object of " pName = manglename(gBaseInfoGetName(parent)) if ct.hasKey(pname): cnt = ct[pname] ns = ($gBaseInfoGetNamespace(parent)).toLowerAscii if ns == moduleNamespace: ns = "" else: ns = fixedModName(ns) & '.' if ns == "gio." and gBaseInfoGetName(info) == "Application": # a few special cases for gtk.nim cnt = 9 if ns == "gio." and gBaseInfoGetName(info) == "MountOperation": cnt = 9 if ns == "gio." and gBaseInfoGetName(info) == "NumerableIcon": cnt = 9 if moduleNamespace == "gtksource" and gBaseInfoGetName(info) == "Buffer": cnt = 9 if moduleNamespace == "gtksource" and gBaseInfoGetName(info) == "Mark": cnt = 9 if moduleNamespace == "gtksource" and gBaseInfoGetName( info) == "CompletionInfo": cnt = 9 if moduleNamespace == "gtksource" and gBaseInfoGetName(info) == "View": cnt = 9 if not suppressType: output.writeLine("type") if ns == "" and pname != "": # check forward exeption for parent name! discard mangleType(pname) if mangleName(gBaseInfoGetName(info)) == "Object" and moduleNamespace == "gobject": discard elif parent.isNil: # this is new for v0.6.0 with gstreamer support output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & EM & " = ref object of RootRef") output.write(" impl*: ptr ") output.write(gBaseInfoGetName(info)) output.writeLine("00") output.writeLine(" ignoreFinalizer*: bool") #elif gBaseInfoGetName(info) == "ParamSpec": # output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & EM & " = ref object of RootRef") # output.writeLine(" impl*: ptr ParamSpec00") else: output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & EM & " = ref object of " & ns & pname) if pname != "": pname.add("00") output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & "00" & EM, oof, ns & $pname) assert not callerAlloc.contains(ns & '.' & manglename(gBaseInfoGetName(info))) if callerAlloc.contains(($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName(info))): assert false # echo ($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName(info)) assert not callerAlloc.contains(($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName(info))) when WriteFields: if mangleName(gBaseInfoGetName(info)) != "InitiallyUnowned": for j in 0.cint ..< info.gObjectInfoGetNFields(): let field = info.gObjectInfoGetField(j) var name = mangleName(gBaseInfoGetName(field)) if privStr.contains(name) and cnt > 0: renumber(name, cnt) else: name.add(EM) let t = gFieldInfoGetType(field) let h = newGenRec(t).name if j == 0 and parent != nil: continue output.writeLine(" ", name, ": ", h) if mangleName(gBaseInfoGetName(info)) == "Object" and moduleNamespace == "gobject": output.writeLine("type") output.writeLine(" GToggleNotify* = proc (data: pointer; obj: ptr Object00; isLastRef: gboolean) {.cdecl.}\n") output.writeLine("proc g_object_add_toggle_ref*(obj: ptr Object00; notify: GToggleNotify; data: pointer) {.") output.writeLine(" importc: \"g_object_add_toggle_ref\", libprag.}") output.writeLine("proc g_object_remove_toggle_ref*(obj: ptr Object00; notify: GToggleNotify; data: pointer) {.") output.writeLine(" importc: \"g_object_remove_toggle_ref\", libprag.}") output.writeLine("\nproc g_object_set_qdata*(self: ptr Object00; quark: uint32; p: pointer) {.") output.writeLine(" importc: \"g_object_set_qdata\", libprag.}") #proc getQdata*(self: Object; quark: int): pointer = # g_object_get_qdata(cast[ptr Object00](self.impl), uint32(quark)) #output.writeLine("\nproc setQdata*(self: Object; quark: int; p: pointer) =") #output.writeLine(" g_object_set_qdata(cast[ptr Object00](self.impl), uint32(quark), p)") output.writeLine("proc toggleNotify*(data: pointer; obj: ptr Object00; isLastRef: gboolean) {.cdecl.} =") output.writeLine(" if isLastRef.int == 0:") output.writeLine(" GC_ref(cast[RootRef](data))") output.writeLine(" else:") output.writeLine(" GC_unref(cast[RootRef](data))") output.writeLine("\nproc finalizeGObject*[T](o: ref T) =") output.writeLine(" g_object_set_qdata(o.impl, Quark, nil)") output.writeLine("\n if not o.ignoreFinalizer:") output.writeLine(" g_object_remove_toggle_ref(o.impl, toggleNotify, addr(o[]))") writeGetTypeProc() let numsig = info.gObjectInfoGetNSignals for j in 0.cint ..< numsig: let signalInfo = gObjectInfoGetSignal(info, j) let c = gSignalInfoGetClassClosure(signalInfo) if not c.isNil: echo "maybe we should process class closures!" if gBaseInfoGetName(signalInfo) == "notify": continue # XXX fix later var h = genPars(signalInfo, false)[0][1..^1] let zzzu = gCallableInfoGetReturnType(signalinfo) writeSignal() if class != nil and not allSyms.contains(mangleName(gBaseInfoGetName(class))): assert false classList.add(class) ct.inc($gBaseInfoGetName(info), cnt + 1) if gBaseInfoGetName(info) == "Object" and moduleNamespace == "gobject": output.writeLine("type\n Object* = ref object of RootRef") output.writeLine(" impl*: ptr Object00") output.writeLine(" ignoreFinalizer*: bool") output.writeLine("\nproc refCount*(o: gobject.Object): int =") output.writeLine(" let p = cast[ptr cuint](cast[int](o.impl) + sizeof(pointer))") output.writeLine(" return p[].int") output.writeLine("\nproc setQdata*(self: gobject.Object; quark: int; p: pointer) =") output.writeLine(" g_object_set_qdata(cast[ptr Object00](self.impl), uint32(quark), p)") if gObjectInfoGetFundamental(info) == GFalse: # guess work, ignore fake GObjects like GParamSpec and such #output.writeLine("\nwhen compileOption(\"gc\", \"arc\"):") #if not (mangleName(gBaseInfoGetName(info)) == "Window" and moduleNamespace == "gtk"): if not (mangleName(gBaseInfoGetName(info)) in ["Window", "ApplicationWindow"] and moduleNamespace == "gtk"): output.writeLine("\nwhen defined(gcDestructors):") output.writeLine(" proc `=destroy`*(self: var typeof(" & mangleName(gBaseInfoGetName(info)) & "()[])) =") output.writeLine(" when defined(gintroDebug):") output.writeLine(" echo \"destroy \", $typeof(self), ' ', cast[int](unsafeaddr self)") output.writeLine(" g_object_set_qdata(self.impl, Quark, nil)") output.writeLine(" if not self.ignoreFinalizer and self.impl != nil:") output.writeLine(" g_object_remove_toggle_ref(self.impl, toggleNotify, addr(self))") output.writeLine(" self.impl = nil") if gBaseInfoGetName(info) == "ParamSpec" and moduleNamespace == "gobject": ## for ParamSpec no unref proc is provided by gobject-introspection, and it asks for uref! #[ output.writeLine("\nproc g_param_spec_unref*(self: ptr ParamSpec00) {.") output.writeLine(" importc, libprag.}") output.writeLine("\nproc g_param_spec_uref*(self: ptr ParamSpec00) {.") output.writeLine(" importc: \"g_param_spec_unref\", libprag.}") output.writeLine("\nproc unref*(self: ParamSpec) =") output.writeLine(" g_param_spec_unref(cast[ptr ParamSpec00](self.impl))") output.writeLine("\nproc uref*(self: ParamSpec) =") output.writeLine(" g_param_spec_unref(cast[ptr ParamSpec00](self.impl))") output.writeLine("\nproc generic_g_param_spec_uref*(self: ParamSpec) =") output.writeLine(" g_param_spec_unref(cast[ptr ParamSpec00](self.impl))") ]# output.writeLine("\nproc g_param_spec_ref_sink*(self: ptr ParamSpec00): ptr ParamSpec00 {.") output.writeLine(" importc, libprag.}") if gBaseInfoGetType(info) == GIInfoType.Object and gObjectInfoGetFundamental(info) == GTrue: ## generate the destroy() for the non gobject objects assert(gObjectInfoGetFundamental(info) == GTrue) var parent = info while true: let h = g_object_info_get_parent(parent) if h == nil: break parent = h var freeMeName = $g_object_info_get_unref_function(parent) if freeMeName == "g_param_spec_uref": freeMeName = "g_param_spec_unref" if freeMeName != "": let n = mangleName(gBaseInfoGetName(info)) if true:#freeMeName != "g_param_spec_uref" and freeMeName != "g_param_spec_unref": # v0.9.8, latest gobject fixed name to unref output.writeLine("\nproc " & freeMeName & "*(self: ptr " & n & "00) {.importc, libprag.}") output.writeLine("\nproc generic_$1*(self: $2) =" % [freeMeName, n]) output.writeLine(" if not self.ignoreFinalizer:") output.writeLine(" $1(self.impl)" % [freeMeName]) output.writeLine("\nwhen defined(gcDestructors):") output.writeLine(" proc `=destroy`*(self: var typeof(" & mangleName(gBaseInfoGetName(info)) & "()[])) =") output.writeLine(" when defined(gintroDebug):") output.writeLine(" echo \"destroy \", $typeof(self), ' ', cast[int](unsafeaddr self)") output.writeLine(" if not self.ignoreFinalizer and self.impl != nil:") if n in ["ParamArray", "ParamFraction"]: output.writeLine(" $#(cast[ptr $#00](self.impl))" % [freeMeName, n]) else: output.writeLine(" $1(self.impl)" % [freeMeName]) output.writeLine(" self.impl = nil") for j in 0.cint ..< gObjectInfoGetNMethods(info): if gFunctionInfoGetSymbol(gObjectInfoGetMethod(info, j)) != freeMeName: writeMethod(info, gObjectInfoGetMethod(info, j)) else: for j in 0.cint ..< gObjectInfoGetNMethods(info): #if gFunctionInfoGetSymbol(gObjectInfoGetMethod(info, j)) != freeMeName: writeMethod(info, gObjectInfoGetMethod(info, j)) proc extractFromUnion(tag: GITypeTag; arg: GIArgumentObj): string = result = case tag: of GITypeTag.BOOLEAN: $arg.vBoolean of GITypeTag.INT8: $arg.vInt8 & "'i8" of GITypeTag.UINT8: $arg.vUint8 & "'u8" of GITypeTag.INT16: $arg.vInt16 & "'i16" of GITypeTag.UINT16: $arg.vUint16 & "'u16" of GITypeTag.INT32: $arg.vInt32 & "'i32" of GITypeTag.UINT32: $arg.vUint32 & "'u32" of GITypeTag.INT64: $arg.vInt64 & "'i64" of GITypeTag.UINT64: $arg.vUint64 & "'u64" of GITypeTag.FLOAT: $arg.vFloat & "'f32" of GITypeTag.DOUBLE: $arg.vDouble & "'f64" of GITypeTag.UTF8: '"' & $arg.vstring & '"' #of GITypeTag.FILENAME: $arg. #of GITypeTag.ARRAY: $arg. of GITypeTag.INTERFACE: """"INTERFCE (unsuported)"""" #of GITypeTag.GLIST: $arg. #of GITypeTag.GSLIST: $arg. #of GITypeTag.GHASH: $arg. #of GITypeTag.ERROR: $arg. #of GITypeTag.UNICHAR: $arg. else: "XXX" & $tag proc writeConst(info: GIConstantInfo) = var tg = "" var arg: GIArgumentObj let t = gConstantInfoGetType(info) let tag = gTypeInfoGetTag(t) discard gConstantInfoGetValue(info, addr(arg)) # TODO: we should check the size s! var str = extractFromUnion(tag, arg) if str == """"\"""": str = """"\\"""" var h = $gBaseInfoGetName(info) if h == "MODIFIER_MASK": return if h == "ATTR_INDEX_FROM_TEXT_BEGINNING": return # gint in gir, but should be guint if gBaseInfoGetNamespace(info) == "Soup": h.add("_STR") # too many name conflicts with enums! if h.replace("_", "").toLowerAscii == "keych": h.add(str[^5]) if gdkKeys.contains(h.toLowerAscii): var s = gdkKeys[h.toLowerAscii] if s.len > 1: if s.len == 2: if h == s[0]: tg = "U" elif h == s[1]: discard else: assert(false) elif s.len == 3: # eth and thorn if h == s[0]: tg = "X" elif h == s[2]: discard elif h == s[1]: tg = "U" else: assert(false) output.writeLine("const ", tg, h & EM, " = ", str) else: output.writeLine("const ", mangleName(h) & EM, " = ", str) proc processInfo(i: GIBaseInfo) = if not (isFunctionInfo(i) or gBaseInfoGetType(i) == GIInfoType.STRUCT): output.write("\n") if isCallableInfo(i): if isFunctionInfo(i): let s = $gFunctionInfoGetSymbol(i) if s[^1] != '_' and not processedFunctions.contains(s) and not s.contains("__") and s != "g_type_add_interface_dynamic" and s != "g_type_get_plugin" and s != "g_type_register_dynamic": writeMethod(nil, i) else: assert(isCallbackInfo(i)) if not suppressType: output.write("type\n") output.writeLine(" ", mangleName(gBaseInfoGetName(i)) & "* = proc " & genPars(i)[0] & " {.cdecl.}") elif gBaseInfoGetType(i) == GIInfoType.OBJECT: writeObj(i) elif gBaseInfoGetType(i) == GIInfoType.UNION: writeUnion(i) elif gBaseInfoGetType(i) == GIInfoType.INTERFACE: writeInterface(i) elif gBaseInfoGetType(i) == GIInfoType.STRUCT: writeStruct(i) elif isEnumInfo(i): writeEnum(i) elif gBaseInfoGetType(i) == GIInfoType.CONSTANT: writeConst(i) elif gBaseInfoGetType(i) == GIInfoType.Boxed: if $gBaseInfoGetName(i) notin ["TreeRowData", "ByteArray", "FileList"]: # hide ugly output for v0.8.7, investgate later echo "gBaseInfoGetType(i) == GIInfoType.Boxed: ", gBaseInfoGetName(i) # echo "++++++++ ", g_registered_type_info_get_g_type(i), g_registered_type_info_get_type_name(i) # assert false executed for gtk4 else: assert(false) const PRO = """ proc seq2cstringArray*(s: openarray[string]; a: var cstringArray): ptr cstring = assert s.high < $1 - 1 let x = cast[ptr UncheckedArray[string]](s) for i in 0 .. s.high: a[i] = addr(x[i][0]) a[s.len] = nil return cast[ptr cstring](a) """ % [$StringArrayEntries] const GTK_SOURCE_EPI = """ proc getView*(builder: Builder; name: string): View = let gt = g_type_from_name("GSource") assert(gt != g_type_invalid_get_type()) let gobj = gtk_builder_get_object(cast[ptr Builder00](builder.impl), name) assert(gobj != nil) if g_object_get_qdata(gobj, Quark) != nil: result = cast[type(result)](g_object_get_qdata(gobj, Quark)) assert(result.impl == gobj) else: fnew(result, $1.finalizeGObject) result.impl = gobj result.ignoreFinalizer = true g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[])) assert(g_object_get_qdata(result.impl, Quark) == nil) g_object_set_qdata(result.impl, Quark, addr(result[])) assert(toBool(g_type_check_instance_is_a(cast[ptr TypeInstance00](result.impl), gt))) """ const GDK3_EPI = """ proc getButton*(self: SomeEvent): int = var button: uint32 if not toBool(gdk_event_get_button(cast[ptr Event00](self.impl), button)): raise newException(Defect, "Event don't has a button field.") return int(button) proc getClickCount*(self: SomeEvent): int = var clickCount_00: uint32 if not toBool(gdk_event_get_click_count(cast[ptr Event00](self.impl), clickCount_00)): raise newException(Defect, "Event does not support getClickCount().") return int(clickCount_00) proc getCoords*(self: SomeEvent): (cdouble, cdouble) = if not toBool(gdk_event_get_coords(cast[ptr Event00](self.impl), result[0], result[1])): raise newException(Defect, "This event don't has a coordinate field.") proc getKeyval*(self: SomeEvent): int = var keyval_00: uint32 if not toBool(gdk_event_get_keyval(cast[ptr Event00](self.impl), keyval_00)): raise newException(Defect, "This event don't has a keyval field.") return int(keyval_00) # not available in GTK4 proc getRootCoords*(self: SomeEvent): (cdouble, cdouble) = if not toBool(gdk_event_get_root_coords(cast[ptr Event00](self.impl), result[0], result[1])): raise newException(Defect, "This event don't has a rootCoordinate field.") proc getScrollDeltas*(self: SomeEvent): (cdouble, cdouble) = if not toBool(gdk_event_get_scroll_deltas(cast[ptr Event00](self.impl), result[0], result[1])): raise newException(Defect, "This event don't has a scrollDeltas field.") proc getScrollDirection*(self: SomeEvent): ScrollDirection = if not toBool(gdk_event_get_scroll_direction(cast[ptr Event00](self.impl), result)): raise newException(Defect, "Event don't has a scrollDirection field.") proc getState*(self: SomeEvent): ModifierType = if not toBool(gdk_event_get_state(cast[ptr Event00](self.impl), result)): raise newException(Defect, "Event don't has a state field.") proc gdk_window_invalidate_nilrect(self: ptr Window00; rect: ptr Rectangle; invalidateChildren: gboolean) {. importc: "gdk_window_invalidate_rect", libprag.} proc invalidateRect*(self: Window; rect: ptr Rectangle = nil; invalidateChildren: bool = false) = gdk_window_invalidate_nilrect(cast[ptr Window00](self.impl), rect, gboolean(invalidateChildren)) proc fixednewCursorFromName*(display: Display; name: string): Cursor = fnew(result, gdk.finalizeGObject) result.impl = gdk_cursor_new_from_name(cast[ptr Display00](display.impl), cstring(name)) GC_ref(result) discard g_object_ref_sink(result.impl) g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[])) g_object_unref(result.impl) #assert(g_object_get_qdata(result.impl, Quark) == nil) g_object_set_qdata(result.impl, Quark, addr(result[])) """ const GDK_EPI = """ proc getAngle*(self: SomeEvent; event2: SomeEvent): cdouble = if not toBool(gdk_events_get_angle(cast[ptr Event00](self.impl), cast[ptr Event00](event2.impl), result)): raise newException(Defect, "Events do not support getAngle().") proc getCenter*(self: SomeEvent; event2: SomeEvent): (cdouble, cdouble) = if not toBool(gdk_events_get_center(cast[ptr Event00](self.impl), cast[ptr Event00](event2.impl), result[0], result[1])): raise newException(Defect, "Events do not support getCenter().") proc getDistance*(self: SomeEvent; event2: SomeEvent): cdouble = if not toBool(gdk_events_get_distance(cast[ptr Event00](self.impl), cast[ptr Event00](event2.impl), result)): raise newException(Defect, "Events do not support getDistance().") proc getAxis*(self: SomeEvent; axisUse: AxisUse): cdouble = if not toBool(gdk_event_get_axis(cast[ptr Event00](self.impl), axisUse, result)): raise newException(Defect, "Event does not support getAxis().") """ const GIO_EPI = """ proc run*(self: GApplication): int = int(g_application_run(cast[ptr GApplication00](self.impl), 0, nil)) #proc gFile00Array2seq*(p: GFile00Array; l: int32): seq[gio.GFile] = proc gFile00Array2seq*(p: ptr GFile00; l: int32): seq[gio.GFile] = let a = cast[ptr UncheckedArray[ptr GFile00]](p) result = newSeq[gio.GFile]() var i: int while i < l: let f = new gio.GFile f.impl = a[i] f.ignoreFinalizer = true result.add(f) inc(i) """ const GObject_EPI = """ #proc refCount*(o: gobject.Object): int = # let p = cast[ptr cuint](cast[int](o.impl) + sizeof(pointer)) # return p[].int proc scNotify*(self: Object; p: proc (self: ptr Object00; paramSpec: ptr ParamSpec00; xdata: pointer) {.cdecl.}, xdata: pointer, cf: gobject.ConnectFlags; sigName: cstring): culong = # g_signal_connect_data(self.impl, "notify::cursor-position", cast[GCallback](p), xdata, nil, cf) g_signal_connect_data(self.impl, sigName, cast[GCallback](p), xdata, nil, cf) proc typeCheckInstanceIsA*(instance: Object; ifaceType: GType): bool = toBool(g_type_check_instance_is_a(cast[ptr TypeInstance00](instance.impl), ifaceType)) # similar to gobjectTemp() proc glistObjects2seq*[T](t: typedesc[T]; l: ptr glib.List; elTransferFull: bool): seq[T] = var r: T var obj: ptr Object00 var el = l while el != nil: obj = cast[ptr Object00](el.data) if obj == nil: continue let qdata = g_object_get_qdata(obj, Quark) if qdata != nil: r = cast[T](qdata) assert(r.impl == obj) result.add(r) else: fnew(r, finalizeGObject)#" % [mprefix]) r.impl = obj GC_ref(r) if elTransferFull: if g_object_is_floating(r.impl).int != 0: discard g_object_ref_sink(r.impl) else: discard g_object_ref_sink(r.impl) g_object_add_toggle_ref(r.impl, toggleNotify, addr(r[])) g_object_unref(r.impl) assert(g_object_get_qdata(r.impl, Quark) == nil) g_object_set_qdata(r.impl, Quark, addr(r[])) el = el.next proc gslistObjects2seq*[T](t: typedesc[T]; l: ptr glib.SList; elTransferFull: bool): seq[T] = var r: T var obj: ptr Object00 var el = l while el != nil: obj = cast[ptr Object00](el.data) if obj == nil: continue let qdata = g_object_get_qdata(obj, Quark) if qdata != nil: r = cast[T](qdata) assert(r.impl == obj) result.add(r) else: fnew(r, finalizeGObject)#" % [mprefix]) r.impl = obj GC_ref(r) if elTransferFull: if g_object_is_floating(r.impl).int != 0: discard g_object_ref_sink(r.impl) else: discard g_object_ref_sink(r.impl) g_object_add_toggle_ref(r.impl, toggleNotify, addr(r[])) g_object_unref(r.impl) assert(g_object_get_qdata(r.impl, Quark) == nil) g_object_set_qdata(r.impl, Quark, addr(r[])) el = el.next proc glistStructs2seq*[T](l: ptr glib.List; igFin: bool): seq[T] = var r: T var el = l while el != nil: if el.data == nil: continue newWithFinalizer(r) # CAUTION: newWithFinalizer() seems to be rarely used, can we remove it fully? r.impl = cast[typeof(r.impl)](el.data) r.ignoreFinalizer = igFin result.add(r) el = el.next proc gslistStructs2seq*[T](l: ptr glib.SList; igFin: bool): seq[T] = var r: T var el = l while el != nil: if el.data == nil: continue newWithFinalizer(r) # CAUTION: newWithFinalizer() seems to be rarely used, can we remove it fully? r.impl = cast[typeof(r.impl)](el.data) r.ignoreFinalizer = igFin result.add(r) el = el.next # Not much tested, but in use for libnice simple_example.nim # Some other modules may need a similar local proc, ie for pango.Item proc seq2GList*[T](s: seq[T]): ptr glib.List = var l: ptr glib.List var i = s.len while i > 0: dec(i) when T is gobject.Object or compiles(T.impl): # https://github.com/StefanSalewski/gintro/issues/99#issuecomment-739435944 # when compiles(s[i].impl == nil): # when T is gobject.Object: # or T is pango.Item: l = g_list_prepend(l, s[i].impl) elif T is cstring: l = g_list_prepend(l, s[i]) # cstring else: # {.error: "seq2GList was called with unsupported type".} # that would break compiling the modules currently discard # make it compile for these cases, of course will not work return l proc seq2GSList*[T](s: seq[T]): ptr glib.SList = var l: ptr glib.SList var i = s.len while i > 0: dec(i) when T is gobject.Object or compiles(T.impl): # when compiles(s[i].impl == nil): # NiceCandidate # when T is gobject.Object: # or T is pango.Item: l = g_slist_prepend(l, s[i].impl) elif T is cstring: l = g_slist_prepend(l, s[i]) # cstring else: # {.error: "seq2GSList was called with unsupported type".} discard # make it compile for these cases, of course will not work return l #include gimplgobj include gimplglib export glib.g_strdup """ # for v0.8.2 we create this manually, as gst_structure_from_string() is a constructor # since gst 1.18 and constructor with out parameter is currently not supported by gintro # the code is taken from v0.8.1 with gst 1.16 const Gst_EPI = """ proc gst_structure_from_string(string: cstring; `end`: var cstring): ptr Structure00 {. importc, libprag.} proc fromStringStructure*(string: cstring; `end`: var string): Structure = var end_00 = cstring(`end`) let impl0 = gst_structure_from_string(string, end_00) if impl0.isNil: return nil fnew(result, gBoxedFreeGstStructure) result.impl = impl0 `end` = $(end_00) # https://discourse.gnome.org/t/gst-buffer-copy-is-missing-in-gir-file/5327 # GstMiniObject * gst_mini_object_copy (const GstMiniObject *mini_object); proc gst_buffer_copy(self: ptr Buffer00): ptr Buffer00 {. importc: "gst_mini_object_copy", libprag.} proc copy*(self: Buffer): Buffer = fnew(result, gBoxedFreeGstBuffer) result.impl = gst_buffer_copy(cast[ptr Buffer00](self.impl)) include gimplgst """ const Pango_EPI = """ when not declared(ATTR_INDEX_TO_TEXT_END): const ATTR_INDEX_TO_TEXT_END* = uint32.high when not declared(ATTR_INDEX_FROM_TEXT_BEGINNING): const ATTR_INDEX_FROM_TEXT_BEGINNING* = uint32.low proc setStartIndex*(a: Attribute; i: uint32) = a.impl.startIndex = i proc setEndIndex*(a: Attribute; i: uint32) = a.impl.endIndex = i proc setIndices*(a: Attribute; s, e: uint32) = a.impl.startIndex = s a.impl.endIndex = e proc `startIndex=`*(a: Attribute; i: uint32) = a.impl.startIndex = i proc `endIndex=`*(a: Attribute; i: uint32) = a.impl.endIndex = i #proc `indices=`*(a: Attribute; s, e: uint32) = proc `indices=`*(a: Attribute; se: tuple[start: uint32; `end`: uint32]) = a.impl.startIndex = se[0] a.impl.endIndex = se[1] """ const Nice_EPI = """ proc nice_agent_get_selected_pair(self: ptr Agent00; streamId: uint32; componentId: uint32; local: var ptr Candidate00; remote: var ptr Candidate00): gboolean {.importc, libprag.} proc getSelectedPair*(self: Agent; streamId: int; componentId: int; local: var Candidate; remote: var Candidate): bool = fnew(local, gBoxedFreeNiceCandidate) local.ignoreFinalizer = true fnew(remote, gBoxedFreeNiceCandidate) remote.ignoreFinalizer = true toBool(nice_agent_get_selected_pair(cast[ptr Agent00](self.impl), uint32(streamId), uint32(componentId), local.impl, remote.impl)) include gimplnice """ const GLib_EPI = """ when not declared(g_thread_new): proc g_thread_new(name: cstring; fn: ThreadFunc; data:pointer): ptr Thread00 {.importc, libprag.} proc newThread*(name: string; fn: ThreadFunc; data:pointer): Thread = fnew(result, finalizerunref) result.impl = g_thread_new(name, fn, data) #include gimplglib will not work as glib does not import gobject """ const GTK3_EPI = """ proc mainQuit*(w: Window) = mainQuit() """ const GTK4_EPI = """ proc getRootWidget*(self: Widget): Widget = let h = self.getRoot assert(toBool(g_type_check_instance_is_a(cast[ptr TypeInstance00](h.impl), gtk_widget_get_type()))) #g_type_check_instance_is_a(cast[ptr TypeInstance00](result.impl), gt))) cast[Widget](h) proc stringObject*(self: gobject.Object): StringObject = assert(toBool(g_type_check_instance_is_a(cast[ptr TypeInstance00](self.impl), gtk_string_object_get_type()))) cast[StringObject](self) proc fileInfo*(self: gobject.Object): gio.FileInfo = assert(toBool(g_type_check_instance_is_a(cast[ptr TypeInstance00](self.impl), g_file_info_get_type()))) cast[gio.FileInfo](self) proc gtk_constant_expression_new(value_type: GType): ptr Expression00 {.varargs, importc, libprag.} proc newConstantExpression*(gtype: GType; obj: gobject.Object): Expression = fnew(result, generic_gtk_expression_unref) result.impl = gtk_constant_expression_new(gtype, obj.impl) """ const GDK4_EPI = """ proc getPosition*(self: Event): (float, float) = assert toBool(gdk_event_get_position(cast[ptr Event00](self.impl), result[0].float, result[1].float)) """ const GTK_EPI = """ proc setMargin*(w: Widget; m: int) = setMarginStart(w, m) setMarginEnd(w, m) setMarginTop(w, m) setMarginBottom(w, m) # allow connecting GtkText and GtkEntry to "changed" signal of GtkEditable! proc editable*(x: Text): Editable = cast[Editable](x) proc editable*(x: Entry): Editable = cast[Editable](x) #proc loadFromData*(self: CssProvider; data: cstring): bool = # loadFromData(self, uint8Array(data), -1) proc addAction*(self: ApplicationWindow; action: Action | PropertyAction | SimpleAction) = g_action_map_add_action(cast[ptr ActionMap00](self.impl), cast[ptr Action00](action.impl)) proc gtk_file_chooser_dialog_new*(title: cstring; parent: ptr Window00; action: FileChooserAction; firstButtonText: cstring = nil): ptr FileChooserDialog00 {.varargs, importc: "gtk_file_chooser_dialog_new", libprag.} proc newFileChooserDialog*(title: cstring = nil; parent: Window = nil; action: FileChooserAction): FileChooserDialog = let gobj = gtk_file_chooser_dialog_new(title, if parent.isNil: nil else: cast[ptr Window00](parent.impl), action) if g_object_get_qdata(gobj, Quark) != nil: result = cast[type(result)](g_object_get_qdata(gobj, Quark)) assert(result.impl == gobj) else: fnew(result, $1.finalizeGObject) result.impl = gobj GC_ref(result) discard g_object_ref_sink(result.impl) g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[])) g_object_unref(result.impl) assert(g_object_get_qdata(result.impl, Quark) == nil) g_object_set_qdata(result.impl, Quark, addr(result[])) proc initFileChooserDialog*[T](result: var T; title: cstring = nil; parent: Window = nil; action: FileChooserAction) = assert(result is FileChooserDialog) let gobj = gtk_file_chooser_dialog_new(title, if parent.isNil: nil else: cast[ptr Window00](parent.impl), action) if g_object_get_qdata(gobj, Quark) != nil: result = cast[type(result)](g_object_get_qdata(gobj, Quark)) assert(result.impl == gobj) else: fnew(result, $1.finalizeGObject) result.impl = gobj GC_ref(result) discard g_object_ref_sink(result.impl) g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[])) g_object_unref(result.impl) assert(g_object_get_qdata(result.impl, Quark) == nil) g_object_set_qdata(result.impl, Quark, addr(result[])) import macros, strutils #include gisup #include gimpl """ var gstLib: LibHandle adwLib: LibHandle gtk3Lib: LibHandle gtk4Lib: LibHandle proc main(namespace: string; version: cstring = nil) = priList = newSeq[string]() var buildableList: seq[string] suppressType = false suppressRaise = false delayedMethods = newSeq[(GIBaseInfo, GIFunctionInfo)]() classList = newSeq[GIBaseInfo]() output = newStringStream() methodBuffer = newStringStream() var externInterfaces: seq[string] var error: GError ct = initCountTable[string]() var delayedSyms: seq[GIBaseInfo] allSyms = initHashSet[string]() provInt.clear interfaceProvider.clear var ig: HashSet[string] knownSyms = initHashSet[string]() let gi = gIrepositoryGetDefault() assert(gi != nil) moduleNamespace = namespace.toLowerAscii #echo fixedModName(moduleNameSpace) #let version: cstring = nil # latest # export GI_TYPELIB_PATH=/opt/gtk/lib64/girepository-1.0 # echo $XDG_DATA_DIRS # man g-ir-scanner #g_irepository_prepend_search_path("/opt/gtk/lib64/girepository-1.0") # ISGTK3 = not (((namespace == "Gtk") or (namespace == "Gdk") or (namespace == "GdkX11")) and version == "4.0") # ISGTK3 = parmCount() == 0 # we have to launch the generator two times, as typelibs can not be unloaded! if namespace == "Gst" and gstLib == nil: gstLib = tryInitGst() if namespace == "Adw" and adwLib == nil: adwLib = tryInitAdw() if namespace == "Gtk" and version == "3.0" and gtk3Lib == nil: gtk3Lib = tryInitGtk3() if namespace == "Gtk" and version == "4.0" and gtk4Lib == nil: gtk4Lib = tryInitGtk4() let typelib = gi.gIrepositoryRequire(namespace, version, cast[GIRepositoryLoadFlags](0), error) #let typelib = gIrepositoryRequirePrivate(nil, namespace, "/usr/lib/girepository-1.0", version, cast[GIRepositoryLoadFlags](0), error) if typelib.isNil: echo "Failed to load ", namespace echo error.message echo "Maybe for your OS you have to install additional GTK related packages?" echo "We continue with the remaining packages..." return #let loadedVersion = g_irepository_get_version(gi, namespace) let dep: cstringArray = gi.gIrepositoryGetDependencies(namespace) var weImportGObject = false output.writeLine("# dependencies:") var importedModules = "" for j in 0 .. 18: # stupid restriction! if dep[j].isNil: break if j == 0: importedModules = "import " output.writeLine("# ", dep[j]) let h = fixedModName(($dep[j]).split('-', 2)[0].toLowerAscii) & ", " importedModules.add(h) if h == "gobject, ": weImportGObject = true importedModules.removeSuffix(", ") strfreev(dep) let idep: cstringArray = gi.gIrepositoryGetImmediateDependencies(namespace) output.writeLine("# immediate dependencies:") for j in 0 .. 12: # puh if idep[j].isNil: break output.writeLine("# ", idep[j]) strfreev(idep) let libs = $gi.gIrepositoryGetSharedLibrary(namespace) output.writeLine("# libraries:") output.writeLine("# ", libs) #output.writeLine("{.deadCodeElim: on, warning[UnusedImport]: off.}") # gmodule, xlib, cairo output.writeLine("{.warning[UnusedImport]: off.}") # gmodule, xlib, cairo output.writeLine(importedModules) #var Lib = if libs.isNil: "" else: ($libs).split(',', 2)[0] var hlibs = libs.split(',') # maybe we can simplify this later, editDistance() is not the optimal algorithm here var hhlibs = hlibs for el in mitems(hlibs): let p = skipUntil(el, {'0' .. '9', '.'}) el.setLen(p) var Lib = hhlibs[maxby.minIndexByIt(hlibs, editDistanceAscii(it.toLowerAscii, moduleNamespace))] # see https://discourse.gnome.org/t/title-in-text-due-to-discourse-bug/4477 if namespace == "PangoCairo" and Lib.startsWith("libpango-"): echo moduleNamespace echo Lib echo libs assert false Lib = Lib.replace("libpango-", "libpangocairo-") # GI bug? output.writeLine("const Lib = \"$1\"" % Lib) output.writeLine("{.pragma: libprag, cdecl, dynlib: Lib.}") if namespace == "GObject": output.writeLine("type\n GCallback* = proc () {.cdecl.}") #output.writeLine("type\n Object00Array* = pointer") output.writeLine("type\n VaClosureMarshal* = pointer") output.writeLine("\nproc boxedFree*(boxedType: GType; boxed: pointer) {.") output.writeLine(" importc: \"g_boxed_free\", libprag.}") output.writeLine("\nproc g_boxed_copy*(boxedType: GType; boxed: pointer): pointer {.") output.writeLine(" importc , libprag.}") elif namespace == "GLib": # we need gobject. #let gobjectlibs = gi.gIrepositoryGetSharedLibrary("GObject") #var GobjectLib = if gobjectlibs.isNil: "" else: ($gobjectlibs).split(',', 2)[0] var GobjectLib = maxby.minValueByIt(libs.split(','), editDistanceAscii(it.toLowerAscii, "gobject")) output.writeLine("const GobjectLib* = \"$1\"" % GobjectLib) output.writeLine("{.pragma: gobjectlibprag, cdecl, dynlib: GobjectLib.}") output.writeLine("type\n GException* = object of CatchableError") output.writeLine("type\n GArray00* = pointer") #output.writeLine("type\n Regex00Array* = pointer") output.writeLine("type\n ucstring* = distinct cstring") output.writeLine("type\n gboolean* = distinct cint") output.writeLine("const\n GLIB_SIZEOF_VOID_P = sizeof(pointer)") output.writeLine("const\n GLIB_SIZEOF_SIZE_T* = GLIB_SIZEOF_VOID_P") output.writeLine("const\n GLIB_SIZEOF_LONG* = sizeof(clong)") output.writeLine("type\n Gssize* = int # csize") # https://forum.nim-lang.org/t/5637#35015 output.writeLine("type\n Gsize* = uint # csize # note: csize is signed in Nim!") #output.writeLine("type\n GType* = distinct cint") # wrong #stefan@nuc ~/Downloads/glib-2.53.3/gobject $ grep -A5 GLIB_SIZEOF_S *.h #gtype.h:#if GLIB_SIZEOF_SIZE_T != GLIB_SIZEOF_LONG || !defined __cplusplus #gtype.h-typedef gsize GType; #gtype.h-#else /* for historic reasons, C++ links against gulong GTypes */ #gtype.h-typedef gulong GType; #gtype.h-#endif output.writeLine("when GLIB_SIZEOF_SIZE_T != GLIB_SIZEOF_LONG or not defined(cpp):") output.writeLine(" type\n GType* = Gsize") output.writeLine("else:") output.writeLine(" type\n GType* = culong") output.writeLine("type\n gunichar* = uint32") output.writeLine("type\n utf8* = char") output.writeLine("const GFalse* = gboolean(0)") output.writeLine("const GTrue* = gboolean(1)") output.writeLine("\nproc boxedFree(boxedType: GType; boxed: pointer) {.") output.writeLine(" importc: \"g_boxed_free\", gobjectlibprag.}") output.writeLine("\nproc g_boxed_copy(boxedType: GType; boxed: pointer): pointer {.") output.writeLine(" importc , gobjectlibprag.}") output.writeLine(""" #proc fnew*[T](a: var ref T; finalizer: proc (x: ref T)) = template fnew*(a: untyped; finalizer: untyped) = when defined(gcDestructors): system.new(a) else: new(a, finalizer) """) output.writeLine(""" proc int32ArrayZT2seq*(p: pointer): seq[int32] = let a = cast[ptr UncheckedArray[int32]](p) var i: int while true: if a[i] == 0: break result.add(a[i]) inc(i) """) output.writeLine(""" proc uint32ArrayZT2seq*(p: pointer): seq[uint32] = let a = cast[ptr UncheckedArray[uint32]](p) var i: int while true: if a[i] == 0: break result.add(a[i]) inc(i) """) output.writeLine(""" proc uint8ArrayZT2seq*(p: pointer): seq[uint8] = let a = cast[ptr UncheckedArray[uint8]](p) var i: int while true: if a[i] == 0: break result.add(a[i]) inc(i) """) output.writeLine(""" proc uint8ArrayToSeq*(s: ptr uint8; n: int): seq[uint8] = let a = cast[ptr UncheckedArray[uint8]](s) for i in 0 ..< n: result.add(a[i]) """) output.writeLine(""" proc uint32ArrayToSeq*(s: ptr uint32; n: int): seq[uint32] = let a = cast[ptr UncheckedArray[uint32]](s) for i in 0 ..< n: result.add(a[i]) """) output.writeLine(""" proc int32ArrayToSeq*(s: ptr int32; n: int): seq[int32] = let a = cast[ptr UncheckedArray[int32]](s) for i in 0 ..< n: result.add(a[i]) """) output.writeLine(""" proc cstringArrayToSeq*(s: ptr cstring): seq[string] = system.cstringArrayToSeq(cast[cstringArray](s)) """) output.writeLine("proc cogfree*(mem: pointer) {.importc: \"g_free\", libprag.}") output.writeLine("proc g_strfreev*(strArray: ptr cstring) {.importc: \"g_strfreev\", libprag.}") output.writeLine("proc toBool*(g: gboolean): bool = g.int != 0") # output.writeLine("proc safeStringToCString*(s: cstring): cstring = (if s.len == 0: nil else: s)") output.writeLine(PRO) elif namespace == "Gdk": discard elif namespace == "Gtk": discard #output.writeLine( # "# https://developer.gnome.org/gtk3/stable/GtkWidget.html#GtkWidget-draw") #output.writeLine( # "# TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.") #output.writeLine("const\n SignalEventStopPropagation* = true") #output.writeLine("const\n SignalEventContinuePropagation* = false") elif namespace == "Atk": discard elif namespace == "cairo": output.writeLine("\nfrom gobject import boxedFree") output.writeLine("from glib import GType") elif namespace == "Pango": discard elif namespace == "Gio": discard elif namespace == "Graphene": discard elif namespace == "Gsk": discard elif namespace == "GtkSource": output.writeLine("import glib") elif namespace == "Vte": output.writeLine("import glib\n") elif namespace == "Gst": discard elif namespace == "WebKit2": output.writeLine("from atk import ImplementorIface\n") # Extern interfaces support elif namespace == "Nice": output.writeLine("import macros, nativesockets\n") output.writeLine("from strutils import `%`\n") discard if namespace == "GObject": output.writeLine("\nimport times") output.writeLine("var qt = \"NGIQ\" & $epochTime()") output.writeLine("if g_quark_try_string(qt) != 0:") output.writeLine(" qt = \"NGIQ\" & $epochTime()") output.writeLine("let Quark* = g_quark_from_static_string(qt)") #if namespace notin ["GObject", "GLib", "xlib", "GModule"]: # if weImportGObject: output.writeLine("\nproc finalizeGObject*[T](o: ref T) =") output.writeLine(" if not o.ignoreFinalizer:") output.writeLine(" gobject.g_object_remove_toggle_ref(o.impl, gobject.toggleNotify, addr(o[]))") #output.writeLine("\nproc genericGObjectUnref*[T](self: ref T) =") #output.writeLine(" if not self.ignoreFinalizer:") #output.writeLine(" gobject.g_object_unref(cast[ptr gobject.Object00](self.impl))") var n = gi.gIrepositoryGetNInfos(namespace) var s: seq[GIBaseInfo] for i in 0.cint ..< n: if not droppedSyms.contains(mangleName(gBaseInfoGetName(gi.gIrepositoryGetInfo(namespace, i)))): s.add(gi.gIrepositoryGetInfo(namespace, i)) for i in s: if gBaseInfoGetType(i) in {GIInfoType.OBJECT, GIInfoType.INTERFACE, GIInfoType.STRUCT, GIInfoType.UNION} or isEnumInfo(i) or isCallbackInfo(i): allSyms.incl(mangleName(gBaseInfoGetName(i))) for i in 0 .. s.high: if namespace == "GLib" and gBaseInfoGetType(s[i]) == GIInfoType.STRUCT and gBaseInfoGetName(s[i]) == "Error": let h = s[i] s.delete(i, i) s.insert([h]) break for i in 0 .. s.high: if namespace == "GstRtsp" and gBaseInfoGetType(s[i]) == GIInfoType.ENUM and gBaseInfoGetName(s[i]) == "RTSPResult": let h = s[i] s.delete(i, i) s.insert([h]) break # NOTE: We may? remove all structs from xcallerAlloc when that struct ever is returned by a function! # v0.9.5 # And we may remove all structs with a GType! # https://discourse.gnome.org/t/what-is-the-difference-between-gmutex-and-gchecksum/4542 if namespace notin ["HarfBuzz", "cairo"]: # auto-detecting the "light" entities is too hard, but here we get some candidates for info in s: #if gBaseInfoGetType(info) == GIInfoType.UNION or gBaseInfoGetType(info) == GIInfoType.STRUCT: # if gRegisteredTypeInfoGetGType(info) != G_TYPE_NONE and gTypeFundamental(gRegisteredTypeInfoGetGType(info)) == G_TYPE_BOXED: # echo gBaseInfoGetName(info)#gRegisteredTypeInfoGetGType(info) let n = gBaseInfoGetName(info) if n[0] != '_' and not n.endsWith("Private") and not (namespace == "Gdk" and n.startsWith("Event")) and not (namespace == "Pango" and n.startsWith("Attribute")): if not isRegisteredTypeInfo(info) or gRegisteredTypeInfoGetGType(info) == G_TYPE_NONE: # v0.9.5 if gBaseInfoGetType(info) == GIInfoType.STRUCT: # if not ((gStructInfoIsGtypeStruct(info) and n != "ObjectClass")): # v0.9.4 with Debian Buster crash # if (not gStructInfoIsGtypeStruct(info) or (n == "ObjectClass")): # equivalent to above if (not gStructInfoIsGtypeStruct(info) and (n != "ObjectClass")): # this may work -- the same as suggested by Mr. 1jss var lightObj = true for n in "free unref get_qdata".split: if gStructInfoFindMethod(info, n) != nil: # crash for legacy Debian Buster lightObj = false if lightObj: for j in 0.cint ..< gStructInfoGetNMethods(info): let minfo = gStructInfoGetMethod(info, j) if (gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) != 0: lightObj = false if lightObj: let el = moduleNamespace & '.' & $n if not manCallerAlloc.contains(el) and not noCallerAlloc.contains(el): xcallerAlloc.incl(el) if gBaseInfoGetType(info) == GIInfoType.UNION: var lightObj = true for n in "free unref get_qdata".split: if gUnionInfoFindMethod(info, n) != nil: lightObj = false if lightObj: for j in 0.cint ..< gUnionInfoGetNMethods(info): let minfo = gUnionInfoGetMethod(info, j) if (gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) != 0: lightObj = false if lightObj: let el = moduleNamespace & '.' & $n if not manCallerAlloc.contains(el) and not noCallerAlloc.contains(el): xcallerAlloc.incl(el) for info in s: if gBaseInfoGetType(info) == GIInfoType.OBJECT: let ninterfaces = info.gObjectInfoGetNInterfaces if ninterfaces > 0: var interf: seq[string] let name = gBaseInfoGetQualifiedName(info) for i in 0.cint ..< ninterfaces: var ns = ($gBaseInfoGetNamespace(info.gObjectInfoGetInterface(i))).toLowerAscii if ns != moduleNamespace: var iname = $gBaseInfoGetName(info.gObjectInfoGetInterface(i)) var fname = iname; fname.unCap iname = fixedModName(ns) & "." & iname let tname = fixedModName(moduleNamespace) & "." & $gBaseInfoGetName(info) externInterfaces.add("proc " & fname & "*(x: " & tname & "): " & iname & " = cast[" & iname & "](x)") interf.add(gBaseInfoGetQualifiedName(info.gObjectInfoGetInterface(i))) let builderinter = info.gObjectInfoGetInterface(i) if gBaseInfoGetName(builderinter) == "Buildable": buildableList.add($gBaseInfoGetName(info)) if provInt.contains(name): assert false else: provInt[name] = interf #echo "eeeeeeeeeee", provInt[name] # Cross module interfaces -- maybe only a few, so we add it manually # GSimpleActionGroup implements GActionGroup and GActionMap. if namespace == "Gtk": provInt["gio.SimpleActionGroup"] = @["gio.ActionGroup", "gio.ActionMap", "ActionGroup", "ActionMap"] #provInt["gio.SimpleActionGroup"] = @["ActionGroup", "ActionMap"] # The next two do not work, as gio does not import gtk! So we have to use converter proc. # GtkApplication implements GActionGroup and GActionMap. # provInt["Application"] = @["ActionGroup", "ActionMap"] # GtkApplicationWindow implements AtkImplementorIface, GtkBuildable, GActionGroup and GActionMap. # provInt["ApplicationWindow"] = @["ImplementorIface", "Buildable", "ActionGroup", "ActionMap"] for obj, ifaces in provInt: for i in ifaces: if not interfaceProvider.contains(i): #echo "fff", obj interfaceProvider[i] = @[obj] else: interfaceProvider[i].add(obj) if namespace == "Gdk": # special care for gdk keys due to nim's style insensitivity! for i in s: var h = $gBaseInfoGetName(i) if h.startsWith("KEY_"): if gdkKeys.contains(h.toLowerAscii): gdkKeys[h.toLowerAscii].add(h) else: gdkKeys[h.toLowerAscii] = @[h] for el in mvalues(gdkKeys): sort(el, system.cmp) var i: GIBaseInfo var unp: seq[GIBaseInfo] reverse(s) var more_runs = 50 while s.len > 0 or more_runs > 0: if s.len == 0: dec(more_runs) if namespace == "GObject" and not knownSyms.contains("g_signal_connect_data"): if knownSyms.contains("ClosureNotify") and knownSyms.contains("ConnectFlags"): knownSyms.incl("g_signal_connect_data") output.writeLine("proc g_signal_connect_data*(instance: pointer; detailedSignal: cstring; cHandler: GCallback;") output.writeLine(" data: pointer; destroyData: ClosureNotify; connectFlags: ConnectFlags): culong {.") output.writeLine(" importc: \"g_signal_connect_data\", libprag.}") while priList.len > 0: # move missing symbols to top, but only once! let h = priList.pop if ig.contains(h): continue ig.incl(h) var k = -1 for p, el in s: if (gBaseInfoGetType(el) in {GIInfoType.OBJECT, GIInfoType.INTERFACE, GIInfoType.STRUCT} or isEnumInfo(el)) and gBaseInfoGetName(el) == h: k = p if k >= 0: s.add(s[k]) s.delete(k) if s.len > 0: i = s.pop delayedSyms.insert(i) if classList.len > 0: assert false delayedSyms.insert(classList.pop) unp.setLen(0) for k in delayedSyms: var pos = output.getPosition var supmodpos3 = supmod3.getPosition var supmodpos4 = supmod4.getPosition try: knownSyms.incl(mangleName(gBaseInfoGetName(k))) methodBuffer = newStringStream() signalBuffer = newStringStream() processInfo(k) output.write(signalBuffer.data) output.write(methodBuffer.data) except UndefEx: unp.add(k) knownSyms.excl(mangleName(gBaseInfoGetName(k))) output.cut(pos) supmod3.cut(supmodpos3) supmod4.cut(supmodpos4) delayedSyms = unp block myb: for a in 1 .. 3: # process clustered symbols into one single type section if delayedSyms.len > a: suppressType = true methodBuffer = newStringStream() signalBuffer = newStringStream() unp = delayedSyms #for t in unp.combinations(a + 1): # works fine with default GC var hhh = toSeq(unp.combinations(a + 1)) # nedded for --gc:arc for t in hhh: var pos = output.getPosition var supmodpos3 = supmod3.getPosition var supmodpos4 = supmod4.getPosition methodBuffer = newStringStream() signalBuffer = newStringStream() let x = delayedMethods.len #var processedFunctionsBack = processedFunctions # var due to https://forum.nim-lang.org/t/6312 tempProcessedFunctions.setLen(0) useTempProcessedFunctions = true try: var h = false for k in t: if gBaseInfoGetType(k) notin {GIInfoType.INTERFACE, GIInfoType.OBJECT, GIInfoType.STRUCT, GIInfoType.UNION} and not isCallbackInfo(k): h = true assert false if h: continue output.writeLine("type") for k in t: knownSyms.incl(mangleName(gBaseInfoGetName(k))) for k in t: processInfo(k) for k in t: delayedSyms.keepItIf(mangleName(gBaseInfoGetName(k)) != mangleName(gBaseInfoGetName(it))) suppressType = false output.write(signalBuffer.data) output.write(methodBuffer.data) break myb except UndefEx: for k in t: knownSyms.excl(mangleName(gBaseInfoGetName(k))) output.setPosition(pos) supmod3.cut(supmodpos3) supmod4.cut(supmodpos4) #processedFunctions = processedFunctionsBack # for el in tempProcessedFunctions: processedFunctions.excl(el) useTempProcessedFunctions = false assert delayedMethods.len >= x delayedMethods.setLen(x) suppressType = false methodBuffer = newStringStream() var h = delayedMethods delayedMethods = newSeq[(GIBaseInfo, GIFunctionInfo)]() for el in h: writeMethod(el[0], el[1]) output.write(methodBuffer.data) suppressRaise = true output.writeLine("# === remaining symbols:") # in best case there is nothing left for i in delayedSyms: assert false processInfo(i) if externInterfaces.len > 0: output.writeLine("\n# Extern interfaces: (we don't use converters, but explicit procs for now.)") for i in externInterfaces: output.writeLine("") output.writeLine(i) if namespace == "Gst": output.write( """ proc init* = var argc: int32 = 0 #var argv: cstringArray = nil var argv: ptr cstring = nil gst_init(argc, argv) proc getType*(m: gst.Message): gst.MessageType = m.impl.type """) if namespace == "Gtk": if ISGTK3: output.write(GTK3_EPI) output.write( """ proc init* = var argc: int32 = 0 #var argv: cstringArray = nil var argv: ptr cstring = nil gtk_init(argc, argv) """) output.write(GTK_EPI % fixedModName("gtk")) if ISGTK3: output.write("include gisup3\n") output.write("include gimplgobj\n") output.write("include gimplgtk\n") else: output.write(GTK4_EPI) output.write("include gisup4\n") output.write("include gimplgobj\n") output.write("include gimplgtk\n") buildableList.add("MenuModel") buildableList.add("FileChooserNative") for i in buildableList: var prefix = "gtk" var modname = fixedModName(moduleNamespace) if i == "MenuModel": prefix = "g" modname = "gio" if i == "": continue output.write( """ proc get$1*(builder: Builder; name: string): $1 = let gt = $2 assert(gt != g_type_invalid_get_type()) let gobj = gtk_builder_get_object(cast[ptr Builder00](builder.impl), name) assert(gobj != nil) if g_object_get_qdata(gobj, Quark) != nil: result = cast[type(result)](g_object_get_qdata(gobj, Quark)) assert(result.impl == gobj) else: fnew(result, $3.finalizeGObject) result.impl = gobj # not floating, with ref count == 1 #result.ignoreFinalizer = true #discard g_object_ref(result.impl) # v0.99, try to fix issue GC_ref(result) # when builder instance goes out and is destroyed, it unrefs its childs... g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[])) # do toggle_refs make sense at all for builder objects? #g_object_unref(result.impl) # new for v0.8.4 and GTK4, make close main windows working assert(g_object_get_qdata(result.impl, Quark) == nil) g_object_set_qdata(result.impl, Quark, addr(result[])) assert(toBool(g_type_check_instance_is_a(cast[ptr TypeInstance00](result.impl), gt))) """ % [i, prefix & "_" & myCamelToSnake(i) & "_get_type()", modname]) output.write("") if namespace == "Gio": output.write(GIO_EPI) if namespace == "GObject": output.write(GObject_EPI) if namespace == "Gst": output.write(Gst_EPI) if namespace == "Pango": output.write(Pango_EPI) if namespace == "GLib": output.write(GLib_EPI) if namespace == "Nice": output.write(Nice_EPI) if namespace == "cairo": if not cairoProvidesRectangle: output.writeLine(""" type Rectangle* {.pure, byRef.} = object x*: cdouble y*: cdouble width*: cdouble height*: cdouble proc cairo_gobject_rectangle_get_type*(): GType {.importc, libprag.} """) output.write("\ninclude cairoimpl\n") if namespace == "GObject": output.writeLine("\nproc g_type_invalid_get_type*(): GType = g_type_from_name(\"(null)\")") output.writeLine("\nproc g_type_none_get_type*(): GType = g_type_from_name(\"void\")") output.writeLine("\nproc g_interface_get_type*(): GType = g_type_from_name(\"GInterface\")") output.writeLine("\nproc g_char_get_type*(): GType = g_type_from_name(\"gchar\")") output.writeLine("\nproc g_uchar_get_type*(): GType = g_type_from_name(\"guchar\")") output.writeLine("\nproc g_boolean_get_type*(): GType = g_type_from_name(\"gboolean\")") output.writeLine("\nproc g_int_get_type*(): GType = g_type_from_name(\"gint\")") output.writeLine("\nproc g_uint_get_type*(): GType = g_type_from_name(\"guint\")") output.writeLine("\nproc g_long_get_type*(): GType = g_type_from_name(\"glong\")") output.writeLine("\nproc g_ulong_get_type*(): GType = g_type_from_name(\"gulong\")") output.writeLine("\nproc g_int64_get_type*(): GType = g_type_from_name(\"gint64\")") output.writeLine("\nproc g_uint64_get_type*(): GType = g_type_from_name(\"guint64\")") output.writeLine("\nproc g_enum_get_type*(): GType = g_type_from_name(\"GEnum\")") output.writeLine("\nproc g_flags_get_type*(): GType = g_type_from_name(\"GFlags\")") output.writeLine("\nproc g_float_get_type*(): GType = g_type_from_name(\"gfloat\")") output.writeLine("\nproc g_double_get_type*(): GType = g_type_from_name(\"gdouble\")") output.writeLine("\nproc g_string_get_type*(): GType = g_type_from_name(\"gchararray\")") output.writeLine("\nproc g_pointer_get_type*(): GType = g_type_from_name(\"gpointer\")") output.writeLine("\nproc g_boxed_get_type*(): GType = g_type_from_name(\"GBoxed\")") output.writeLine("\nproc g_param_get_type*(): GType = g_type_from_name(\"GParam\")") #output.writeLine("\nproc g_object_get_type*(): GType = g_type_from_name(\"GObject\")") #output.writeLine("\nproc g_type_get_type*(): GType = g_type_from_name(\"GType\")") output.writeLine("\nproc g_variant_get_type*(): GType = g_type_from_name(\"GVariant\")") output.setPosition(output.data.len) if namespace == "Gdk": if ISGTK3: output.write(GDK3_EPI.replace("SomeEvent", "Event")) output.write(GDK_EPI.replace("SomeEvent", "Event")) if not ISGTK3: output.write(GDK4_EPI) if namespace == "GtkSource": output.write(GTK_SOURCE_EPI % fixedModName("gtksource")) output.flush var suff = "" if version == "4.0": suff = "4" if namespace == "GtkSource" and version == nil: suff = "5" if namespace in ["JavaScriptCore", "WebKit2", "WebKit2WebExtension"]: if version == "4.0": suff = "" if version == "5.0": suff = "5" if namespace == "Soup": if version == "2.4": suff = "" if version == "3.0": suff = "3" var o = open("nim_gi" / (namespace.toLowerAscii) & suff & ".nim", fmWrite) o.write(output.data) o.close() output.close var hs = fixedModName(moduleNameSpace) & "............................" hs.setLen(24) stdout.write(hs, ": Remaining delayed methods: ", delayedMethods.len) if delayedMethods.len == 0: echo " (Fine!)" else: echo " delayed:" for el in delayedMethods: echo gBaseInfoGetName(el[1]) if false: # namespace in ["Nice", "Soup"]: # this gives other issues! gTypelibFree(typelib) # v0.9.8, try to fix libnice/libsoup conflict proc launch() = when defined(gcDestructors): echo "defined(gcDestructors)" echo "maybe GC is arc" #when compileOption("gc", "arc"): # echo "GC is arc" #when compileOption("gc", "refc"): # echo "GC is refc" ISGTK3 = paramCount() == 0 # we have to launch the generator two times, as typelibs can not be unloaded! supmod3 = newStringStream() supmod3.writeLine("const\n SCA = [") supmod4 = newStringStream() supmod4.writeLine("const\n SCA = [") # as typelib does not support reloading, we have to generate all libs twice # note cairo is handcrafted! if ISGTK3: echo "Generating bindings for GTK3..." main("Gtk", "3.0") # the 3 new 4.0 releases in old version main("Gdk", "3.0") main("GdkX11", "3.0") # main("Gsk") # not available for GTK3 main("Graphene") main("GObject") # and the old common onces. GObject before Glib! main("GLib") main("Gio") main("GdkPixbuf") main("GModule") main("GtkSource", "4") main("Atk") main("Pango") main("PangoCairo") main("PangoFT2") main("fontconfig") main("freetype2") main("HarfBuzz") main("Rsvg") main("xlib") main("Vte") main("Notify") main("Handy") main("Soup", "2.4") # process Soup before Nice, preventing the load of not matching libsoup version main("Nice") main("cairo") main("WebKit2", "4.0") main("JavaScriptCore", "4.0") #main("Soup", "2.4") main("WebKit2WebExtension", "4.0") main("Gst") main("GstBase") main("GstAllocators") main("GstApp") main("GstAudio") main("GstCheck") main("GstController") main("GstGL") main("GstInsertBin") main("GstMpegts") main("GstNet") main("GstPlayer") main("GstRtp") main("GstRtsp") main("GstSdp") main("GstTag") main("GstVideo") main("GstWebRTC") main("GstApp") main("GstPbutils") main("GtkLayerShell") else: echo "First we try generating bindings for GTK4, this may fail when GTK4 is not properly installed" echo "on your computer. But don't worry, you can still use GTK3" main("Gtk", "4.0") # the 3 new 4.0 releases main("Gdk", "4.0") main("GdkX11", "4.0") main("Gsk") # and two new ones for gtk4 main("Graphene") main("GObject") # and the old common onces. GObject before Glib! main("GLib") main("Gio") main("GdkPixbuf") main("GModule") main("GtkSource") main("Atk") main("Pango") main("PangoCairo") main("PangoFT2") main("fontconfig") main("freetype2") main("HarfBuzz") main("Rsvg") main("xlib") # main("Vte") # not yet available for GTK4 main("Notify") # main("Handy") # not yet available for GTK4 main("Adw") # replaces libhandy for GTK4 main("Soup", "3.0") # process Soup before Nice, preventing the load of not matching libsoup version # main("Nice") # https://discourse.gnome.org/t/some-libsoup-3-issue/7807/14 no nice for GTK4 in v0.9.8 main("cairo") main("WebKit2", "5.0") main("JavaScriptCore", "5.0") #main("Soup", "3.0") main("WebKit2WebExtension", "5.0") main("Gst") main("GstBase") main("GstAllocators") main("GstApp") main("GstAudio") main("GstCheck") main("GstController") main("GstGL") main("GstInsertBin") main("GstMpegts") main("GstNet") main("GstPlayer") main("GstRtp") main("GstRtsp") main("GstSdp") main("GstTag") main("GstVideo") main("GstWebRTC") main("GstApp") main("GstPbutils") if ISGTK3: supmod3.writeLine(" ]") supmod3.flush var o = open("nim_gi" / "gisup3.nim", fmWrite) o.write(supmod3.data) o.close() supmod3.close else: supmod4.writeLine(" ]") supmod4.flush var o = open("nim_gi" / "gisup4.nim", fmWrite) o.write(supmod4.data) o.close() supmod4.close if gstLib != nil: unloadLib(gstLib) if adwLib != nil: unloadLib(adwLib) if gtk3Lib != nil: unloadLib(gtk3Lib) if gtk4Lib != nil: unloadLib(gtk4Lib) launch() #for el in xcallerAlloc: # if not callerAlloc.contains(el): # echo "maybe add: ", el #for el in xcallerAlloc: # if not callerAlloc.contains(el): # echo "maybe add: ", el #echo "---" #for el in oldcallerAlloc: # if not xcallerAlloc.contains(el): # echo el # 4613 lines # gtk_icon_view_get_tooltip_context bug Candidate ignoreFinalizer # gtk_tree_view_get_cursor bug getBox genRec gisup4 # # troubles: gTypeFundamental(gRegisteredTypeInfoGetGType(info)) == G_TYPE_BOXED: #[ proc gst_structure_take(oldstrPtr: var ptr Structure00; newstr: ptr Structure00): gboolean {. importc, libprag.} proc take*(oldstrPtr: var Structure; newstr: Structure = nil): bool = toBool(gst_structure_take(if oldstrPtr.isNil: nil else: cast[ptr Structure00](oldstrPtr.impl), if newstr.isNil: nil else: cast[ptr Structure00](newstr.impl))) gtk4 CssLocation may be userAlloc ! Face idleAdd g_idle_add_full nil str.add | provider nilb g_object_set_qdata g_object_get_qdata ]#