Skip to content

GTK-sugar is a client package of GTK-server for Go.

License

Notifications You must be signed in to change notification settings

jopbrown/gtk-sugar

Repository files navigation

GTK-sugar

Documentation

GTK-sugar is a client package of GTK-server for Go.

The package aims to develop cross-platform GUI app without cgo binding.

Features:

  • No cgo
  • Cross-platform
  • Supports GTK 1.x/2.x/3.x and so on...
  • Provide both interpreted and embedded GTK API
  • Runtime depend on GTK-server

Status

Interpreted API is stable enough to run simple applications.

Embedded API is work in process, breaking change will be made.

Prerequisites

Examples

Interpreted API

package main

import (
	"log"

	sugar "github.com/jopbrown/gtk-sugar"
)

func main() {
	log.Println("start gtk-server...")
	clt := sugar.NewClient(sugar.ConnStdio(), sugar.WithDebug(true))
	err := clt.Start()
	if err != nil {
		panic(err)
	}
	defer clt.Stop()

	gui := sugar.NewGuifyer(clt.Conn())

	gui.Guify("gtk_init", nil, nil)
	win := gui.Guify("gtk_window_new", 0)
	gui.Guify("gtk_window_set_title", win, "Interpreted API demo")
	gui.Guify("gtk_window_set_default_size", win, 400, 200)
	gui.Guify("gtk_window_set_position", win, 1)
	table := gui.Guify("gtk_table_new", 10, 10, true)
	gui.Guify("gtk_container_add", win, table)
	helloLabel := gui.Guify("gtk_label_new", "Hello world")
	gui.Guify("gtk_table_attach_defaults", table, helloLabel, 2, 8, 2, 6)
	showBtn := gui.Guify("gtk_button_new_with_label", "Show dialog")
	gui.Guify("gtk_table_attach_defaults", table, showBtn, 1, 4, 6, 9)
	exitBtn := gui.Guify("gtk_button_new_with_label", "Exit")
	gui.Guify("gtk_table_attach_defaults", table, exitBtn, 6, 9, 6, 9)
	gui.Guify("gtk_widget_show_all", win)
	dialog := gui.Guify("gtk_message_dialog_new", win, "GTK_DIALOG_MODAL", "GTK_MESSAGE_INFO", "GTK_BUTTONS_OK", "Hello world", "''")

	log.Println("start main loop...")
	var event sugar.Response
	for event != win && event != exitBtn {
		event = gui.Guify("gtk_server_callback", "WAIT")
		switch event {
		case dialog:
			gui.Guify("gtk_widget_hide", dialog)
		case showBtn:
			gui.Guify("gtk_dialog_run", dialog)
		}
	}

	log.Println("exit gtk-server...")
	gui.Guify("gtk_server_exit")
}

Embedded GTK API

package main

import (
	"time"

	sugar "github.com/jopbrown/gtk-sugar"

	"github.com/jopbrown/gtk-sugar/lib/gtk"
)

func main() {
	clt := sugar.NewClient(sugar.ConnStdio(), sugar.WithCfgPath(`/cfgs/gtk-server.cfg`))
	err := clt.Start()
	if err != nil {
		panic(err)
	}
	defer clt.Stop()

	sugar.GiveCandy(sugar.NewCandy(clt.Conn()))
	gtk.Init()

	win := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
	win.SetTitle("Embedded GTK API demo")
	win.SetDefaultSize(400, 200)
	win.SetPosition(gtk.WIN_POS_CENTER)
	win.ConnectDefault(gtk.MainQuit)

	table := gtk.TableNew(10, 10, true)
	win.Add(table)

	helloLabel := gtk.LabelNew("Hello world")
	table.AttachDefaults(helloLabel, 2, 8, 2, 6)

	dialog := gtk.MessageDialogNew(win, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, "Hello %s", "world")
	dialog.ConnectDefault(dialog.Hide)

	showBtn := gtk.ButtonNewWithLabel("Show dialog")
	showBtn.ConnectDefault(func() {
		go func() {
			time.Sleep(time.Second)
			// the goroutine is not run in the main loop.
			// so it's not safe to do any GUI operation.
			// need to invoke to main loop.
			gtk.Invoke(func() { dialog.Run() })
		}()
	})
	table.AttachDefaults(showBtn, 1, 4, 6, 9)

	exitBtn := gtk.ButtonNewWithLabel("Exit")
	exitBtn.ConnectDefault(gtk.MainQuit)
	table.AttachDefaults(exitBtn, 6, 9, 6, 9)

	win.ShowAll()

	gtk.Main()

}

TODO

  • Core

    • 🏃 Client - launch and communication to GTK-server
      • stdio(2-way pipes)
      • fifo(named pipe)
      • ipc(message queue)
      • tcp/udp
      • socket
    • Guifyer - interpreted API
    • Sugar - Guifyer with GTK-server internal functions
    • Candy - Sugar with signal handling and main loop control
  • Libarys

    • 🏃 GTK family
      • gtk
      • 🏃 glib
      • 🏃 gdk
      • cairo
      • pango
    • libc
    • Xforms
    • Motif
    • HUG
  • Other

    • tool to generate gtk-server.cfg from code
    • more comments
    • more examples
    • unit tests

Why?

I’ve been looking for the librarys for native GUI app in Go. There are already many librarys, like gotk3, go-gtk, that binding GTK with Go. However, all of them link to libgtk via cgo which is heavy dependency in compile-time. In my usecase, it's hard to build all targets platform because of cgo.

So, I start to look for pure Go librarys for GUI programing. shiny is one of librarys do not need cgo, but it already not maintained and not support X-Server with remote display.

And then duit emerged, which is pure Go, cross-platform, but runtime depend on devdraw, a standslone tool talking to X window via stdin/stdout. It is nice, but in early development and not friendly to windows. Nevertheless, duit show a way to separate compile-time dependency and move it to runtime.

Finally, I found GTK-server, a standalone tool talking to libgtk via stdin/stdout. This is the beginning of everything.

What's in a name?

Take from pronouncing sound like gtk-server and meaning of syntactic sugar.

Contributing

PRs welcome.

Licence

MIT

Releases

No releases published

Packages

No packages published

Languages