Hacker News new | past | comments | ask | show | jobs | submit login
Tk9.0: CGo-free, cross platform GUI toolkit for Go (go.dev)
228 points by nateb2022 9 days ago | hide | past | favorite | 82 comments





Back in the day, I used to really dislike anything TK related. It looked old and ugly.

Now it looks like a wonderful alternative to all the bloated, wasteful, Electron JS applications out there.


traditional desktop gui,yes. desktop gui needs some web feature? electronjs is still a better option

Use Tauri instead if possible.

tauri uses web related libraries on each OS which is different from a real browser,some website will not work

Includes beautiful modern themes, e.g. azure https://pkg.go.dev/modernc.org/tk9.0@v0.53.0/themes/azure

Edit: CORRECTION! This is a person that used to use the cznic nickname, maybe because they worked in CZNIC for a while, but now goes by "modernc"

Seems like they've been involved in transpiling C projects, like TCK, to Go.

Some context: https://news.ycombinator.com/item?id=33197603

==previous message before my edit==

Oh, seems like this is made by CZNIC, the org that admins .cz TLD.

They've also done the Omnia Turris routers, KNOT DNS server or BIRD routing daemon...


> Seems like they've been involved in transpiling C projects, like TCK, to Go.

Probably best known for their port of SQLite: https://pkg.go.dev/modernc.org/sqlite


Huh.

I once read drh note that no-one had ever bought any copies of TH3. I'm not sure what that does or doesn't say.

But I would hope this is using TH3 in the development pipeline!

If it's a direct port, the branch coverage should be constructively similar so as to be just as effective a test as for the C version.


Yeah this gentleman is Jan Mercl and is quite known in the Go community. I think his most known project is the sqlite driver in pure Go, as opposed to mattn's driver.

Modernc.org is kind of umbrella of his projects.


As someone who doesn’t know a lot about go: why is CGo-free a feature? In what situations is CGo (which is basically just calling C libs from go, right?) bad?

It makes cross-compiling a lot more difficult. Instead of being able to build on whatever OS/architecture you use and produce binaries for any other OS/architecture you want to target with a single command (one of Go's superpowers), you need a complex build pipeline.

I've been using zig's toolchain in CGo projects for a couple years now and cross compilation _just works_. Maybe there are libraries it doesn't handle well but so far all of my use cases have been covered perfectly.

I have personally hit some roadblock before that I cannot really remember anymore, so I just gave up and used debian docker image.

(Which needed to be old enough that it had old glibc, so someone with 10 year old OS doesn't complain. Linux.)

zig gets around that by using musl, right? or does it use old libc?


Example? Curious, can Zig can be used to simplify CGO dependency management in general, or only for Zig programs?


It could definitely work for that. You have to think of zig in this context as a build system which can download and compile C/C++ codebases.

Zig is a C compiler. Much like D, you can use it to cross compile any C code.

Note that modernc/cznic stuff is not really actual go but C trans-compiled to Go, the trans-compiler having specific quirks for every platform,.

So it's not technically possible to compile to all platforms that Go runs on, only the platforms that the trans-compiler supports. And the resulting Go code is not that readable.

https://gitlab.com/cznic/libtcl9.0/-/blob/master/libtcl9_0_l...

https://pkg.go.dev/modernc.org/ccgo/v3

But it still improves cross-compiling, and results in a libc independent static binary, which is nice. And the work done on the trans-compiling is great.


FFI is an additional headache. Instead of having a single hermetic build process that just works, with FFI you now have to deal with shared libraries which may or may not be present, and may or may not support all the architectures or operating systems you want to target. FFI is why so many Python projects blow up when you run pip install. Then it takes sometimes hours to untangle that horror show.

This is using purego which is still using FFI, it is dynamically linking the C libs so you still have the same shared library issues. You don’t have to setup a C compiler toolchain though which is nice.

Why don't they just compile to C to Go like modern c does for SQLite?


I mean why don't they do it for the source library too? There are very few operations in C that can't be done in Go (mostly inline assembly and some pointer manipulation) under a standard userland assumption.

It’s not a technical thing.

It’s not bad.

It’s a misguided community thing.

Cgo is the correct choice for many domains (ui, gamedev, systems stuff) where you can’t use a network boundary as your “interacts with other languages”.

The language is opinionated; it’s not good at playing with others. It’s good at other things (network services, etc)… but you can and it’s not bad.

…it’s just hard, and people don’t like hard things.


It can be slower than pure Go options in some scenarios.

Purego is ffi and is slower than cgo.

That library (like this) claim “no cgo” when they use ffi is just ridiculous.

This one is particularly egregious in even supporting cgo!

Pure go my ass. You’re invoking c functions. It’s not pure go.

The distinction is in the tool chain; cgo is a better, first party solution.

Purego is an unstable (it is, read the repo!) workaround for people who a) don’t like the word “cgo” or b) dont like having a c tool chain.

…but realistically you have to interop with c code in many domains.

Sure, a pure world is great, but that’s not always possible.

People who don’t like cgo and choose purego are doing it for, mostly, optics (cgo is bad! This isn’t cgo… it’s ffi… totally different) and appear to fail to appreciate the technical distinction more complicated than they imagine, and they are still using c.


Cgo in server projects makes using Alpine as a base a headache honestly.

If I can I always pick pure Go solutions just for this reason.


Being CGo-free is very desirable when you can't/don't want/don't bother to link C library deps for some reason. On example when you don't want to do that is cross-compiling for another architecture and not really being able to control what runtime libraries are installed on the target.

So, it simplifies build pipelines, at the cost of being a bit slower in the runtime.

This is also nice to read about the topic: https://dave.cheney.net/2016/01/18/cgo-is-not-go



By eliminating cgo, they cut the supported platform list in half.

FFI mess is the price Go pays for having its own bespoke green threads (goroutines).

CGo compilation can be insanely slow.

That motif toolkit with the detachable pulldowns and diamond shaped radios...

I know tk has moved on but I have not.


IIRC they were called tear-off menus in X / Motif days.

I had attended a company course on X Windows, Xlib, and Motif programming, back in the day.

Motif might have been clunky or whatever, but was also powerful. That course was my first introduction to event-driven GUI programming and I was quite junior then, and didn't quite grok all the programming concepts involved, but a colleague, who was more knowledgeable, created a rudimentary MS Paint-like application, in about 1 hour or less, using Motif and C.

(Okay, he worked in the same company as me, but in a different city, so might have had the hardware and software resources to practice on X and Motif before the course, which I did not have.)

Search for 16.3.7 at:

https://www.oreilly.com/library/view/volume-6a-motif/9780596...

or search for tear-off menu at:

https://www.oreilly.com/openbook/motif/vol6a/Vol6a_html/ch15...


detachable menus is an undervalued feature, being able to detach a menu or submenu and cycle through its element, is great to have when you need it

There's a bunch of innovative things that just didn't go through enough design cycles to get the flow right which have since been abandoned

Is there a screenshot/gif/video/demo that demonstrates what you mean? Like, so you mean any group of widgets can be turned into its own window?

The application menus (like File, Edit, etc) had a built-in way of detaching them when they were expanded so that you could keep them open and place them somewhere convenient on your screen. This was useful if you had to select different menu options frequently.

here you go

https://tkdocs.com/images/tearoff.png

this used to be on by default in IDLE-python, but it seems they disabled it in more recent versions

you clicked tat dotted line and the menu detached and you could place it anywhere you wanted


Oh wow! This is super-cool.

It's too ugly for "general-purpose" apps, but it looks to be perfect for internal management apps (control panels, tools). I'm definitely going to try it for my key-management server.


I do not see anything particularly ugly in provided screenshots. And many "modern" utterly unergonomic applications with lots of wasted whitespace, low contrast invisible text and "clickable" elements that look the same as the rest are pure abomination. But I guess it can be a generational difference.

There are rather pleasant exceptions of course.


I can't really tell why, but Tk interfaces always feel just a bit "off" somehow.

And I also don't like modern "Material Fuck You" UIs, FWIW.


The"too ugly"has been my reaction as well.

That said, I can't even elaborate as to why I feel that way.

I'm totally fine with Material design, Fluent design or Apple's HIG, kde or gnome default looks. But this is just... not for me.

I wonder if a ui/ux expert could put into words why so many others feel the same.


Tk! Some things just work. Never underestimate proven tech.

How does this avoid Cgo? In the case of Ltk (FFI-free, Common Lisp bindings for Tcl/Tk), I know that the library communicates strings to a Tcl interpreter. This means no FFI is involved, but it does mean the user must have Tcl -- specifically, wish -- installed. Is there a similar requirement for this library?

Unfortunately, GitLab is locked behind Cloudflare turnstile and I can't access the source code.


It’s using purego: https://github.com/ebitengine/purego

And linking against libtcl and libtk.


> Unfortunately, GitLab is locked behind Cloudflare turnstile and I can't access the source code.

Out of curiosity, is that true for $(git clone), too, or just the browser access?


can cloudflare even be called a cdn anymore?

I'm really impressed that it can render math from TeX input. Is this a common thing in GUI toolkits? My graphics experience is mostly limited to Java's Swing and OpenGL from my college days.

Apparently it's embedding actual TeX for this purpose: https://git.sr.ht/~sbinet/star-tex (TeX is written in a Pascal variant, and this kind of transpilation is by no means unusual.)

It's common to have HTML widgets in GUI toolkits, and some may even support MathML, but this here is a bit different.


This looks perfect for my command line go app. I wanted to add config wizard all along.

One question though: app is primarily distributed through docker. Can docker app open a window somehow on all platforms? How?


How I wish andlibs/ui (actually native widgets) wasn’t abandoned in a half-done state. Now to build any GUI in Go that doesn’t look abominable I have to use Wails, this is no exception.

Hm... the examples look nice, but there are several examples that render graphics and/or text on a canvas. How about demonstrating more complex controls, e. g. list views?

Oh it's another of those modernc projects, where it's just C, transcompiled to go?

Yes, it is.

https://gitlab.com/cznic/libtcl9.0/-/blob/master/libtcl9_0_l...

So the "actual source" is still C, but it is CGo-less. Which is neat? But I am not sure how it performs in bigger apps, what are its limitations, etc.


It is cgo-free, but it seems to require several libraries. I am concerned that some people may misunderstand that it can be run as a single static binary.

$ ldd libtcl9tk9.0.so linux-vdso.so.1 libXft.so.2 => /lib/x86_64-linux-gnu/libXft.so.2 libfontconfig.so.1 => /lib/x86_64-linux-gnu/libfontconfig.so.1 libX11.so.6 => /lib/x86_64-linux-gnu/libX11.so.6 libXss.so.1 => /lib/x86_64-linux-gnu/libXss.so.1 libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 libcups.so.2 => /lib/x86_64-linux-gnu/libcups.so.2 libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 libfreetype.so.6 => /lib/x86_64-linux-gnu/libfreetype.so.6 libXrender.so.1 => /lib/x86_64-linux-gnu/libXrender.so.1 libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 libxcb.so.1 => /lib/x86_64-linux-gnu/libxcb.so.1 libXext.so.6 => /lib/x86_64-linux-gnu/libXext.so.6 /lib64/ld-linux-x86-64.so.2 libgssapi_krb5.so.2 => /lib/x86_64-linux-gnu/libgssapi_krb5.so.2 libavahi-common.so.3 => /lib/x86_64-linux-gnu/libavahi-common.so.3 libavahi-client.so.3 => /lib/x86_64-linux-gnu/libavahi-client.so.3 libgnutls.so.30 => /lib/x86_64-linux-gnu/libgnutls.so.30 libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 libbz2.so.1.0 => /lib/x86_64-linux-gnu/libbz2.so.1.0 libpng16.so.16 => /lib/x86_64-linux-gnu/libpng16.so.16 libbrotlidec.so.1 => /lib/x86_64-linux-gnu/libbrotlidec.so.1 libXau.so.6 => /lib/x86_64-linux-gnu/libXau.so.6 libXdmcp.so.6 => /lib/x86_64-linux-gnu/libXdmcp.so.6 libkrb5.so.3 => /lib/x86_64-linux-gnu/libkrb5.so.3 libk5crypto.so.3 => /lib/x86_64-linux-gnu/libk5crypto.so.3 libcom_err.so.2 => /lib/x86_64-linux-gnu/libcom_err.so.2 libkrb5support.so.0 => /lib/x86_64-linux-gnu/libkrb5support.so.0 libdbus-1.so.3 => /lib/x86_64-linux-gnu/libdbus-1.so.3 libp11-kit.so.0 => /lib/x86_64-linux-gnu/libp11-kit.so.0 libidn2.so.0 => /lib/x86_64-linux-gnu/libidn2.so.0 libunistring.so.5 => /lib/x86_64-linux-gnu/libunistring.so.5 libtasn1.so.6 => /lib/x86_64-linux-gnu/libtasn1.so.6 libnettle.so.8 => /lib/x86_64-linux-gnu/libnettle.so.8 libhogweed.so.6 => /lib/x86_64-linux-gnu/libhogweed.so.6 libgmp.so.10 => /lib/x86_64-linux-gnu/libgmp.so.10 libbrotlicommon.so.1 => /lib/x86_64-linux-gnu/libbrotlicommon.so.1 libbsd.so.0 => /lib/x86_64-linux-gnu/libbsd.so.0 libkeyutils.so.1 => /lib/x86_64-linux-gnu/libkeyutils.so.1 libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 libsystemd.so.0 => /lib/x86_64-linux-gnu/libsystemd.so.0 libffi.so.8 => /lib/x86_64-linux-gnu/libffi.so.8 libmd.so.0 => /lib/x86_64-linux-gnu/libmd.so.0 libcap.so.2 => /lib/x86_64-linux-gnu/libcap.so.2 libgcrypt.so.20 => /lib/x86_64-linux-gnu/libgcrypt.so.20 liblz4.so.1 => /lib/x86_64-linux-gnu/liblz4.so.1 liblzma.so.5 => /lib/x86_64-linux-gnu/liblzma.so.5 libzstd.so.1 => /lib/x86_64-linux-gnu/libzstd.so.1 libgpg-error.so.0 => /lib/x86_64-linux-gnu/libgpg-error.so.0


how does this handle state management and event delegation? As in, when state is modified in one control , it instantly updates in the other controls.

The examples show how to draw controls, but that’s the easiest and least interesting part of GUI apps


He he, is this based on Tcl? It for sure seems at least inspired by Tcl/Tk.

These are Go bindings for Tk, a cross-platform widget toolkit initially developed as extension for Tcl. Nowadays a lot of languages have bindings for Tcl/Tk. Python for example has been including tkinter [0] for a long time.

[0]: https://docs.python.org/3/library/tkinter.html


Seems Tk is now the default cross platform UI for any language. It is doing for local apps what JavaScript has not - a usable toolset for majority of use cases without a ton of overhead and interference. I e only played with tcl/tk over the years - now will put in some hard yards to try in depth. Golang+tk for heavy lifting and server side and tcl/tk for scripts and as hoc things. After 50 years of casual/prof development this might be my personal version of nirvana. YMMV.

> Seems Tk is now the default cross platform UI for any language.

So let's hope someone writes a wasm binding.


yes, for python, from 1.5 or early 2.x versions onwards, iirc. I've used py a bit from 1.5 and much more from early 2.x, is how i know this.

yes, perl, python and ruby, for example.

Really? Would love to see a binding for Powershell. Just for cross-platform shell scripts to be able to disable a pop-up for input etc. Just makes them more accessible.

That would be WPF. It uses Tk under the covers.

I believe that has been removed in later versions as the old examples I find online don't work in Powershell

> InvalidOperation: Unable to find type System.Windows.Forms.MessageBoxButtons].


This still works today for me:

    Add-Type -AssemblyName PresentationFramework
    [XML]$form = @"
       <Window 
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            Title="MainWindow" Height="450" Width="800">
        <Grid>
            
        </Grid>
        </Window>
    "@

    $NR = (New-Object System.Xml.XmlNodeReader $form)
    $window = [Windows.Markup.XamlReader]::Load($NR)

    $window.ShowDialog()

Ah, my bad. It is inspired by Tk. Should still be usable across most things today.

Similarly to Python Tkinter, it actually embeds Tcl/Tk and provides a Go interface to it.

And latest Tcl/Tk is v9 I think. So I guess there should be something...

Tcl/Tk the hidden hero.

CGO free. TK. I’m sold. imgui user.

Figma killed the desktop app. I yearn for the good old days of standardized UI if I actually need to get shit done efficiently. Nowadays it's learning everything from either scratch; maybe if you're lucky, the designer put in some 'intuitive' (read 'fashionable') interactions.

You write like you were born after all the events related to the desktop application had run their curse.

We killed the desktop app, to free ourselves from the Wintel monopoly. We pushed the migration to the Web, because that was the unreachable niche for Microsoft and their monopolistic practices.

We succeeded, and as punishment, now we have to endure all these applications written in Node.js with Electron UIs. We won, but we have paid a high price for it.

In this context, Figma is nothing more than an afterthought. Something that appeared as a consequence, not the cause of anything.


Don't worry, mobile applications, which are basically another nightmare, are slowly eating the web for general purpose/public applications.

And now we have 2 oligopolies instead of 1 monopoly, but in practice it's basically the same thing.


True. Once upon a time, we believed in Google's “Don't be evil.”

The same thing but twice the work !

At least we avoided the Flash hegemony

>to free ourselves from the Wintel monopoly

Now we "enjoy" the Chrome monopoly.


And I may add that even Microsoft themselves killed desktop apps.

I mean, just try creating a GUI app even exclusively for Windows in 2024 : it was their strength in the past, it’s now the same pain as everywhere else.

Even Windows 11 uses multiple intricate UI frameworks from Microsoft, sometimes on the same screen without any UI coherence.


>You write like you were born after all the events related to the desktop application had run their curse.

>We killed the desktop app, to free ourselves from the Wintel monopoly.

Bombastic nonsensical crap!

There is no "we”, period. That is a fallacy that you, not "we", impose upon yourself, and try to generalize it to, or foist it upon, everyone.

"We" didn't kill anything. and "we" were not slaves in the first place, so "we" didn't need to make ourselves free.

Maybe you, and some known to you, were slaves, or still are. Don't generalize vacuously.

This is not the multiple Oscar-winning award-winning Ben-Hur movie or the Biblical story of the ancient Israelites as slaves in Egypt or something like that.

Anyone, who wanted to, or at least, any reasonably large group of people (1), could have moved off, from Windows, if they wanted to, badly enough. In the early years of Windows, DOS was still there, right? And had plenty of good software on it, just not GUI-based. and there were some Unix versions around, including maybe some cheaper ones. I rememember Coherent Unix and ESIX, for example. I actually work on the latter, briefly, in an early job. Microsoft's own Xenix existed around the same time too, plus or minus a year or three, maybe.

(1) Say a few hundred or a few thousand people. As an example, they could have collected donations, and hired 20 to 50 smart computer science students, grad or undergrad, and / or professors and / or operating system developers, to create a better OS without the monopoly and bad practices of MS. You bet your ass, at least some people would have queued up for that.

Set up some rules for correct behaviour, and kick out anybody who did not comply.

>We pushed the migration to the Web, because that was the unreachable niche for Microsoft and their monopolistic practices.

So, your only option is to run away from an enemy? And do you think that the enemy cannot follow you there? What about WSL and Azure and what not? Ha ha. Never underestimate your enemies.

See the Stockdale Paradox. The Jim Collins version is a good one.

https://news.ycombinator.com/item?id=42153495


The Tk GUI toolkit dates back to 1991.

This style of GUI predates Figma by decades.


Yeah, web dev sucks.



Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: