{"id":32360053,"url":"https://github.com/jinzhongmin/gg","last_synced_at":"2026-05-17T15:10:07.803Z","repository":{"id":317666025,"uuid":"1068328474","full_name":"jinzhongmin/gg","owner":"jinzhongmin","description":"A Go framework that leverages libffi to provide GTK4 and ImGui bindings, enabling native GUI application development with modern graphics interfaces.","archived":false,"fork":false,"pushed_at":"2025-11-03T10:43:18.000Z","size":477,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-03T12:19:07.968Z","etag":null,"topics":["gtk4","imgui","libffi"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jinzhongmin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-02T08:06:49.000Z","updated_at":"2025-11-03T10:43:23.000Z","dependencies_parsed_at":"2025-10-24T12:26:20.320Z","dependency_job_id":"27da516c-a45b-431a-a7f8-0f66e4279695","html_url":"https://github.com/jinzhongmin/gg","commit_stats":null,"previous_names":["jinzhongmin/gg"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jinzhongmin/gg","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jinzhongmin%2Fgg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jinzhongmin%2Fgg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jinzhongmin%2Fgg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jinzhongmin%2Fgg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jinzhongmin","download_url":"https://codeload.github.com/jinzhongmin/gg/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jinzhongmin%2Fgg/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33143276,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-17T09:28:26.183Z","status":"ssl_error","status_checked_at":"2026-05-17T09:27:52.702Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gtk4","imgui","libffi"],"created_at":"2025-10-24T14:28:09.687Z","updated_at":"2026-05-17T15:10:07.791Z","avatar_url":"https://github.com/jinzhongmin.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GG - GTK4 GUI Framework\n\nA  GTK4 GUI framework for Go that leverages libffi and minimal CGO to achieve significantly faster compilation times compared to traditional Go GTK bindings.\n\n## Environment Setup\n\n### Windows with MSYS2\n\nAdd the MSYS2 UCRT bin directory to your system PATH to ensure all required DLLs and executables are accessible, and ensure you have the following dependencies installed via MSYS2 pacman:\n\n``` bash\npacman -S mingw-w64-ucrt-x86_64-toolchain mingw-w64-ucrt-x86_64-gtk4 mingw-w64-ucrt-x86_64-mimalloc\n```\n\n## Example\n\n### Hello world\n\n``` go\npackage main\n\nimport (\n    \"unsafe\"\n\n    \"github.com/jinzhongmin/gg/glib/gio\"\n    \"github.com/jinzhongmin/gg/gtk/gtk/v4\"\n)\n\nfunc main() {\n    app := gtk.NewApplication(\"com.github.jinzhongmin.helloworld\", gio.GApplicationFlagsDefaultFlags)\n    app.ConnectActivate(func(a *gio.GApplication) {\n        app := (*gtk.Application)(unsafe.Pointer(a))\n\n        window := gtk.NewApplicationWindow(app)\n        button := gtk.NewButtonWithLabel(\"hello world\")\n        button.ConnectClicked(func(b *gtk.Button) {\n            window.Close()\n        })\n\n        window.SetChild(button)\n        window.Present()\n    })\n    app.Run(nil)\n}\n\n```\n\n### Build\n\n``` bash\ngo build -tags ccrelease  # Using ccrelease tag to minimize reflect usage for potentially better performance\n```\n\n## Basic Usage\n\n``` go\ncc.Open(\"libgtk-4.dll\") // Manually load the GTK dynamic library if you encounter failures when calling GTK functions\n```\n\nIf you find that the existing APIs don't match your local GTK APIs, you can manually implement the required APIs:\n\n```go\n\n// *gtk.Label is equivalent to the corresponding C pointer - Go pointers are unwrapped raw pointers\n\n// cc.DlFunc[Go function prototype, return type of Go function]{Name: symbol}\n// Use cc.Void if the return type is void\nvar gtk_label_new = cc.DlFunc[func(str cc.String) *gtk.Label, *gtk.Label]{Name: \"gtk_label_new\"}\n\nfunc newLabel(str string) *gtk.Label {\n    cstr := cc.NewString(str) // string can be replaced with cc.String\n    defer cstr.Free()\n    return gtk_label_new.Fn()(cstr)\n}\n```\n\nHow to Bind Go Variable Lifetime with Corresponding C-side Variable Lifetime\n\n``` go\npackage main\n\nimport (\n    \"fmt\"\n    \"unsafe\"\n\n    \"github.com/jinzhongmin/gg/glib/gio\"\n    \"github.com/jinzhongmin/gg/gtk/gtk/v4\"\n)\n\ntype MyButton struct {\n    *gtk.Button\n    cur int\n}\n\nfunc newMyButton() *MyButton {\n    btn := new(MyButton)\n    btn.Button = gtk.NewButton()\n    btn.cur = 0\n    btn.SetLabel(fmt.Sprintf(\"%d\", btn.cur))\n\n    btn.Button.Pin(btn) // Bind btn's lifetime to btn.Button - it will exist as long as btn.Button exists\n    return btn\n}\n\nfunc (btn *MyButton) Inc() {\n    btn.cur += 1\n    btn.SetLabel(fmt.Sprintf(\"%d\", btn.cur))\n}\n\nfunc main() {\n    app := gtk.NewApplication(\"com.github.jinzhongmin.helloworld\", gio.GApplicationFlagsDefaultFlags)\n    app.ConnectActivate(func(a *gio.GApplication) {\n        app := (*gtk.Application)(unsafe.Pointer(a))\n\n        window := gtk.NewApplicationWindow(app)\n\n        button := newMyButton() // button lifetime begins\n        button.ConnectClicked(func(b *gtk.Button) {\n            obj, ok := b.GetPinned() // Use this to retrieve the Go variable pinned by gtk.Button\n            if !ok {\n                return\n            }\n            btn := obj.(*MyButton)\n            btn.Inc()\n        })\n        // Although button's lifetime would normally end here, the Pin() call in newMyButton() \n        // ensures the variable persists until gtk.Button is destroyed\n\n        window.SetChild(button)\n        window.Present()\n    })\n    app.Run(nil)\n}\n```\n\nHow to Use ImGui in GTK Applications\n\nFirst, compile [libdcimgui](https://github.com/jinzhongmin/libdcimgui) to obtain the dynamic library file, then place it in either your application directory or system PATH.\n\n```go\npackage main\n\nimport (\n    \"math\"\n    \"unsafe\"\n\n    \"github.com/jinzhongmin/gg/cc\"\n    \"github.com/jinzhongmin/gg/dcimgui\"\n    ig \"github.com/jinzhongmin/gg/dcimgui\"\n    plt \"github.com/jinzhongmin/gg/dcimgui/dcimplot\"\n    \"github.com/jinzhongmin/gg/glib/gio\"\n    \"github.com/jinzhongmin/gg/gtk/gtk/v4\"\n    \"github.com/jinzhongmin/gg/gtk/gtk/v4/imgtk\"\n)\n\ntype uptr = unsafe.Pointer\n\n// Convert Go string to ImGui required type\n// Example: sr(\"hello\\x00\") - requires \\x00 termination\n// This approach avoids frequent CGO string conversion memory allocations\nfunc sr(str string) cc.String { return *(*cc.String)(uptr(\u0026str)) }\n\nfunc build[T any](obj T, builders ...func(T)) T {\n    for _, fn := range builders {\n        fn(obj)\n    }\n    return obj\n}\n\nfunc main() {\n\n    app := gtk.NewApplication(\"com.github.jinzhongmin.imgtk\", 0)\n    app.ConnectActivate(func(a *gio.GApplication) {\n        build(gtk.NewWindow(), func(win *gtk.Window) { // Window self setup\n\n            win.SetApplication(app)\n            win.SetTitle(\"mcv\")\n            win.SetDefaultSize(900, 600)\n\n        }, func(win *gtk.Window) { // Window layout\n\n            var font *ig.ImFont\n            var implotCtx *plt.ImPlotContext\n\n            var sin cc.Func // Corresponds to C callback function\n            var cos uptr    // uptr and cc.Func are essentially equivalent\n\n            // C prototype: ImPlotPoint (*ImPlotGetter)(int idx, void* user_data);\n            // The following function binds sin to a Go function matching the C prototype\n            // This binding uses reflect in generated code, which may have slightly lower performance\n            sin.Bind(func(idx int32, _ uptr) (pt plt.ImPlotPoint) {\n                x := float64(math.Pi) / 100 * float64(idx)\n                y := math.Sin(x)\n\n                pt.X = x\n                pt.Y = y\n                return\n            })\n\n            // C prototype: ImPlotPoint (*ImPlotGetter)(int idx, void* user_data);\n            // The following function binds cos to a Go function matching the C prototype\n            // This binding does not use reflect in generated code\n            cos = cc.CbkRaw[func(idx int32, _ uptr) plt.ImPlotPoint](func(out, ins uptr) {\n                // Input parameters need manual conversion:\n                // out: *ImPlotPoint\n                // ins: []unsafe.Pointer{*int32, *unsafe.Pointer}\n\n                pt := (*plt.ImPlotPoint)(out)\n\n                inPtrs := unsafe.Slice((*uptr)(ins), 2)\n                idx := *(*int32)(inPtrs[0])\n\n                x := float64(math.Pi) / 100 * float64(idx)\n                y := math.Cos(x)\n\n                pt.X = x\n                pt.Y = y\n            })\n\n            vbox := build(gtk.NewBox(gtk.OrientationVertical, 0), func(vbox *gtk.Box) { // vbox configuration\n\n                vbox.SetHExpand(true)\n                vbox.SetVExpand(true)\n\n            }, func(vbox *gtk.Box) { // Child 1: ImArea\n\n                var customColor plt.ImPlotColormap\n\n                // For C-side char** parameter types, use cc.Strings with pre-allocation\n                labels := cc.NewStrings([]string{\n                    \"PASS\", \"NG\",\n                })\n\n                // Use imgtk.NewImArea to create an ImGui control in GTK\n                ia := build(imgtk.NewImArea(func(ia *imgtk.ImArea) {\n                    // ImGui rendering process below\n\n                    if customColor == 0 {\n                        customColor = plt.AddColormapImVec4(sr(\"pn\\x00\"), []ig.ImVec4{\n                            {93.0 / 255.0, 197.0 / 255.0, 108.0 / 255.0, 1},\n                            {1, 0, 0, 1},\n                        }, true)\n                    }\n\n                    dcimgui.StyleColorsLight(nil)\n                    plt.SetCurrentContext(implotCtx)\n\n                    if ig.Begin(sr(\"PieChart example\\x00\"), nil, 0) {\n\n                        if plt.BeginPlot(sr(\"Production Line PASS Statistics\\x00\"), ig.ImVec2{-1, -1}, 0) {\n\n                            plt.SetupAxis(plt.ImAxis_X1, 0,\n                                plt.ImPlotAxisFlags_NoLabel|plt.ImPlotAxisFlags_NoTickMarks|plt.ImPlotAxisFlags_NoTickLabels)\n                            plt.SetupAxesLimits(-110, 110, -110, 110, plt.ImPlotCond_Always)\n                            plt.SetupAxisFormat(plt.ImAxis_X1, sr(\"\\x00\"))\n                            plt.SetupAxisFormat(plt.ImAxis_Y1, sr(\"\\x00\"))\n                            plt.SetupLegend(plt.ImPlotLocation_SouthEast,\n                                plt.ImPlotLegendFlags_Outside|plt.ImPlotLegendFlags_Horizontal)\n\n                            plt.PushColormap(customColor)\n                            ig.PushFontSize(nil, 18)\n                            plt.PlotPieChart(labels, ig.ImGuiDataType_Double, []float64{0.8 * 100, 0.1 * 100}, 0, 0, 100, sr(\"%.1f%%\\x00\"), 90, 0)\n                            ig.PopFont()\n                            plt.PopColormap(1)\n\n                            plt.EndPlot()\n                        }\n\n                    }\n                    ig.End()\n\n                    if ig.Begin(sr(\"callback\\x00\"), nil, 0) {\n                        if plt.BeginPlot(sr(\"callback\\x00\"), ig.ImVec2{-1, -1}, 0) {\n                            plt.PlotLineG(sr(\"sin\\x00\"), sin, 200, 0, nil)\n                            plt.PlotLineG(sr(\"cos\\x00\"), cc.Func(cos), 200, 0, nil)\n                            plt.EndPlot()\n                        }\n                    }\n                    ig.End()\n\n                }), func(ia *imgtk.ImArea) {\n                    ia.ConnectImInit(func(igc *ig.ImGuiContext, igi *ig.ImGuiIO) {\n                        // Load fonts during ImGui initialization\n                        font = igi.Fonts.AddFontFromFileTTF(sr(\"./DingTalk_JinBuTi.ttf\\x00\"), 16.5, nil, nil)\n                        \n                        // ImPlot context needs to be created manually\n                        implotCtx = plt.CreateContext()\n                    })\n                    ia.ConnectImDestroy(func(igc *ig.ImGuiContext, igi *ig.ImGuiIO) {\n                        // Cleanup during destruction\n                        if implotCtx != nil {\n                            implotCtx.Destroy()\n                        }\n                        if font != nil {\n                            igi.Fonts.RemoveFont(font)\n                        }\n\n                    })\n\n                })\n                ia.SetHExpand(true)\n                ia.SetVExpand(true)\n                vbox.Append(ia)\n            })\n            vbox.SetHExpand(true)\n            vbox.SetVExpand(true)\n            win.SetChild(vbox)\n\n        }).Present()\n\n    })\n    app.Run(nil)\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjinzhongmin%2Fgg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjinzhongmin%2Fgg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjinzhongmin%2Fgg/lists"}