Hello, I was trying to create a small Gtk program for my personal use. It has a glib timeout function that reads data from a few spinbuttons, comboboxtext and an entry periodically and automatically refreshes a couple of labels. Here is the app itself:
import gintro/[gtk, glib, gobject, gio]
import strutils
proc updateIntervalResult(builder: Builder): bool =
result = true
let
startAM = builder.getComboBoxText("start_am_pm").getActiveText() == "AM"
startHour = builder.getSpinButton("start_hour").getValue() + (if startAM: 0 else: 12)
startMin = builder.getSpinButton("start_minute").getValue()
endAM = builder.getComboBoxText("end_am_pm").getActiveText() == "AM"
endHour = builder.getSpinButton("end_hour").getValue() + (if endAM: 0 else: 12)
endMin = builder.getSpinButton("end_minute").getValue()
let interval = (endHour * 60 + endMin - startHour * 60 - startMin) / 60
if interval < 0.0:
builder.getLabel("interval_label").setLabel("-")
builder.getLabel("currency_label").setLabel("-")
else:
let intervalFormat = interval.formatFloat(ffDecimal, 2)
builder.getLabel("interval_label").setLabel(intervalFormat)
if builder.getEntry("rate").getTextLength() > uint16(0):
try:
let rateStr = builder.getEntry("rate").getText()
let rate = rateStr.parseFloat()
builder.getLabel("currency_label").setLabel(cstring("$" & (interval * rate).formatFloat(ffDecimal, 2)))
except:
echo "parsing currency failed"
builder.getLabel("currency_label").setLabel("$0.00")
else:
builder.getLabel("currency_label").setLabel(" ")
proc appActivate(app: Application) =
let builder = newBuilderFromFile("resources/ui.glade")
let appWindow = builder.getApplicationWindow("aw")
appWindow.setApplication(app)
timeoutAdd(400, updateIntervalResult, builder)
appWindow.showAll()
when isMainModule:
let app = newApplication("com.gitlab.adnan338.Interval")
app.connect("activate", appActivate)
discard run(app)
Here is the glade file: https://pastebin.com/hAFqWm8b
However the app crashes after a few seconds by itself after entering some data saying:
Error: unhandled exception: /home/adnan338/.nimble/pkgs/gintro-0.8.3/gintro/gtk.nim(61531, 11) result.impl == gobj [AssertionError]
What could be causing this? Thanks in advance.
glib timeout function that reads data from a few spinbuttons
I think that is a bit critical. Reading from widgets with timer? We have examples for animations with timeout. But extracting data from widgets is most often done with signals and callback functions.
Do you have some knowledge about GTK and maybe example in other languages, preferable C that do it in this way? GTK is not really thread-safe, we have two examples how GTK can be used with threads.
Will have a closer look tomorrow.
It is true, in an idiomatic GTK program I would add callbacks to the widgets, however I would have to implement 7 different callbacks for the 7 different widgets that I am reading data from. I want to avoid this, callbacks internally rely on a polled timer anyways, so I made things simpler by periodically trying to read data and update the labels accordingly.
I could also have used a button to calculate and display my result but I personally like live updates so I went with it.
I believe in Gtk you access the widgets from Glib.Idle or Glib.Timeouts on multithreaded scenarios, but I am not doing any multithreading here, everything is happening inside the loop and I just injected a timeout callback into it. Why would you not imagine this working in this way? That's usually how I load/update progressbars.
Luckily I know some basic Gtk so I was able to (hastily) recreate this on Gtk-rs and it seems to be stable (https://pastebin.com/zdi0vfEc). The only thing I did different is that I used glib::timeout_add_local as it was primarily intended.
in an idiomatic GTK program I would add callbacks to the widgets, however I would have to implement 7 different callbacks for the 7 different widgets that I am reading data from.
Unfortunately that is true. This is the reason I suggested to you to try one of the immediate mode GUIs, for these your use case may be simpler.
Luckily I know some basic Gtk so I was able to (hastily) recreate this on Gtk-rs
It would be nice if you could post your Rust implementation to the GTK forum. There we have Mr. Bassi from Gnome and Mr. Droege from the Rust team as experts, so we may learn more about the reason why it may crash, or maybe not.
I had considered making a C version and ask Mr. Bassi for details, but I am a bit busy currently. Asking about Nim Gtk code at the GTK forum makes not too much sense currently unfortunately.
Generally I recommend compiling gintro code with --gc:arc as with that you get possible crashes immediately, while with default refc GC the garbage collector frees its objects with a delay.
Unfortunately I don't get a crash. At least not with latest Nim devel, and 64 bit Linux and gintro #head.
I compiled with default refc and with arc GC and played some minutes with it.
I was hoping that the reason for a crash may be the try/except or the fact that you put the last 3 statements in global scope, what we generally avoid in C and in Nim.
But as there is no crash it makes no real sense to ask Mr Bassi or Mr Droege about that program shape, both are very busy.