Skip to content

Commit

Permalink
Merge pull request alexflint#35 from alexflint/cgo_interfaces
Browse files Browse the repository at this point in the history
Add interface for getting native window handle
  • Loading branch information
alexflint committed Nov 1, 2016
2 parents acd0058 + 67756e3 commit ffe0959
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 9 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ out/
# Vim
/*.swp
*.app

/build/
64 changes: 58 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func main() {
}

func onReady(app *gallium.App) {
app.NewWindow("http://example.com/", "Window title!")
app.OpenWindow("http://example.com/", gallium.FramedWindow)
}
```

Expand All @@ -62,7 +62,7 @@ an app bundle:
```shell
$ go build ./example
$ go install github.com/alexflint/gallium/cmd/gallium-bundle
$ gallium-bundle -o example.app example
$ gallium-bundle example
$ open example.app
```

Expand All @@ -84,7 +84,7 @@ func main() {
}

func onReady(app *gallium.App) {
app.NewWindow("http://example.com/", "Here is a window")
app.OpenWindow("http://example.com/", gallium.FramedWindow)
app.SetMenu([]gallium.Menu{
gallium.Menu{
Title: "demo",
Expand Down Expand Up @@ -116,7 +116,7 @@ func main() {
}

func onReady(app *gallium.App) {
app.NewWindow("http://example.com/", "Here is a window")
app.OpenWindow("http://example.com/", gallium.FramedWindow)
app.AddStatusItem(
20,
"statusbar",
Expand Down Expand Up @@ -169,6 +169,58 @@ func onReady(app *gallium.App) {
}
```

### Writing native code

You can write C or Objective-C code that interfaces directly with native
windowing APIs using golang's excellent C bridging technology, cgo. The
following example uses the macOS native API `[NSWindow setAlphaValue]` to
create a semi-transparent window.

```go
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](http://electron.atom.io/) is a well-known framework for writing desktop applications in node.js rather than Go. 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 in fact some of the C components for Gallium were ported from Electron.
Expand All @@ -184,13 +236,13 @@ desktop UI applications in Go.

### Common pitfalls

- When you run an app bundle with `open app.bundle`, OSX launch services
- 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")
```
- When you run an app bundle with `open app.bundle`, OSX launch services
- 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.
Expand Down
12 changes: 12 additions & 0 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,3 +255,15 @@ func (w *Window) CloseDevTools() {
func (w *Window) DevToolsAreOpen() bool {
return bool(C.GalliumWindowDevToolsAreOpen(w.c))
}

// NativeWindow gets a operating-system dependent handle for this window. Under macOS
// this is NSWindow*.
func (w *Window) NativeWindow() unsafe.Pointer {
return unsafe.Pointer(C.GalliumWindowNativeWindow(w.c))
}

// NativeWindow gets an operating-system dependent handle for the window controller.
// Under macOS this is *NSWindowController.
func (w *Window) NativeController() unsafe.Pointer {
return unsafe.Pointer(C.GalliumWindowNativeController(w.c))
}
4 changes: 2 additions & 2 deletions dist/Gallium.framework/Versions/A/Gallium
Git LFS file not shown
11 changes: 10 additions & 1 deletion dist/include/gallium/browser.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,19 @@ GALLIUM_EXPORT void GalliumWindowOpenDevTools(gallium_window_t* window);

// GalliumWindowCloseDevTools closes the developer tools for the given window
GALLIUM_EXPORT void GalliumWindowCloseDevTools(gallium_window_t* window);

// GalliumWindowDevToolsVisible returns true if the developer tools are currently visible for the given window
GALLIUM_EXPORT bool GalliumWindowDevToolsAreOpen(gallium_window_t* window);

// GalliumWindowNativeWindow gets a native handle for this window (NSWindow*).
GALLIUM_EXPORT void* GalliumWindowNativeWindow(gallium_window_t* window);

// GalliumWindowNativeWindow gets a native handle for the window controller (NSWindowController*).
GALLIUM_EXPORT void* GalliumWindowNativeController(gallium_window_t* window);

// GalliumWindowNativeWindow gets a native handle for the window content (content::WebContent*).
GALLIUM_EXPORT void* GalliumWindowNativeContent(gallium_window_t* window);

#ifdef __cplusplus
}
#endif
Expand Down
43 changes: 43 additions & 0 deletions examples/native/native.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
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.RedirectStdoutStderr(os.ExpandEnv("$HOME/Library/Logs/Gallium.log"))
gallium.Loop(os.Args, onReady)
}

0 comments on commit ffe0959

Please sign in to comment.