4628 lines
191 KiB
Nim
4628 lines
191 KiB
Nim
# 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: # <method name="" c:identifier="gst_video_chroma_resample" moved-to="video_chroma_resample">
|
|
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
|
|
|
|
]#
|