Top Related Projects
Tiny cross-platform webview library for C/C++. Uses WebKit (GTK/Cocoa) and Edge WebView2 (Windows).
Build cross platform GUI apps with GO and HTML/JS/CSS (powered by Electron)
Create beautiful applications using Go
A package to build progressive web apps with Go programming language and WebAssembly.
a cross platfrom Go library to place an icon and menu in the notification area
Cross platform GUI toolkit in Go inspired by Material Design
Quick Overview
Gallium is a Go library for building desktop applications using Go and HTML/JS/CSS. It provides a way to create cross-platform desktop apps with a native look and feel, while leveraging web technologies for the user interface.
Pros
- Allows developers to use familiar web technologies (HTML, CSS, JavaScript) for UI development
- Cross-platform support for Windows, macOS, and Linux
- Integrates Go's powerful backend capabilities with frontend web technologies
- Lightweight and easy to get started with
Cons
- Limited community support and resources compared to more established frameworks
- May have performance limitations compared to fully native applications
- Documentation could be more comprehensive
- Project appears to be less actively maintained in recent years
Code Examples
- Creating a basic window:
package main
import "github.com/alexflint/gallium"
func main() {
gallium.Loop(func(app *gallium.App) {
app.NewWindow("http://example.com/")
})
}
- Handling menu item clicks:
menuItem := gallium.MenuItem{
Title: "Click me",
OnClick: func() {
log.Println("Menu item clicked!")
},
}
- Executing JavaScript in the window:
window.Eval(`
document.body.innerHTML = "<h1>Hello from Go!</h1>";
`)
Getting Started
To use Gallium in your Go project:
-
Install Gallium:
go get github.com/alexflint/gallium
-
Import it in your Go file:
import "github.com/alexflint/gallium"
-
Create a basic application:
package main import "github.com/alexflint/gallium" func main() { gallium.Loop(func(app *gallium.App) { window := app.NewWindow("https://example.com") window.SetTitle("My Gallium App") }) }
-
Build and run your application:
go build ./your_app_name
Competitor Comparisons
Tiny cross-platform webview library for C/C++. Uses WebKit (GTK/Cocoa) and Edge WebView2 (Windows).
Pros of webview
- More actively maintained with frequent updates
- Supports multiple programming languages (Go, C/C++, Python, Rust)
- Smaller footprint and simpler API
Cons of webview
- Less feature-rich compared to Gallium
- Limited to basic web view functionality
- Lacks native macOS menu integration
Code Comparison
Gallium (Go):
app, _ := gallium.New()
window, _ := app.NewWindow("https://example.com")
app.Run()
webview (Go):
w := webview.New(true)
defer w.Destroy()
w.SetSize(800, 600, webview.HintNone)
w.Navigate("https://example.com")
w.Run()
Both libraries provide a straightforward way to create a web view window, but Gallium offers more macOS-specific features and a richer API for native app development. webview, on the other hand, focuses on simplicity and cross-platform compatibility, making it easier to use for basic web view applications across different operating systems and programming languages.
Build cross platform GUI apps with GO and HTML/JS/CSS (powered by Electron)
Pros of go-astilectron
- Cross-platform support for Windows, macOS, and Linux
- Active development and community support
- Integrates with Electron, providing access to a rich ecosystem of tools and libraries
Cons of go-astilectron
- Larger application size due to Electron dependency
- Potentially higher resource usage compared to native solutions
- Steeper learning curve for developers unfamiliar with Electron
Code Comparison
go-astilectron:
astilectron.New(astilectron.Options{
AppName: "MyApp",
AppIconDefaultPath: "resources/icon.png",
AppIconDarwinPath: "resources/icon.icns",
}).Run()
gallium:
gallium.Loop(os.Args, func(w *gallium.Window) {
w.OpenURL("http://example.com")
})
Summary
go-astilectron leverages Electron to provide cross-platform desktop applications using Go, offering a wide range of features and community support. However, it comes with increased application size and resource usage. gallium, on the other hand, focuses on creating native macOS applications with Go, resulting in smaller, more efficient applications but with limited platform support. The choice between the two depends on the specific requirements of your project, such as target platforms, performance needs, and development preferences.
Create beautiful applications using Go
Pros of Wails
- More active development and larger community support
- Cross-platform support for Windows, macOS, and Linux
- Built-in tooling for project creation and management
Cons of Wails
- Steeper learning curve due to more complex architecture
- Larger application size compared to Gallium
Code Comparison
Wails:
package main
import (
"github.com/wailsapp/wails"
)
func main() {
app := wails.CreateApp(&wails.AppConfig{
Width: 1024,
Height: 768,
Title: "My Wails App",
})
app.Run()
}
Gallium:
package main
import "github.com/alexflint/gallium"
func main() {
gallium.Loop(func(window gallium.Window) {
window.SetTitle("My Gallium App")
window.SetSize(1024, 768)
})
}
Both Wails and Gallium are frameworks for building desktop applications using Go and web technologies. Wails offers a more comprehensive solution with better cross-platform support and active development. However, it may have a steeper learning curve and result in larger application sizes. Gallium, while simpler to use, has less active development and limited platform support. The code examples demonstrate the basic setup for creating a window in each framework, highlighting their different approaches to application initialization and configuration.
A package to build progressive web apps with Go programming language and WebAssembly.
Pros of go-app
- Cross-platform support for web, desktop, and mobile applications
- Rich set of UI components and layouts out of the box
- Active development and community support
Cons of go-app
- Steeper learning curve for developers new to Go
- Limited native OS integration compared to Gallium
Code Comparison
go-app:
func main() {
app.Route("/", &hello{})
app.Run()
}
type hello struct {
app.Compo
}
func (h *hello) Render() app.UI {
return app.H1().Text("Hello World!")
}
Gallium:
func main() {
gallium.Loop(os.Args, func(app *gallium.Application, fs *gallium.Filesystem) {
window, _ := app.NewWindow("http://example.com")
window.SetTitle("Hello World")
window.Show()
})
}
Summary
go-app offers a more comprehensive framework for building cross-platform applications with a rich set of UI components. It provides better support for web applications and has a more active community. However, it may have a steeper learning curve for Go beginners.
Gallium, on the other hand, focuses on desktop applications with native OS integration. It's simpler to get started with for basic desktop apps but has limited cross-platform capabilities compared to go-app.
The choice between the two depends on the specific requirements of your project, target platforms, and development team's expertise.
a cross platfrom Go library to place an icon and menu in the notification area
Pros of systray
- More lightweight and focused specifically on system tray functionality
- Supports a wider range of operating systems, including Windows, macOS, and Linux
- Actively maintained with more recent updates and contributions
Cons of systray
- Limited to system tray functionality, lacking broader desktop application features
- Less comprehensive documentation and examples compared to Gallium
- May require additional libraries or frameworks for more complex GUI applications
Code Comparison
systray example:
systray.Run(onReady, onExit)
func onReady() {
systray.SetIcon(icon.Data)
systray.SetTitle("My App")
mQuit := systray.AddMenuItem("Quit", "Quit the app")
}
Gallium example:
app, _ := gallium.New()
window, _ := app.NewWindow("http://example.com")
menu := gallium.NewMenu("My Menu")
menu.AddItem("Quit", app.Quit)
app.SetMenu(menu)
app.Run()
Both libraries provide ways to create system tray applications, but Gallium offers a more comprehensive approach for desktop applications with built-in web view support. systray focuses solely on system tray functionality, making it more suitable for simpler use cases or as part of larger applications.
Cross platform GUI toolkit in Go inspired by Material Design
Pros of Fyne
- Cross-platform support for desktop and mobile
- Pure Go implementation with no CGo dependencies
- Larger community and more active development
Cons of Fyne
- Steeper learning curve for developers new to Go
- Less native look and feel compared to platform-specific UIs
Code Comparison
Gallium (JavaScript):
app.on('ready', function() {
var window = gallium.createWindow({
width: 800,
height: 600,
url: 'http://example.com'
})
})
Fyne (Go):
app := app.New()
w := app.NewWindow("Hello")
w.SetContent(widget.NewLabel("Hello Fyne!"))
w.ShowAndRun()
Summary
Fyne is a more comprehensive and actively maintained framework for building cross-platform GUI applications in Go. It offers broader platform support and a pure Go implementation. However, it may have a steeper learning curve and less native look compared to Gallium.
Gallium, on the other hand, focuses on creating desktop applications using web technologies, which may be more familiar to web developers. It provides a more native appearance but is limited to desktop platforms and has less active development.
The choice between the two depends on the developer's familiarity with Go, desired platform support, and preference for native look versus cross-platform consistency.
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Write desktop applications in Go, HTML, Javascript, and CSS.
Gallium is a Go library for managing windows, menus, dock icons, and desktop notifications. Each window contains a webview component, in which you code your UI in HTML. Under the hood, the webview is running Chromium.
Warning
This is an extremely early version of Gallium. Most APIs will probably change before the 1.0 release, and much of the functionality that is already implemented remains unstable.
Platforms
Only OSX is supported right now. I intend to add support for Windows and Linux soon.
Discussion
Join the #gallium
channel over at the Gophers slack. (You can request an invite to
the Gophers slack team here.)
Installation
Requires go >= 1.7
First install git large file storage, then install Gallium:
$ brew install git-lfs
$ git lfs install
$ go get github.com/alexflint/gallium # will not work without git lfs!
This will fetch a 92MB framework containing a binary distribution of the Chromium content module, so it may take a few moments. This is also why git large file storage must be installed (github has a limit on file size.)
Quickstart
package main
import (
"os"
"runtime"
"github.com/alexflint/gallium"
)
func main() {
runtime.LockOSThread() // must be the first statement in main - see below
gallium.Loop(os.Args, onReady) // must be called from main function
}
func onReady(app *gallium.App) {
app.OpenWindow("http://example.com/", gallium.FramedWindow)
}
To run the example as a full-fledged UI application, you need to build an app bundle:
$ go build ./example
$ go install github.com/alexflint/gallium/cmd/gallium-bundle
$ gallium-bundle example
$ open example.app
If you run the executable directly without building an app bundle then many UI elements, such as menus, will not work correctly.
$ go run example.go
Menus
func main() {
runtime.LockOSThread()
gallium.Loop(os.Args, onReady)
}
func onReady(app *gallium.App) {
app.OpenWindow("http://example.com/", gallium.FramedWindow)
app.SetMenu([]gallium.Menu{
gallium.Menu{
Title: "demo",
Entries: []gallium.MenuEntry{
gallium.MenuItem{
Title: "About",
OnClick: handleMenuAbout,
},
gallium.Separator,
gallium.MenuItem{
Title: "Quit",
Shortcut: "Cmd+q",
OnClick: handleMenuQuit,
},
},
},
})
}
func handleMenuAbout() {
log.Println("about clicked")
os.Exit(0)
}
func handleMenuQuit() {
log.Println("quit clicked")
os.Exit(0)
}
Status Bar
func main() {
runtime.LockOSThread()
gallium.Loop(os.Args, onReady)
}
func onReady(app *gallium.App) {
app.OpenWindow("http://example.com/", gallium.FramedWindow)
app.AddStatusItem(
20,
"statusbar",
true,
gallium.MenuItem{
Title: "Do something",
OnClick: handleDoSomething,
},
gallium.MenuItem{
Title: "Do something else",
OnClick: handleDoSomethingElse,
},
)
}
func handleDoSomething() {
log.Println("do something")
}
func handleDoSomethingElse() {
log.Println("do something else")
}
Desktop Notifications
Note that the OSX Notification Center determines whether or not to show any given desktop notification, so you may need to open the notification center and scroll to the bottom in order to see notifications during development.
func main() {
runtime.LockOSThread()
gallium.Loop(os.Args, onReady)
}
func onReady(app *gallium.App) {
img, err := gallium.ImageFromPNG(pngBuffer)
if err != nil {
...
}
app.Post(gallium.Notification{
Title: "Wow this is a notification",
Subtitle: "The subtitle",
Image: img,
})
}
Dock icons
To add a dock icon, create a directory named myapp.iconset
containing the following files:
icon_16x16.png # 16 x 16
icon_16x16@2x.png # 32 x 32
icon_32x32.png # 32 x 32
icon_32x32@2x.png # 64 x 64
icon_128x128.png # 128 x 128
icon_128x128@2x.png # 256 x 256
icon_256x256.png # 256 x 256
icon_256x256@2x.png # 512 x 512
icon_512x512.png # 512 x 512
icon_512x512@2x.png # 1024 x 1024
Then build you app with
gallium-bundle myapp --icon myapp.iconset
Alternatively, if you have a .icns
file:
gallium-bundle myapp --icon myapp.icns
Writing native code
You can write C or Objective-C code that interfaces directly with native
windowing APIs. The following example uses the macOS native API [NSWindow setAlphaValue]
to create a semi-transparent window.
package main
import (
"log"
"os"
"runtime"
"github.com/alexflint/gallium"
)
/*
#cgo CFLAGS: -x objective-c
#cgo CFLAGS: -framework Cocoa
#cgo LDFLAGS: -framework Cocoa
#include <Cocoa/Cocoa.h>
#include <dispatch/dispatch.h>
void SetAlpha(void* window, float alpha) {
// Cocoa requires that all UI operations happen on the main thread. Since
// gallium.Loop will have initiated the Cocoa event loop, we can can use
// dispatch_async to run code on the main thread.
dispatch_async(dispatch_get_main_queue(), ^{
NSWindow* w = (NSWindow*)window;
[w setAlphaValue:alpha];
});
}
*/
import "C"
func onReady(ui *gallium.App) {
window, err := ui.OpenWindow("http://example.com/", gallium.FramedWindow)
if err != nil {
log.Fatal(err)
}
C.SetAlpha(window.NativeWindow(), 0.5)
}
func main() {
runtime.LockOSThread()
gallium.Loop(os.Args, onReady)
}
Relationship to other projects
Electron is a well-known framework for writing desktop applications in node.js. Electron and Gallium are similar in that the core UI is developed in HTML and javascript, but with Gallium the "outer layer" of logic is written in Go. Both Electron and Gallium use Chromium under the hood, and some of the C components for Gallium were ported from Electron.
The Chromium Embedded Framework is a C framework for embedding Chromium into other applications. I investigated CEF as a basis for Gallium but decided to use libchromiumcontent instead.
cef2go is a Go wrapper for Chromium based on CEF, but so far it still requires some manual steps to use as a library.
Rationale
The goal of Gallium is to make it possible to write cross-platform desktop UI applications in Go.
Troubleshooting
"file was built for unsupported file format"
If you see the following error:
ld: warning: ignoring file go/src/github.com/alexflint/gallium/dist/Gallium.framework/Gallium, file was built for unsupported file format ( 0x76 0x65 0x72 0x73 0x69 0x6F 0x6E 0x20 0x68 0x74 0x74 0x70 0x73 0x3A 0x2F 0x2F ) which is not the architecture being linked (x86_64): go/src/github.com/alexflint/gallium/dist/Gallium.framework/Gallium
then you probably have an issue with git lfs
. You can confirm that this is
the problem by checking the size of the file in the error message: it should
be over 1 MB, but if you see a much smaller file then this is your problem.
To fix this, try re-installing git lfs
as described in the installation
section above, then delete and re-install gallium.
No console output
When you run an app bundle with open Foo.app
, OSX launch services discards
standard output and standard error. If you need to see this output for
debugging purposes, use a redirect:
gallium.RedirectStdoutStderr("output.log")
App does not start
When you run an app bundle with open Foo.app
, OSX launch services will only
start your app if there is not already another instance of the same
application running, so if your app refuses to start then try checking the
activity monitor for an already running instance.
Menus not visible
If you run the binary directly without building an app bundle then your menus will not show up, and the window will initially appear behind other applications.
UI thread issues and runtime.LockOSThread
It is very important that the first statement in your main function
be runtime.LockOSThread()
. The reason is that gallium calls
out to various C functions in order to create and manage OSX UI elements,
and many of these are required to be called from the first thread
created by the process. But the Go runtime creates many threads and any
one piece of Go code could end up running on any thread. The solution
is runtime.LockOSThread
, which tells the Go scheduler to lock the
current goroutine so that it will only ever run on the current thread.
Since the main function always starts off on the main thread, this wil
guarantee that the later call to gallium.Loop
will also be on the main
thread. At this point gallium takes ownership of this thread for its main
event loop and calls the OnReady
callback in a separate goroutine.
From this point forward it is safe to call gallium functions from any
goroutine.
Shared libraries and linking issues
Gallium is based on Chromium, which it accesses via Gallium.framework
.
That framework in turn contains libchromiumcontent.dylib
, which is a
shared library containing the chromium content module and is distributed
in binary form by the same folks responsible for the excellent Electron
framework. When you build your Go executable, the directives in
Gallium.framework
instruct the linker to set up the executable to look for
Gallium.framework
in two places at runtime:
<dir containing executable>/../Frameworks/Gallium.framework
: this will resolve correctly if you choose to build and run your app as a bundle (and also means you can distribute the app bundle as a self-contained unit).$GOPATH/src/github.com/alexflint/dist/Gallium.framework
: this will resolve if you choose to run your executable directly.
Top Related Projects
Tiny cross-platform webview library for C/C++. Uses WebKit (GTK/Cocoa) and Edge WebView2 (Windows).
Build cross platform GUI apps with GO and HTML/JS/CSS (powered by Electron)
Create beautiful applications using Go
A package to build progressive web apps with Go programming language and WebAssembly.
a cross platfrom Go library to place an icon and menu in the notification area
Cross platform GUI toolkit in Go inspired by Material Design
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot