support for GTK 3.98.3

This commit is contained in:
Stefan Salewski 2020-05-19 14:19:38 +02:00
commit a725770ff0
15 changed files with 386 additions and 193 deletions

View file

@ -1,6 +1,6 @@
= High level GTK3 (and GTK4) bindings for the Nim programming language = High level GTK3 (and GTK4) bindings for the Nim programming language
(c) Stefan Salewski (c) Stefan Salewski
//Version 0.7.3 //Version 0.7.4
:experimental: :experimental:
:imagesdir: http://ssalewski.de/tmp :imagesdir: http://ssalewski.de/tmp
:source-highlighter: pygments :source-highlighter: pygments
@ -25,7 +25,9 @@ with code inserted from files directly.
NOTE: This work is partly based on earlier works of J. Mansour and has been supported by A. Rumpf, E. Bassi and other _Nim_ and _GTK/Gnome_ developers. NOTE: This work is partly based on earlier works of J. Mansour and has been supported by A. Rumpf, E. Bassi and other _Nim_ and _GTK/Gnome_ developers.
The `combinatorics` module was kindly provided by R. Behrends. The `combinatorics` module was kindly provided by R. Behrends.
NOTE: Starting with current version v0.7.3 we allow passing a type descriptor as first parameter to the NOTE: With current version 0.7.4 we support latest GTK 3.98.3 which may become GTK 4 at the end of 2020.
NOTE: Starting with version v0.7.3 we allow passing a type descriptor as first parameter to the
new() procs like `newButton(MyButtonSubclass)` to support subclassing and extending Widgets in OOP style. new() procs like `newButton(MyButtonSubclass)` to support subclassing and extending Widgets in OOP style.
See <<Extending or sub-classing Widgets>> for an complete example. The init() procs which were used See <<Extending or sub-classing Widgets>> for an complete example. The init() procs which were used
before for this task are now deprecated and will be removed later. This new approach generally saves before for this task are now deprecated and will be removed later. This new approach generally saves
@ -2723,6 +2725,7 @@ proc main =
## Wait until error or EOS ## Wait until error or EOS
bus = gst.getBus(pipeline) bus = gst.getBus(pipeline)
msg = gst.timedPopFiltered(bus, gst.Clock_Time_None, {gst.MessageFlag.error, gst.MessageFlag.eos}) msg = gst.timedPopFiltered(bus, gst.Clock_Time_None, {gst.MessageFlag.error, gst.MessageFlag.eos})
echo msg.getType
discard gst.setState(pipeline, gst.State.null) # is this necessary? discard gst.setState(pipeline, gst.State.null) # is this necessary?
main() main()
@ -2752,8 +2755,10 @@ button, but called after gtk4.main(). A bit strange indeed, see forum note of Mr
.headerbar.nim .headerbar.nim
---- ----
# https://github.com/GNOME/gtk/blob/mainline/tests/testheaderbar.c # https://github.com/GNOME/gtk/blob/mainline/tests/testheaderbar.c
# this is still based on the original testheaderbar.c, which was recently replaced by testheaderbar2.c
# and testheaderbar.c is not a very good Nim GTK4 example unfortunately -- too comlicated and strange code.
# nim c headerbar.nim # nim c headerbar.nim
import gintro/[gtk4, glib, gobject, gio] import gintro/[gtk4, glib, gobject]
const const
Css = """ Css = """
@ -2775,7 +2780,7 @@ const
# we try to avoid use of global header variable as done in C code # we try to avoid use of global header variable as done in C code
type type
MyWindow = ref object of gtk4.Window MyWindow = ref object of gtk4.Window
header: gtk4.Headerbar header: gtk4.Widget
proc response(d: gtk4.FileChooserDialog; responseID: int) = gtk4.destroy(d) proc response(d: gtk4.FileChooserDialog; responseID: int) = gtk4.destroy(d)
@ -2787,11 +2792,11 @@ proc onBookmarkClicked(button: Button; data: MyWindow) =
chooser.connect("response", response) chooser.connect("response", response)
chooser.show chooser.show
proc changeSubtitle(button: Button; w: MyWindow) = #proc changeSubtitle(button: Button; w: MyWindow) =
if w.header.subtitle == "": # if w.header.subtitle == "":
w.header.setSubtitle("(subtle subtitle)") # w.header.setSubtitle("(subtle subtitle)")
else: # else:
w.header.setSubtitle("") # can we pass nil? # w.header.setSubtitle("") # can we pass nil?
proc toggleFullscreen(button: Button; window: MyWindow) = proc toggleFullscreen(button: Button; window: MyWindow) =
var fullscreen {.global.}: bool var fullscreen {.global.}: bool
@ -2807,68 +2812,85 @@ proc toIntVal(i: int): Value =
discard init(result, gtype) discard init(result, gtype)
setInt(result, i) setInt(result, i)
proc quit(b: Button) = gtk4.mainQuit() var done = false
proc quit_cb(b: Button) = # we can not pass a var parameter
#gtk4.mainQuit()
done = true
wakeup(defaultMainContext()) # g_main_context_wakeup (NULL);
proc changeHeader(button: ToggleButton; window: MyWindow) = proc changeHeader(button: ToggleButton; window: MyWindow) =
if button != nil and button.getActive: if button != nil and button.getActive:
window.header = cast[HeaderBar](newBox(gtk4.Orientation.horizontal, window.header = (newBox(gtk4.Orientation.horizontal,
10)) # intended cast, see C code! 10))
addClass(getStyleContext(window.header), "titlebar") addCssClass(window.header, "titlebar")
addClass(getStyleContext(window.header), "header-bar") addCssClass(window.header, "header-bar")
window.header.setProperty("margin", toIntVal(10)) #window.header.setProperty("margin_start", toIntVal(10))
#window.header.setProperty("margin_end", toIntVal(10))
#window.header.setProperty("margin_top", toIntVal(10))
#window.header.setProperty("margin_bottom", toIntVal(10))
window.header.setMarginStart(10)
window.header.setMarginEnd(10)
window.header.setMarginTop(10)
window.header.setMarginBottom(10)
let label = newLabel("Label") let label = newLabel("Label")
window.header.add(label) gtk4.Box(window.header).append(label)
let levelBar = newLevelBar() let levelBar = newLevelBar()
levelBar.setValue(0.4) levelBar.setValue(0.4)
levelBar.setHexpand levelBar.setHexpand
window.header.add(levelBar) gtk4.Box(window.header).append(levelBar)
else: else:
window.header = newHeaderBar() window.header = newHeaderBar()
addClass(getStyleContext(window.header), "titlebar") #addClass(getStyleContext(window.header), "titlebar")
window.header.setTitle("Example header") addCssClass(window.header, "titlebar")
#window.header.setTitle("Example header")
var button = newButton("_Close") var button = newButton("_Close")
button.setUseUnderline button.setUseUnderline
addClass(getStyleContext(button), "suggested-action") addCssClass(button, "suggested-action")
button.connect("clicked", quit) button.connect("clicked", quit_cb)
window.header.packEnd(button) gtk4.HeaderBar(window.header).packEnd(button)
button = newButton() button = newButton()
let image = newImageFromIconName("bookmark-new-symbolic") let image = newImageFromIconName("bookmark-new-symbolic")
button.connect("clicked", onBookmarkClicked, window) button.connect("clicked", onBookmarkClicked, window)
button.add(image) button.setChild(image)
window.header.packStart(button) gtk4.HeaderBar(window.header).packStart(button)
window.setTitlebar(window.header) window.setTitlebar(window.header)
proc main = proc main =
gtk4.init() gtk4.init()
var window: MyWindow #var window: MyWindow
initWindow(window) let window = newWindow(MyWindow)
addClass(getStyleContext(window), "main") addCssClass(window, "main") # gtk_widget_add_css_class (window, "main");
let provider = newCssProvider() let provider = newCssProvider()
provider.loadFromData(Css) provider.loadFromData(Css)
addProviderForDisplay(getDisplay(window), provider, STYLE_PROVIDER_PRIORITY_USER) addProviderForDisplay(getDisplay(window), provider, STYLE_PROVIDER_PRIORITY_USER)
changeHeader(nil, window) changeHeader(nil, window)
let box = newBox(Orientation.vertical, 0) let box = newBox(Orientation.vertical, 0)
window.add(box) window.setChild(box) # gtk_window_set_child (GTK_WINDOW (window), box);
#window.add(box)
let content = newImageFromIconName("start-here-symbolic") let content = newImageFromIconName("start-here-symbolic")
content.setPixelSize(512) content.setPixelSize(512)
box.add(content) content.setVexpand
box.append(content)
let footer = newActionBar() let footer = newActionBar()
footer.setCenterWidget(newCheckButtonWithLabel("Middle")) footer.setCenterWidget(newCheckButtonWithLabel("Middle"))
let button = newToggleButtonWithLabel("Custom") let button = newToggleButtonWithLabel("Custom")
button.connect("clicked", changeHeader, window) button.connect("clicked", changeHeader, window)
footer.packStart(button) footer.packStart(button)
var button1 = newButton("Subtitle") #var button1 = newButton("Subtitle")
button1.connect("clicked", changeSubtitle, window) #button1.connect("clicked", changeSubtitle, window)
footer.packEnd(button1) #footer.packEnd(button1)
button1 = newButton("Fullscreen") var button1 = newButton("Fullscreen")
footer.packEnd(button1) footer.packEnd(button1)
button1.connect("clicked", toggleFullscreen, window) button1.connect("clicked", toggleFullscreen, window)
box.add(footer) box.append(footer)
window.show window.show
gtk4.main() #gtk4.main()
while not done:
discard iteration(defaultMainContext(), true) # g_main_context_iteration (NULL, TRUE);
destroy(window) # this is special for this example, see https://discourse.gnome.org/t/tests-testgaction-c/2232/6 destroy(window) # this is special for this example, see https://discourse.gnome.org/t/tests-testgaction-c/2232/6
main() # 118 lines main() # 137 lines
---- ----
NOTE: Related work: https://github.com/jdmansour/nim-smartgi NOTE: Related work: https://github.com/jdmansour/nim-smartgi

View file

@ -1,6 +1,6 @@
# app0.nim -- minimal application style example # app0.nim -- minimal application style example
# nim c app0.nim # nim c app0.nim
import gintro/[gtk, glib, gobject, gio] import gintro/[gtk, gobject, gio]
proc appActivate(app: Application) = proc appActivate(app: Application) =
let window = newApplicationWindow(app) let window = newApplicationWindow(app)

View file

@ -1,7 +1,7 @@
# https://developer.gnome.org/gtk3/stable/ch01s03.html # https://developer.gnome.org/gtk3/stable/ch01s03.html
# builder.nim -- application style example using builder/glade xml file for user interface # builder.nim -- application style example using builder/glade xml file for user interface
# nim c builder.nim # nim c builder.nim
import gintro/[gtk, glib, gobject, gio] import gintro/[gtk, gobject, gio]
proc hello(b: Button; msg: string) = proc hello(b: Button; msg: string) =
echo "Hello", msg echo "Hello", msg

View file

@ -1,6 +1,6 @@
# This example shows how to apply a CellDataFunc to a GtkTreeView # This example shows how to apply a CellDataFunc to a GtkTreeView
# C example code was provided by A.Krause in chapter 8 of his book # C example code was provided by A.Krause in chapter 8 of his book
import gintro/[gtk, gobject, glib] import gintro/[gtk, gobject]
const const
Color = 0 Color = 0

View file

@ -0,0 +1,55 @@
# nim c button.nim
import gintro/[gtk, glib, gobject, gio, cairo]
from math import Tau
type
ColorPicker = ref object of Button
c: array[4, float]
proc newColorPicker(c: array[4, float]): ColorPicker =
result = newButton(ColorPicker)
result.c = c
proc buttonClicked (button: ColorPicker) =
#button.label = utf8Strreverse(button.label, -1)
echo "clicked"
proc draw(b: ColorPicker; cr: cairo.Context): bool =
echo "draw"
let x = getAllocatedWidth(b).float / 2
let y = getAllocatedHeight(b).float / 2
cr.moveTo(x, y)
cr.newPath
cr.arc(x, y, 10, 0, math.Tau)
cr.setSource(b.c)
cr.setLineWidth(5)
cr.stroke
proc appActivate (app: Application) =
let window = newApplicationWindow(app)
window.title = "GNOME Button"
window.defaultSize = (250, 50)
let box = newBox(Orientation.horizontal, 0)
var button = newColorPicker([1.0, 0, 0, 1])#newButton(ColorPicker)#"Click Me")
box.add(button)
button.connect("clicked", buttonClicked)
button.connectAfter("draw", draw)
button = newColorPicker([0.0, 0, 1, 1])#newButton(ColorPicker)#"Click Me")
box.add(button)
button.connect("clicked", buttonClicked)
button.connectAfter("draw", draw)
button = newColorPicker([0.0, 1, 0, 1])#newButton(ColorPicker)#"Click Me")
box.add(button)
button.connect("clicked", buttonClicked)
button.connectAfter("draw", draw)
window.add(box)
window.showAll
proc main =
let app = newApplication("org.gtk.example")
connect(app, "activate", appActivate)
discard app.run
main()

View file

@ -60,7 +60,7 @@ type
handlerID: uint64 handlerID: uint64
proc newPosAdj: PosAdj = proc newPosAdj: PosAdj =
initAdjustment(result, 0, 0, 1, 1, 10, 1) newAdjustment(PosAdj, 0, 0, 1, 1, 10, 1)
type type
PDA_Data* = object PDA_Data* = object
@ -104,7 +104,7 @@ proc drawingAreaDrawCb(darea: DrawingArea; cr: Context; this: PDA): bool =
if this.selecting: if this.selecting:
cr.rectangle(this.lastButtonDownPosX, this.lastButtonDownPosY, cr.rectangle(this.lastButtonDownPosX, this.lastButtonDownPosY,
this.zoomRectX1 - this.lastButtonDownPosX, this.zoomRectY1 - this.lastButtonDownPosY) this.zoomRectX1 - this.lastButtonDownPosX, this.zoomRectY1 - this.lastButtonDownPosY)
cr.setSource(0, 0, 1, 0.5) # SELECT_RECT_COL) # 0, 0, 1, 0.5 cr.setSource(SelectRectCol) # SELECT_RECT_COL) # 0, 0, 1, 0.5
cr.fillPreserve cr.fillPreserve
cr.setSource(0, 0, 0) cr.setSource(0, 0, 0)
cr.setLineWidth(2) cr.setLineWidth(2)
@ -256,7 +256,7 @@ proc onAdjustmentEvent(this: PosAdj; pda: PDA) =
pda.darea.queueDrawArea(0, 0, pda.darea.allocatedWidth, pda.darea.allocatedHeight) pda.darea.queueDrawArea(0, 0, pda.darea.allocatedWidth, pda.darea.allocatedHeight)
proc newPDA: PDA = proc newPDA: PDA =
initGrid(result) result = newGrid(PDA)
let da = newDrawingArea() let da = newDrawingArea()
result.darea = da result.darea = da
da.setHExpand da.setHExpand

View file

@ -62,9 +62,9 @@ proc radio(action: SimpleAction; parameter: Variant; label: Label) =
let str: string = "From Radio menu item " & getString(newState, l) let str: string = "From Radio menu item " & getString(newState, l)
label.setLabel(str) label.setLabel(str)
proc bye(w: Window) = #proc bye(w: Window) =
mainQuit() # mainQuit()
echo "Bye..." # echo "Bye..."
proc main = proc main =
gtk.init() gtk.init()

View file

@ -1,13 +1,13 @@
# gsettings.nim -- basic use of gsettings # gsettings.nim -- basic use of gsettings
# nim c gsettings.nim # nim c gsettings.nim
# https://blog.gtk.org/2017/05/01/first-steps-with-gsettings/ # https://blog.gtk.org/2017/05/01/first-steps-with-gsettings/
import gintro/[gtk, glib, gobject, gio] import gintro/[gtk, gobject, gio]
# unused # unused
proc toggle(b: CheckButton) = #proc toggle(b: CheckButton) =
echo b.active # echo b.active
let s = newSettings("org.gnome.Recipes") # let s = newSettings("org.gnome.Recipes")
discard s.setBoolean("like-nim", b.active) # discard s.setBoolean("like-nim", b.active)
proc appActivate(app: Application) = proc appActivate(app: Application) =
let window = newApplicationWindow(app) let window = newApplicationWindow(app)

View file

@ -15,6 +15,7 @@ proc main =
## Wait until error or EOS ## Wait until error or EOS
bus = gst.getBus(pipeline) bus = gst.getBus(pipeline)
msg = gst.timedPopFiltered(bus, gst.Clock_Time_None, {gst.MessageFlag.error, gst.MessageFlag.eos}) msg = gst.timedPopFiltered(bus, gst.Clock_Time_None, {gst.MessageFlag.error, gst.MessageFlag.eos})
echo msg.getType
discard gst.setState(pipeline, gst.State.null) # is this necessary? discard gst.setState(pipeline, gst.State.null) # is this necessary?
main() main()

View file

@ -53,7 +53,7 @@ type
handlerID: uint64 handlerID: uint64
proc newPosAdj: PosAdj = proc newPosAdj: PosAdj =
initAdjustment(result, 0, 0, 1, 1, 10, 1) newAdjustment(PosAdj, 0, 0, 1, 1, 10, 1)
type type
PDA_Data* = object PDA_Data* = object
@ -98,7 +98,7 @@ proc drawingAreaDrawCb(darea: DrawingArea; cr: Context; this: PDA): bool =
if this.selecting: if this.selecting:
cr.rectangle(this.lastButtonDownPosX, this.lastButtonDownPosY, cr.rectangle(this.lastButtonDownPosX, this.lastButtonDownPosY,
this.zoomRectX1 - this.lastButtonDownPosX, this.zoomRectY1 - this.lastButtonDownPosY) this.zoomRectX1 - this.lastButtonDownPosX, this.zoomRectY1 - this.lastButtonDownPosY)
cr.setSource(0, 0, 1, 0.5) # SELECT_RECT_COL) # 0, 0, 1, 0.5 cr.setSource(SelectRectCol) # SELECT_RECT_COL) # 0, 0, 1, 0.5
cr.fillPreserve cr.fillPreserve
cr.setSource(0, 0, 0) cr.setSource(0, 0, 0)
cr.setLineWidth(2) cr.setLineWidth(2)
@ -227,7 +227,7 @@ proc onAdjustmentEvent(this: PosAdj; pda: PDA) =
pda.darea.queueDrawArea(0, 0, pda.darea.allocatedWidth, pda.darea.allocatedHeight) pda.darea.queueDrawArea(0, 0, pda.darea.allocatedWidth, pda.darea.allocatedHeight)
proc newPDA: PDA = proc newPDA: PDA =
initGrid(result) result = newGrid(PDA)
let da = newDrawingArea() let da = newDrawingArea()
result.darea = da result.darea = da
da.setHExpand da.setHExpand

View file

@ -1,4 +1,4 @@
import gintro/[gtk, glib, gobject, gio, gtksource] import gintro/[gtk, gobject, gio, gtksource]
proc appActivate (app: Application) = proc appActivate (app: Application) =
let window = newApplicationWindow(app) let window = newApplicationWindow(app)

View file

@ -1,6 +1,6 @@
# app0.nim -- minimal application style example # app0.nim -- minimal application style example
# nim c app0.nim # nim c app0.nim
import gintro/[gtk4, glib, gobject, gio] import gintro/[gtk4, gobject, gio]
proc appActivate(app: Application) = proc appActivate(app: Application) =
let window = newApplicationWindow(app) let window = newApplicationWindow(app)

View file

@ -1,6 +1,8 @@
# https://github.com/GNOME/gtk/blob/mainline/tests/testheaderbar.c # https://github.com/GNOME/gtk/blob/mainline/tests/testheaderbar.c
# this is still based on the original testheaderbar.c, which was recently replaced by testheaderbar2.c
# and testheaderbar.c is not a very good Nim GTK4 example unfortunately -- too comlicated and strange code.
# nim c headerbar.nim # nim c headerbar.nim
import gintro/[gtk4, glib, gobject, gio] import gintro/[gtk4, glib, gobject]
const const
Css = """ Css = """
@ -22,7 +24,7 @@ const
# we try to avoid use of global header variable as done in C code # we try to avoid use of global header variable as done in C code
type type
MyWindow = ref object of gtk4.Window MyWindow = ref object of gtk4.Window
header: gtk4.Headerbar header: gtk4.Widget
proc response(d: gtk4.FileChooserDialog; responseID: int) = gtk4.destroy(d) proc response(d: gtk4.FileChooserDialog; responseID: int) = gtk4.destroy(d)
@ -34,11 +36,11 @@ proc onBookmarkClicked(button: Button; data: MyWindow) =
chooser.connect("response", response) chooser.connect("response", response)
chooser.show chooser.show
proc changeSubtitle(button: Button; w: MyWindow) = #proc changeSubtitle(button: Button; w: MyWindow) =
if w.header.subtitle == "": # if w.header.subtitle == "":
w.header.setSubtitle("(subtle subtitle)") # w.header.setSubtitle("(subtle subtitle)")
else: # else:
w.header.setSubtitle("") # can we pass nil? # w.header.setSubtitle("") # can we pass nil?
proc toggleFullscreen(button: Button; window: MyWindow) = proc toggleFullscreen(button: Button; window: MyWindow) =
var fullscreen {.global.}: bool var fullscreen {.global.}: bool
@ -54,65 +56,82 @@ proc toIntVal(i: int): Value =
discard init(result, gtype) discard init(result, gtype)
setInt(result, i) setInt(result, i)
proc quit(b: Button) = gtk4.mainQuit() var done = false
proc quit_cb(b: Button) = # we can not pass a var parameter
#gtk4.mainQuit()
done = true
wakeup(defaultMainContext()) # g_main_context_wakeup (NULL);
proc changeHeader(button: ToggleButton; window: MyWindow) = proc changeHeader(button: ToggleButton; window: MyWindow) =
if button != nil and button.getActive: if button != nil and button.getActive:
window.header = cast[HeaderBar](newBox(gtk4.Orientation.horizontal, window.header = (newBox(gtk4.Orientation.horizontal,
10)) # intended cast, see C code! 10))
addClass(getStyleContext(window.header), "titlebar") addCssClass(window.header, "titlebar")
addClass(getStyleContext(window.header), "header-bar") addCssClass(window.header, "header-bar")
window.header.setProperty("margin", toIntVal(10)) #window.header.setProperty("margin_start", toIntVal(10))
#window.header.setProperty("margin_end", toIntVal(10))
#window.header.setProperty("margin_top", toIntVal(10))
#window.header.setProperty("margin_bottom", toIntVal(10))
window.header.setMarginStart(10)
window.header.setMarginEnd(10)
window.header.setMarginTop(10)
window.header.setMarginBottom(10)
let label = newLabel("Label") let label = newLabel("Label")
window.header.add(label) gtk4.Box(window.header).append(label)
let levelBar = newLevelBar() let levelBar = newLevelBar()
levelBar.setValue(0.4) levelBar.setValue(0.4)
levelBar.setHexpand levelBar.setHexpand
window.header.add(levelBar) gtk4.Box(window.header).append(levelBar)
else: else:
window.header = newHeaderBar() window.header = newHeaderBar()
addClass(getStyleContext(window.header), "titlebar") #addClass(getStyleContext(window.header), "titlebar")
window.header.setTitle("Example header") addCssClass(window.header, "titlebar")
#window.header.setTitle("Example header")
var button = newButton("_Close") var button = newButton("_Close")
button.setUseUnderline button.setUseUnderline
addClass(getStyleContext(button), "suggested-action") addCssClass(button, "suggested-action")
button.connect("clicked", quit) button.connect("clicked", quit_cb)
window.header.packEnd(button) gtk4.HeaderBar(window.header).packEnd(button)
button = newButton() button = newButton()
let image = newImageFromIconName("bookmark-new-symbolic") let image = newImageFromIconName("bookmark-new-symbolic")
button.connect("clicked", onBookmarkClicked, window) button.connect("clicked", onBookmarkClicked, window)
button.add(image) button.setChild(image)
window.header.packStart(button) gtk4.HeaderBar(window.header).packStart(button)
window.setTitlebar(window.header) window.setTitlebar(window.header)
proc main = proc main =
gtk4.init() gtk4.init()
var window: MyWindow #var window: MyWindow
initWindow(window) let window = newWindow(MyWindow)
addClass(getStyleContext(window), "main") addCssClass(window, "main") # gtk_widget_add_css_class (window, "main");
let provider = newCssProvider() let provider = newCssProvider()
provider.loadFromData(Css) provider.loadFromData(Css)
addProviderForDisplay(getDisplay(window), provider, STYLE_PROVIDER_PRIORITY_USER) addProviderForDisplay(getDisplay(window), provider, STYLE_PROVIDER_PRIORITY_USER)
changeHeader(nil, window) changeHeader(nil, window)
let box = newBox(Orientation.vertical, 0) let box = newBox(Orientation.vertical, 0)
window.add(box) window.setChild(box) # gtk_window_set_child (GTK_WINDOW (window), box);
#window.add(box)
let content = newImageFromIconName("start-here-symbolic") let content = newImageFromIconName("start-here-symbolic")
content.setPixelSize(512) content.setPixelSize(512)
box.add(content) content.setVexpand
box.append(content)
let footer = newActionBar() let footer = newActionBar()
footer.setCenterWidget(newCheckButtonWithLabel("Middle")) footer.setCenterWidget(newCheckButtonWithLabel("Middle"))
let button = newToggleButtonWithLabel("Custom") let button = newToggleButtonWithLabel("Custom")
button.connect("clicked", changeHeader, window) button.connect("clicked", changeHeader, window)
footer.packStart(button) footer.packStart(button)
var button1 = newButton("Subtitle") #var button1 = newButton("Subtitle")
button1.connect("clicked", changeSubtitle, window) #button1.connect("clicked", changeSubtitle, window)
footer.packEnd(button1) #footer.packEnd(button1)
button1 = newButton("Fullscreen") var button1 = newButton("Fullscreen")
footer.packEnd(button1) footer.packEnd(button1)
button1.connect("clicked", toggleFullscreen, window) button1.connect("clicked", toggleFullscreen, window)
box.add(footer) box.append(footer)
window.show window.show
gtk4.main() #gtk4.main()
while not done:
discard iteration(defaultMainContext(), true) # g_main_context_iteration (NULL, TRUE);
destroy(window) # this is special for this example, see https://discourse.gnome.org/t/tests-testgaction-c/2232/6 destroy(window) # this is special for this example, see https://discourse.gnome.org/t/tests-testgaction-c/2232/6
main() # 118 lines main() # 137 lines

View file

@ -1,6 +1,6 @@
# Package # Package
version = "0.7.3" version = "0.7.4"
author = "Stefan Salewski" author = "Stefan Salewski"
description = "High level GObject-Introspection based GTK3/GTK4 bindings" description = "High level GObject-Introspection based GTK3/GTK4 bindings"
license = "MIT" license = "MIT"

View file

@ -1,6 +1,6 @@
# High level gobject-introspection based GTK3/GTK4 bindings for the Nim programming language # High level gobject-introspection based GTK3/GTK4 bindings for the Nim programming language
# nimpretty --maxLineLen:130 gen.nim # nimpretty --maxLineLen:130 gen.nim
# v 0.7.3 2020-MAR-09 # v 0.7.4 2020-MAY-19
# (c) S. Salewski 2018 # (c) S. Salewski 2018
# https://wiki.gnome.org/Projects/GObjectIntrospection # https://wiki.gnome.org/Projects/GObjectIntrospection
@ -33,9 +33,7 @@
# This module is really ugly currently -- the first goal was to get a working gi solution # 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() -- for # NOTE: Currently we support subclassing only for constructor functions like gtk_button_new()
# these we provide an initButton() additional to the well know newButton(). Maybe other functions
# with a result variable that we may intent to subclass should get a init() variant also...
from os import `/`, paramCount from os import `/`, paramCount
import gir, gobject, glib import gir, gobject, glib
@ -167,6 +165,8 @@ var allSyms: HashSet[string]
var droppedSyms: HashSet[string] var droppedSyms: HashSet[string]
var privStr: HashSet[string] var privStr: HashSet[string]
var processedFunctions: HashSet[string] var processedFunctions: HashSet[string]
var useTempProcessedFunctions: bool
var tempProcessedFunctions: seq[string]
var knownSyms: HashSet[string] var knownSyms: HashSet[string]
var gdkKeys: Table[string, seq[string]] var gdkKeys: Table[string, seq[string]]
@ -210,9 +210,14 @@ fixedProcNames.add("gtk_settings_get_for_display", "getSettingsForDisplay")
fixedProcNames.add("gtk_icon_theme_get_for_display", "getIconThemeForDisplay") fixedProcNames.add("gtk_icon_theme_get_for_display", "getIconThemeForDisplay")
fixedProcNames.add("gst_element_factory_find", "findElementFactory") fixedProcNames.add("gst_element_factory_find", "findElementFactory")
fixedProcNames.add("gtk_shortcut_action_parse_string", "shortcutActionParseString")
fixedProcNames.add("gtk_shortcut_trigger_parse_string", "shortcutTriggerParseString")
fixedProcNames.add("g_main_context_default", "defaultMainContext")
defaultParameters.add("gtk_window_new", "`type` WindowType WindowType.toplevel") defaultParameters.add("gtk_window_new", "`type` WindowType WindowType.toplevel")
defaultParameters.add("gtk_application_new", "flags gio.ApplicationFlags {}") defaultParameters.add("gtk_application_new", "flags gio.ApplicationFlags {}")
defaultParameters.add("gtk_builder_new_from_string", "length int64 -1") defaultParameters.add("gtk_builder_new_from_string", "length int64 -1")
defaultParameters.add("gtk_box_new", "spacing int32 0")
for i in keywords: mangledNames.add(i, '`' & i & '`') for i in keywords: mangledNames.add(i, '`' & i & '`')
@ -340,10 +345,11 @@ graphene.Euler
#cairo.Matrix #cairo.Matrix
cairo.Rectangle cairo.Rectangle
cairo.RectangleInt cairo.RectangleInt
gsk.RoundedRect
""".split.toHashSet """.split.toHashSet
type type
UndefEx = object of Exception UndefEx = object of CatchableError
proc mangleType(s: cstring): string = proc mangleType(s: cstring): string =
result = mangleName(s) result = mangleName(s)
@ -534,7 +540,10 @@ proc genPars(info: GICallableInfo; genProxy = false; binfo: GIBaseInfo = nil): (
self = "(self: " & manglename(gBaseInfoGetName(binfo)) & "; " self = "(self: " & manglename(gBaseInfoGetName(binfo)) & "; "
arglist = "(self" arglist = "(self"
else: else:
arglist = "(cast[ptr " & manglename(gBaseInfoGetName(binfo)) & "00](" & "self.impl)" ## only for very few procs the instance variable itself can be NULL in GTK. We assume non NULL and may provide an overload.
arglist = "(cast[ptr " & manglename(gBaseInfoGetName(binfo)) & "00](" &
"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: if genProxy:
var h = manglename(gBaseInfoGetName(binfo)) var h = manglename(gBaseInfoGetName(binfo))
let provider = interfaceProvider.getOrDefault(h, @[]) let provider = interfaceProvider.getOrDefault(h, @[])
@ -759,6 +768,18 @@ proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo) =
if boxedFreeMeName == "gBoxedFreeGVariantType": # this does not work if boxedFreeMeName == "gBoxedFreeGVariantType": # this does not work
assert false 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 = ""
freeMeName = "generic_" & $g_object_info_get_unref_function(parent)
assert(freeMeName != "")
# assert(info != nil) # why can it be nil? # assert(info != nil) # why can it be nil?
assert(isCallableInfo(mInfo)) assert(isCallableInfo(mInfo))
assert(isFunctionInfo(mInfo)) assert(isFunctionInfo(mInfo))
@ -819,6 +840,7 @@ proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo) =
try: try:
(plist, arglist, replist, arrLex) = genPars(mInfo, false, info) (plist, arglist, replist, arrLex) = genPars(mInfo, false, info)
processedFunctions.incl(sym) processedFunctions.incl(sym)
if not sym.startsWith("g_param_spec_uref"):
if sym.startsWith("g_param_spec_", "g_type_interface_", "g_object_interface_"): return 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", if sym in ["gtk_widget_class_find_style_property", "gtk_container_class_find_child_property",
"gtk_cell_area_class_find_cell_property"]: return "gtk_cell_area_class_find_cell_property"]: return
@ -878,7 +900,8 @@ proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo) =
let tag = gTypeInfoGetTag(ret2) let tag = gTypeInfoGetTag(ret2)
if tag == GITypeTag.INTERFACE: if tag == GITypeTag.INTERFACE:
let iface = gTypeInfoGetInterface(ret2) let iface = gTypeInfoGetInterface(ret2)
if gBaseInfoGetType(iface) == GIInfoType.Object and gBaseInfoGetName(iface) != "ParamSpec": #if gBaseInfoGetType(iface) == GIInfoType.Object and gBaseInfoGetName(iface) != "ParamSpec":
if gBaseInfoGetType(iface) == GIInfoType.Object and gObjectInfoGetFundamental(iface) == GFalse:
isGObject = true isGObject = true
(plist, arglist, replist, arrLex, blex) = genPars(mInfo, true, info) (plist, arglist, replist, arrLex, blex) = genPars(mInfo, true, info)
var sss = "" var sss = ""
@ -954,6 +977,7 @@ proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo) =
methodBuffer.writeLine(" fnew(result, $1)" % boxedFreeMeName) methodBuffer.writeLine(" fnew(result, $1)" % boxedFreeMeName)
elif freeMeName == "": elif freeMeName == "":
assert false assert false
echo "????????", sym
methodBuffer.writeLine(" new(result)") methodBuffer.writeLine(" new(result)")
else: else:
methodBuffer.writeLine(" fnew(result, $1)" % freeMeName) methodBuffer.writeLine(" fnew(result, $1)" % freeMeName)
@ -999,16 +1023,17 @@ proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo) =
assert tag == GITypeTag.INTERFACE assert tag == GITypeTag.INTERFACE
var iface = gTypeInfoGetInterface(ret2) var iface = gTypeInfoGetInterface(ret2)
if gBaseInfoGetType(iface) == GIInfoType.INTERFACE: if gBaseInfoGetType(iface) == GIInfoType.INTERFACE:
#methodBuffer.writeLine("#GIInfoType.INTERFACE")
gobjectTemp() gobjectTemp()
#iface = gInterfaceInfoGetIfaceStruct(iface) #iface = gInterfaceInfoGetIfaceStruct(iface)
#methodBuffer.writeLine(" fnew(result, $1genericGObjectUnref) # Interface" % [mprefix]) #methodBuffer.writeLine(" fnew(result, $1genericGObjectUnref) # Interface" % [mprefix])
#methodBuffer.writeLine(" result.impl = " & sym & arglist) #methodBuffer.writeLine(" result.impl = " & sym & arglist)
elif gBaseInfoGetType(iface) == GIInfoType.OBJECT: # rare, ParamSpec in gobject.nim elif false: #gBaseInfoGetType(iface) == GIInfoType.OBJECT: # rare, ParamSpec in gobject.nim
#echo "XXXXXXXXXXXXXXXXX what shall we do? for ", sym #echo "XXXXXXXXXXXXXXXXX what shall we do? for ", sym
methodBuffer.writeLine(" fnew(result, $1genericGObjectUnref) # Object" % [mprefix]) methodBuffer.writeLine(" fnew(result, $1genericGObjectUnref) # Object" % [mprefix])
methodBuffer.writeLine(" result.impl = " & sym & arglist) methodBuffer.writeLine(" result.impl = " & sym & arglist)
else: else:
assert(gBaseInfoGetType(iface) in {GIInfoType.STRUCT, GIInfoType.UNION}) assert(gBaseInfoGetType(iface) in {GIInfoType.STRUCT, GIInfoType.UNION, GIInfoType.OBJECT})
var freeMeName: string var freeMeName: string
var freeMe: GIFunctionInfo var freeMe: GIFunctionInfo
var boxedFreeMeName: string var boxedFreeMeName: string
@ -1017,7 +1042,7 @@ proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo) =
methodBuffer.writeLine(" fnew(result, $1)" % boxedFreeMeName) methodBuffer.writeLine(" fnew(result, $1)" % boxedFreeMeName)
elif freeMeName == "": elif freeMeName == "":
# assert false # TODO we have to fix this case manually # assert false # TODO we have to fix this case manually
#echo "xCaution: No free/unref found for ", ' ', gBaseInfoGetName(iface), " (", sym, ')' # echo "xCaution: No free/unref found for ", ' ', gBaseInfoGetName(iface), " (", sym, ')' # check this from time to time!
methodBuffer.writeLine(" new(result)") methodBuffer.writeLine(" new(result)")
else: else:
methodBuffer.writeLine(" fnew(result, $1)" % freeMeName) methodBuffer.writeLine(" fnew(result, $1)" % freeMeName)
@ -1149,18 +1174,39 @@ proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo) =
methodBuffer.writeLine("\nproc `defaultSize=`*(self: Window; dim: tuple[width: int; height: int]) =") 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]))") methodBuffer.writeLine(" gtk_window_set_default_size(cast[ptr Window00](self.impl), int32(dim[0]), int32(dim[1]))")
if sym == "g_object_unref": if sym == "g_object_unref":
methodBuffer.writeLine("\nproc genericGObjectUnref*[T](self: ref T) =") # 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(" if not self.ignoreFinalizer:")
methodBuffer.writeLine(" g_object_unref(cast[ptr Object00](self.impl))") methodBuffer.writeLine(" g_object_unref(cast[ptr Object00](self.impl))")
#if gBaseInfoGetType(info) == GIInfoType.Object and isgobject
if info != nil and gBaseInfoGetType(info) == GIInfoType.Object and gObjectInfoGetFundamental(info) == GTrue and sym.endsWith("unref"):
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: except UndefEx:
processedFunctions.excl(sym) processedFunctions.excl(sym)
delayedMethods.add((info, minfo)) delayedMethods.add((info, minfo))
methodBuffer.cut(p) methodBuffer.cut(p)
template genBoxedFree = template genBoxedFree =
if not callerAlloc.contains(($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName(info))): if not callerAlloc.contains(($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName(info))):
if gRegisteredTypeInfoGetGType(info) != G_TYPE_NONE and gTypeFundamental(gRegisteredTypeInfoGetGType(info)) == G_TYPE_BOXED and 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 gBaseInfoGetName(info) != "VariantType": # we have no g_variant_type_get_gtype
# For example, GVariant has a GType but is not a boxed type # 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) #assert(g_type_fundamental(g_registered_type_info_get_g_type(info)) == G_TYPE_BOXED)
@ -1195,12 +1241,7 @@ template genBoxedFree =
else: else:
#if gStructInfoIsGtypeStruct(info) and gBaseInfoGetName(info) != "ObjectClass": #if gStructInfoIsGtypeStruct(info) and gBaseInfoGetName(info) != "ObjectClass":
assert gBaseInfoGetType(info) == GIInfoType.STRUCT assert gBaseInfoGetType(info) == GIInfoType.STRUCT
#echo "aaa", info.isNil
#echo "bbb", gStructInfoIsGtypeStruct(info)
#echo "ccc", gStructInfoGetNMethods(info)
#echo gBaseInfoGetName(info)
freeMe = gStructInfoFindMethod(info, "free") freeMe = gStructInfoFindMethod(info, "free")
#echo "xxxxxxxx"
if freeMe.isNil: if freeMe.isNil:
freeMe = gStructInfoFindMethod(info, "unref") freeMe = gStructInfoFindMethod(info, "unref")
@ -1208,7 +1249,6 @@ template genDestroyFreeUnref =
if not callerAlloc.contains(($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName(info))): if not callerAlloc.contains(($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName(info))):
if gRegisteredTypeInfoGetGType(info) == G_TYPE_NONE or gTypeFundamental(gRegisteredTypeInfoGetGType(info)) != G_TYPE_BOXED or if gRegisteredTypeInfoGetGType(info) == G_TYPE_NONE or gTypeFundamental(gRegisteredTypeInfoGetGType(info)) != G_TYPE_BOXED or
gBaseInfoGetName(info) == "VariantType": # we have no g_variant_type_get_gtype gBaseInfoGetName(info) == "VariantType": # we have no g_variant_type_get_gtype
#if true:
if gBaseInfoGetType(info) == GIInfoType.UNION or gBaseInfoGetType(info) == GIInfoType.STRUCT and if gBaseInfoGetType(info) == GIInfoType.UNION or gBaseInfoGetType(info) == GIInfoType.STRUCT and
gBaseInfoGetName(info) != "ObjectClass" and gBaseInfoGetName(info) != "TypeFind": gBaseInfoGetName(info) != "ObjectClass" and gBaseInfoGetName(info) != "TypeFind":
var freeMe: GIFunctionInfo var freeMe: GIFunctionInfo
@ -1217,7 +1257,6 @@ template genDestroyFreeUnref =
if freeMe.isNil: if freeMe.isNil:
freeMe = gUnionInfoFindMethod(info, "unref") freeMe = gUnionInfoFindMethod(info, "unref")
else: else:
#if gStructInfoIsGtypeStruct(info) and gBaseInfoGetName(info) != "ObjectClass":
assert gBaseInfoGetType(info) == GIInfoType.STRUCT assert gBaseInfoGetType(info) == GIInfoType.STRUCT
freeMe = gStructInfoFindMethod(info, "free") freeMe = gStructInfoFindMethod(info, "free")
if freeMe.isNil: if freeMe.isNil:
@ -1350,7 +1389,8 @@ proc writeStruct(info: GIStructInfo) =
output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & "00" & EM & " {.pure.} = object") output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & "00" & EM & " {.pure.} = object")
if WriteFields or callerAlloc.contains(($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName( if WriteFields or callerAlloc.contains(($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName(
info))) or info))) or
mangleName(gBaseInfoGetName(info)) == "TargetEntry": mangleName(gBaseInfoGetName(info)) == "TargetEntry" or
["gst.Message", "gst.MiniObject"].contains(($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName(info))):
for j in 0.cint ..< info.gStructInfoGetNFields(): for j in 0.cint ..< info.gStructInfoGetNFields():
let field = info.gStructInfoGetField(j) let field = info.gStructInfoGetField(j)
let name = manglename(gBaseInfoGetName(field)) & EM let name = manglename(gBaseInfoGetName(field)) & EM
@ -1506,7 +1546,7 @@ proc writeModifierType(info: GIEnumInfo) =
output.writeLine(i) output.writeLine(i)
output.writeLine("\n ", we & EM, " {.size: sizeof(cint).} = set[$1Flag]" % [tname]) output.writeLine("\n ", we & EM, " {.size: sizeof(cint).} = set[$1Flag]" % [tname])
if we == "ModifierType": if we == "ModifierType":
output.writeLine("\nconst ModifierMask* = {ModifierFlag.shift .. ModifierFlag.button5, ModifierFlag.super .. ModifierFlag.meta, ModifierFlag.release}") output.writeLine("\nconst ModifierMask* = {ModifierFlag.shift .. ModifierFlag.button5, ModifierFlag.super .. ModifierFlag.meta}") #, ModifierFlag.release}")
elif we == "EventMask": elif we == "EventMask":
output.writeLine("\nconst AllEventsMask* = {EventFlag.exposure .. EventFlag.smoothScroll}") output.writeLine("\nconst AllEventsMask* = {EventFlag.exposure .. EventFlag.smoothScroll}")
for j in 0.cint ..< gEnumInfoGetNMethods(info): for j in 0.cint ..< gEnumInfoGetNMethods(info):
@ -1638,7 +1678,7 @@ proc writeObj(info: GIObjectInfo) =
assert not callerAlloc.contains(($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName(info))) assert not callerAlloc.contains(($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName(info)))
when WriteFields: when WriteFields:
if mangleName(gBaseInfoGetName(info)) != "InitiallyUnowned": if mangleName(gBaseInfoGetName(info)) != "InitiallyUnowned":
for j in 0.cint ..< n: for j in 0.cint ..< info.gObjectInfoGetNFields():
let field = info.gObjectInfoGetField(j) let field = info.gObjectInfoGetField(j)
var name = mangleName(gBaseInfoGetName(field)) var name = mangleName(gBaseInfoGetName(field))
if privStr.contains(name) and cnt > 0: if privStr.contains(name) and cnt > 0:
@ -1674,6 +1714,7 @@ proc writeObj(info: GIObjectInfo) =
if getTypeProc notin ["intern", "g_gstring_get_type"]: if getTypeProc notin ["intern", "g_gstring_get_type"]:
output.write("\nproc " & getTypeProc & "*(): GType ") output.write("\nproc " & getTypeProc & "*(): GType ")
output.writeLine("{.importc, " & libprag & ".}") output.writeLine("{.importc, " & libprag & ".}")
let numsig = info.gObjectInfoGetNSignals let numsig = info.gObjectInfoGetNSignals
#if numsig > 0: signalbuffer.writeLine("") #if numsig > 0: signalbuffer.writeLine("")
for j in 0.cint ..< numsig: for j in 0.cint ..< numsig:
@ -1685,9 +1726,23 @@ proc writeObj(info: GIObjectInfo) =
var h = genPars(signalInfo, false)[0][1..^1] var h = genPars(signalInfo, false)[0][1..^1]
let zzzu = gCallableInfoGetReturnType(signalinfo) let zzzu = gCallableInfoGetReturnType(signalinfo)
writeSignal() writeSignal()
#for j in 0.cint ..< gObjectInfoGetNMethods(info):
# let mInfo = gObjectInfoGetMethod(info, j)
# writeMethod(info, minfo)
var mseq: seq[GIFunctionInfo]
var freePos = -1
for j in 0.cint ..< gObjectInfoGetNMethods(info): for j in 0.cint ..< gObjectInfoGetNMethods(info):
let mInfo = gObjectInfoGetMethod(info, j) mseq.add(gObjectInfoGetMethod(info, j))
if freePos < 0 and gBaseInfoGetName(gObjectInfoGetMethod(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) writeMethod(info, minfo)
#if i == 0:
# genDestroyFreeUnref()
if class != nil and not allSyms.contains(mangleName(gBaseInfoGetName(class))): if class != nil and not allSyms.contains(mangleName(gBaseInfoGetName(class))):
assert false assert false
classList.add(class) classList.add(class)
@ -1704,6 +1759,45 @@ proc writeObj(info: GIObjectInfo) =
output.writeLine(" g_object_remove_toggle_ref(self.impl, toggleNotify, addr(self))") output.writeLine(" g_object_remove_toggle_ref(self.impl, toggleNotify, addr(self))")
output.writeLine(" self.impl = nil") 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))")
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
let freeMeName = $g_object_info_get_unref_function(parent)
if freeMeName != "":
output.writeLine("\nwhen defined(gcDestructors):")
let n = mangleName(gBaseInfoGetName(info))
output.writeLine(" proc destroy_" & freeMeName & "(self: ptr " & n & "00) {.importc: \"" & freeMeName & "\", libprag.}\n")
output.writeLine(" proc `=destroy`*(self: var typeof(" & mangleName(gBaseInfoGetName(info)) & "()[])) =")
output.writeLine(" if not self.ignoreFinalizer and self.impl != nil:")
if n in ["ParamArray", "ParamFraction"]:
output.writeLine(" destroy_$#(cast[ptr $#00](self.impl))" % [freeMeName, n])
else:
output.writeLine(" destroy_$1(self.impl)" % [freeMeName])
output.writeLine(" self.impl = nil")
proc extractFromUnion(tag: GITypeTag; arg: GIArgumentObj): string = proc extractFromUnion(tag: GITypeTag; arg: GIArgumentObj): string =
result = result =
case tag: case tag:
@ -1738,6 +1832,8 @@ proc writeConst(info: GIConstantInfo) =
var str = extractFromUnion(tag, arg) var str = extractFromUnion(tag, arg)
if str == """"\"""": str = """"\\"""" if str == """"\"""": str = """"\\""""
var h = $gBaseInfoGetName(info) var h = $gBaseInfoGetName(info)
if h == "MODIFIER_MASK":
return
if h.replace("_", "").toLowerAscii == "keych": if h.replace("_", "").toLowerAscii == "keych":
h.add(str[^5]) h.add(str[^5])
if gdkKeys.contains(h.toLowerAscii): if gdkKeys.contains(h.toLowerAscii):
@ -1833,6 +1929,45 @@ proc getView*(builder: Builder; name: string): View =
const GDK3_EPI = """ 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) {. proc gdk_window_invalidate_nilrect(self: ptr Window00; rect: ptr Rectangle; invalidateChildren: gboolean) {.
importc: "gdk_window_invalidate_rect", libprag.} importc: "gdk_window_invalidate_rect", libprag.}
@ -1868,45 +2003,6 @@ proc getAxis*(self: SomeEvent; axisUse: AxisUse): cdouble =
if not toBool(gdk_event_get_axis(cast[ptr Event00](self.impl), axisUse, result)): if not toBool(gdk_event_get_axis(cast[ptr Event00](self.impl), axisUse, result)):
raise newException(Defect, "Event does not support getAxis().") raise newException(Defect, "Event does not support getAxis().")
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.")
""" """
const GIO_EPI = """ const GIO_EPI = """
@ -1916,13 +2012,17 @@ proc run*(self: GApplication): int =
""" """
const GTK3_EPI = """
proc mainQuit*(w: Window) = mainQuit()
"""
const GTK_EPI = """ const GTK_EPI = """
#proc loadFromData*(self: CssProvider; data: cstring): bool = #proc loadFromData*(self: CssProvider; data: cstring): bool =
# loadFromData(self, uint8Array(data), -1) # loadFromData(self, uint8Array(data), -1)
proc mainQuit*(w: Window) = mainQuit()
proc gtk_file_chooser_dialog_new*(title: cstring; parent: ptr Window00; action: FileChooserAction; proc gtk_file_chooser_dialog_new*(title: cstring; parent: ptr Window00; action: FileChooserAction;
firstButtonText: cstring = nil): ptr FileChooserDialog00 {.varargs, firstButtonText: cstring = nil): ptr FileChooserDialog00 {.varargs,
importc: "gtk_file_chooser_dialog_new", libprag.} importc: "gtk_file_chooser_dialog_new", libprag.}
@ -1993,8 +2093,7 @@ proc main(namespace: string; version: cstring = nil) =
#g_irepository_prepend_search_path("/opt/gtk/lib64/girepository-1.0") #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 = 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! # ISGTK3 = parmCount() == 0 # we have to launch the generator two times, as typelibs can not be unloaded!
let typelib = gi.gIrepositoryRequire(namespace, version, cast[ let typelib = gi.gIrepositoryRequire(namespace, version, cast[GIRepositoryLoadFlags](0), error)
GIRepositoryLoadFlags](0), error)
#let typelib = gIrepositoryRequirePrivate(nil, namespace, "/usr/lib/girepository-1.0", version, cast[GIRepositoryLoadFlags](0), error) #let typelib = gIrepositoryRequirePrivate(nil, namespace, "/usr/lib/girepository-1.0", version, cast[GIRepositoryLoadFlags](0), error)
if typelib.isNil: if typelib.isNil:
echo "Failed to load ", namespace echo "Failed to load ", namespace
@ -2011,8 +2110,7 @@ proc main(namespace: string; version: cstring = nil) =
if j == 0: if j == 0:
importedModules = "import " importedModules = "import "
output.writeLine("# ", dep[j]) output.writeLine("# ", dep[j])
importedModules.add(fixedModName(($dep[j]).split('-', importedModules.add(fixedModName(($dep[j]).split('-', 2)[0].toLowerAscii) & ", ")
2)[0].toLowerAscii) & ", ")
importedModules.removeSuffix(", ") importedModules.removeSuffix(", ")
strfreev(dep) strfreev(dep)
let idep: cstringArray = gi.gIrepositoryGetImmediateDependencies(namespace) let idep: cstringArray = gi.gIrepositoryGetImmediateDependencies(namespace)
@ -2028,8 +2126,8 @@ proc main(namespace: string; version: cstring = nil) =
output.writeLine("{.warning[UnusedImport]: off.}") # gmodule, xlib, cairo output.writeLine("{.warning[UnusedImport]: off.}") # gmodule, xlib, cairo
output.writeLine(importedModules) output.writeLine(importedModules)
var Lib = if libs.isNil: "" else: ($libs).split(',', 2)[0] var Lib = if libs.isNil: "" else: ($libs).split(',', 2)[0]
if namespace == "PangoCairo" and Lib.startsWith( if namespace == "PangoCairo" and Lib.startsWith("libpango-"):
"libpango-"): Lib = Lib.replace("libpango-", "libpangocairo-") # GI bug? Lib = Lib.replace("libpango-", "libpangocairo-") # GI bug?
output.writeLine("const Lib = \"$1\"" % Lib) output.writeLine("const Lib = \"$1\"" % Lib)
output.writeLine("{.pragma: libprag, cdecl, dynlib: Lib.}") output.writeLine("{.pragma: libprag, cdecl, dynlib: Lib.}")
if namespace == "GObject": # declare array types to make it compile -- procs using these will need special care! if namespace == "GObject": # declare array types to make it compile -- procs using these will need special care!
@ -2084,8 +2182,7 @@ proc main(namespace: string; version: cstring = nil) =
#gtype.h-#else /* for historic reasons, C++ links against gulong GTypes */ #gtype.h-#else /* for historic reasons, C++ links against gulong GTypes */
#gtype.h-typedef gulong GType; #gtype.h-typedef gulong GType;
#gtype.h-#endif #gtype.h-#endif
output.writeLine( output.writeLine("when GLIB_SIZEOF_SIZE_T != GLIB_SIZEOF_LONG or not defined(cpp):")
"when GLIB_SIZEOF_SIZE_T != GLIB_SIZEOF_LONG or not defined(cpp):")
output.writeLine(" type\n GType* = Gsize") output.writeLine(" type\n GType* = Gsize")
output.writeLine("else:") output.writeLine("else:")
output.writeLine(" type\n GType* = culong") output.writeLine(" type\n GType* = culong")
@ -2139,15 +2236,13 @@ proc uint8ArrayZT2seq*(p: pointer): seq[uint8] =
inc(i) inc(i)
""") """)
output.writeLine( output.writeLine("proc cogfree*(mem: pointer) {.importc: \"g_free\", libprag.}")
"proc cogfree*(mem: pointer) {.importc: \"g_free\", libprag.}") output.writeLine("proc g_strfreev*(strArray: cstringArray) {.importc: \"g_strfreev\", libprag.}")
output.writeLine(
"proc g_strfreev*(strArray: cstringArray) {.importc: \"g_strfreev\", libprag.}")
output.writeLine("proc toBool*(g: gboolean): bool = g.int != 0") output.writeLine("proc toBool*(g: gboolean): bool = g.int != 0")
output.writeLine( output.writeLine("proc safeStringToCString*(s: cstring): cstring = (if s.len == 0: nil else: s)")
"proc safeStringToCString*(s: cstring): cstring = (if s.len == 0: nil else: s)")
output.writeLine(PRO) output.writeLine(PRO)
elif namespace == "Gdk": elif namespace == "Gdk":
output.writeLine("type\n ContentProvider00Array* = pointer")
output.writeLine("type\n Atom00Array* = pointer") output.writeLine("type\n Atom00Array* = pointer")
output.writeLine("type\n KeymapKeyArray* = pointer") output.writeLine("type\n KeymapKeyArray* = pointer")
output.writeLine("type\n VisualTypeArray* = pointer") # enums! output.writeLine("type\n VisualTypeArray* = pointer") # enums!
@ -2169,6 +2264,7 @@ proc uint8ArrayZT2seq*(p: pointer): seq[uint8] =
output.writeLine("type\n StockItemArray* = pointer") output.writeLine("type\n StockItemArray* = pointer")
output.writeLine("type\n PageRangeArray* = pointer") output.writeLine("type\n PageRangeArray* = pointer")
output.writeLine("type\n PadActionEntry00Array* = pointer") output.writeLine("type\n PadActionEntry00Array* = pointer")
output.writeLine("type\n Widget00Array* = pointer")
output.writeLine("type\n Array* = pointer") output.writeLine("type\n Array* = pointer")
elif namespace == "Atk": elif namespace == "Atk":
output.writeLine("type\n StateTypeArray* = pointer") # enums! output.writeLine("type\n StateTypeArray* = pointer") # enums!
@ -2234,16 +2330,14 @@ proc uint8ArrayZT2seq*(p: pointer): seq[uint8] =
var n = gi.gIrepositoryGetNInfos(namespace) var n = gi.gIrepositoryGetNInfos(namespace)
var s: seq[GIBaseInfo] var s: seq[GIBaseInfo]
for i in 0.cint ..< n: for i in 0.cint ..< n:
if not droppedSyms.contains(mangleName(gBaseInfoGetName( if not droppedSyms.contains(mangleName(gBaseInfoGetName(gi.gIrepositoryGetInfo(namespace, i)))):
gi.gIrepositoryGetInfo(namespace, i)))):
s.add(gi.gIrepositoryGetInfo(namespace, i)) s.add(gi.gIrepositoryGetInfo(namespace, i))
for i in s: for i in s:
if gBaseInfoGetType(i) in {GIInfoType.OBJECT, GIInfoType.INTERFACE, GIInfoType.STRUCT, GIInfoType.UNION} or isEnumInfo(i) or if gBaseInfoGetType(i) in {GIInfoType.OBJECT, GIInfoType.INTERFACE, GIInfoType.STRUCT, GIInfoType.UNION} or isEnumInfo(i) or
isCallbackInfo(i): isCallbackInfo(i):
allSyms.incl(mangleName(gBaseInfoGetName(i))) allSyms.incl(mangleName(gBaseInfoGetName(i)))
for i in 0 .. s.high: for i in 0 .. s.high:
if namespace == "GLib" and gBaseInfoGetType(s[ if namespace == "GLib" and gBaseInfoGetType(s[i]) == GIInfoType.STRUCT and gBaseInfoGetName(s[i]) == "Error":
i]) == GIInfoType.STRUCT and gBaseInfoGetName(s[i]) == "Error":
let h = s[i] let h = s[i]
s.delete(i, i) s.delete(i, i)
s.insert([h]) s.insert([h])
@ -2255,16 +2349,13 @@ proc uint8ArrayZT2seq*(p: pointer): seq[uint8] =
var interf: seq[string] var interf: seq[string]
let name = $gBaseInfoGetName(info) let name = $gBaseInfoGetName(info)
for i in 0.cint ..< ninterfaces: for i in 0.cint ..< ninterfaces:
var ns = ($gBaseInfoGetNamespace(info.gObjectInfoGetInterface( var ns = ($gBaseInfoGetNamespace(info.gObjectInfoGetInterface(i))).toLowerAscii
i))).toLowerAscii
if ns != moduleNamespace: if ns != moduleNamespace:
var iname = $gBaseInfoGetName(info.gObjectInfoGetInterface(i)) var iname = $gBaseInfoGetName(info.gObjectInfoGetInterface(i))
var fname = iname; fname.unCap var fname = iname; fname.unCap
iname = fixedModName(ns) & "." & iname iname = fixedModName(ns) & "." & iname
let tname = fixedModName(moduleNamespace) & "." & let tname = fixedModName(moduleNamespace) & "." & $gBaseInfoGetName(info)
$gBaseInfoGetName(info) externInterfaces.add("proc " & fname & "*(x: " & tname & "): " & iname & " = cast[" & iname & "](x)")
externInterfaces.add("proc " & fname & "*(x: " & tname & "): " &
iname & " = cast[" & iname & "](x)")
interf.add($gBaseInfoGetName(info.gObjectInfoGetInterface(i))) interf.add($gBaseInfoGetName(info.gObjectInfoGetInterface(i)))
let builderinter = info.gObjectInfoGetInterface(i) let builderinter = info.gObjectInfoGetInterface(i)
if gBaseInfoGetName(builderinter) == "Buildable": if gBaseInfoGetName(builderinter) == "Buildable":
@ -2307,15 +2398,11 @@ proc uint8ArrayZT2seq*(p: pointer): seq[uint8] =
var more_runs = 50 var more_runs = 50
while s.len > 0 or more_runs > 0: while s.len > 0 or more_runs > 0:
if s.len == 0: dec(more_runs) if s.len == 0: dec(more_runs)
if namespace == "GObject" and not knownSyms.contains( if namespace == "GObject" and not knownSyms.contains("g_signal_connect_data"):
"g_signal_connect_data"): if knownSyms.contains("ClosureNotify") and knownSyms.contains("ConnectFlags"):
if knownSyms.contains("ClosureNotify") and knownSyms.contains(
"ConnectFlags"):
knownSyms.incl("g_signal_connect_data") knownSyms.incl("g_signal_connect_data")
output.writeLine( output.writeLine("proc g_signal_connect_data*(instance: pointer; detailedSignal: cstring; cHandler: GCallback;")
"proc g_signal_connect_data*(instance: pointer; detailedSignal: cstring; cHandler: GCallback;") output.writeLine(" data: pointer; destroyData: ClosureNotify; connectFlags: ConnectFlags): culong {.")
output.writeLine(
" data: pointer; destroyData: ClosureNotify; connectFlags: ConnectFlags): culong {.")
output.writeLine(" importc: \"g_signal_connect_data\", libprag.}") output.writeLine(" importc: \"g_signal_connect_data\", libprag.}")
while priList.len > 0: # move missing symbols to top, but only once! while priList.len > 0: # move missing symbols to top, but only once!
let h = priList.pop let h = priList.pop
@ -2370,6 +2457,9 @@ proc uint8ArrayZT2seq*(p: pointer): seq[uint8] =
methodBuffer = newStringStream() methodBuffer = newStringStream()
signalBuffer = newStringStream() signalBuffer = newStringStream()
let x = delayedMethods.len let x = delayedMethods.len
#var processedFunctionsBack = processedFunctions # var due to https://forum.nim-lang.org/t/6312
tempProcessedFunctions.setLen(0)
useTempProcessedFunctions = true
try: try:
var h = false var h = false
for k in t: for k in t:
@ -2384,8 +2474,7 @@ proc uint8ArrayZT2seq*(p: pointer): seq[uint8] =
for k in t: for k in t:
processInfo(k) processInfo(k)
for k in t: for k in t:
delayedSyms.keepItIf(mangleName(gBaseInfoGetName( delayedSyms.keepItIf(mangleName(gBaseInfoGetName(k)) != mangleName(gBaseInfoGetName(it)))
k)) != mangleName(gBaseInfoGetName(it)))
suppressType = false suppressType = false
output.write(signalBuffer.data) output.write(signalBuffer.data)
output.write(methodBuffer.data) output.write(methodBuffer.data)
@ -2396,6 +2485,10 @@ proc uint8ArrayZT2seq*(p: pointer): seq[uint8] =
output.setPosition(pos) output.setPosition(pos)
supmod3.cut(supmodpos3) supmod3.cut(supmodpos3)
supmod4.cut(supmodpos4) supmod4.cut(supmodpos4)
#processedFunctions = processedFunctionsBack #
for el in tempProcessedFunctions:
processedFunctions.excl(el)
useTempProcessedFunctions = false
assert delayedMethods.len >= x assert delayedMethods.len >= x
delayedMethods.setLen(x) delayedMethods.setLen(x)
suppressType = false suppressType = false
@ -2411,8 +2504,7 @@ proc uint8ArrayZT2seq*(p: pointer): seq[uint8] =
assert false assert false
processInfo(i) processInfo(i)
if externInterfaces.len > 0: if externInterfaces.len > 0:
output.writeLine( output.writeLine("\n# Extern interfaces: (we don't use converters, but explicit procs for now.)")
"\n# Extern interfaces: (we don't use converters, but explicit procs for now.)")
for i in externInterfaces: for i in externInterfaces:
output.writeLine("") output.writeLine("")
output.writeLine(i) output.writeLine(i)
@ -2424,10 +2516,14 @@ proc init* =
var argc: int32 = 0 var argc: int32 = 0
var argv: cstringArray = nil var argv: cstringArray = nil
gst_init(argc, argv) gst_init(argc, argv)
proc getType*(m: gst.Message): gst.MessageType =
m.impl.type
""") """)
if namespace == "Gtk": if namespace == "Gtk":
if ISGTK3: if ISGTK3:
output.write(GTK3_EPI)
output.write( output.write(
""" """
proc init* = proc init* =
@ -2506,7 +2602,7 @@ proc get$1*(builder: Builder; name: string): $1 =
if namespace == "Gdk": if namespace == "Gdk":
if ISGTK3: if ISGTK3:
output.write(GDK3_EPI) output.write(GDK3_EPI.replace("SomeEvent", "Event"))
output.write(GDK_EPI.replace("SomeEvent", "Event")) output.write(GDK_EPI.replace("SomeEvent", "Event"))
if namespace == "GtkSource": if namespace == "GtkSource":
output.write(GTK_SOURCE_EPI) output.write(GTK_SOURCE_EPI)
@ -2612,4 +2708,4 @@ proc launch() =
supmod4.close supmod4.close
launch() launch()
# 2615 lines # 2711 lines