forked from alexflint/gallium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.go
109 lines (91 loc) · 2.53 KB
/
app.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package gallium
/*
#cgo CFLAGS: -mmacosx-version-min=10.8
#cgo CFLAGS: -DGALLIUM_DIR=${SRCDIR}
#cgo CFLAGS: -Idist/include
#cgo LDFLAGS: -F${SRCDIR}/dist
#cgo LDFLAGS: -framework Gallium
#cgo LDFLAGS: -Wl,-rpath,@executable_path/../Frameworks
#cgo LDFLAGS: -Wl,-rpath,${SRCDIR}/dist
#cgo LDFLAGS: -mmacosx-version-min=10.8
#include <stdlib.h>
#include "gallium/gallium.h"
#include "gallium/menu.h"
// It does not seem that we can import "_cgo_export.h" from here
extern void cgo_onReady(int);
// This is a wrapper around GalliumLoop that adds the function pointer
// argument, since this does not seem to be possible from Go directly.
static inline void helper_GalliumLoop(int app_id, const char* arg0, struct gallium_error** err) {
GalliumLoop(app_id, arg0, &cgo_onReady, err);
}
*/
import "C"
import (
"fmt"
"log"
"time"
"unsafe"
)
// cerr holds a C-allocated error, which must be freed explicitly.
type cerr struct {
c *C.struct_gallium_error
}
// newCerr allocates a new error struct. It must be freed explicitly.
func newCerr() cerr {
return cerr{
c: (*C.struct_gallium_error)(C.malloc(C.sizeof_struct_gallium_error)),
}
}
func (e cerr) free() {
C.free(unsafe.Pointer(e.c))
}
func (e *cerr) err() error {
// TODO
return fmt.Errorf("C error")
}
// Loop starts the browser loop and does not return unless there is an initialization error
func Loop(args []string, onReady func(*App)) error {
log.Println("=== gallium.Loop ===")
cerr := newCerr()
defer cerr.free()
app := App{
ready: make(chan struct{}),
}
go func() {
select {
case <-app.ready:
onReady(&app)
case <-time.After(3 * time.Second):
log.Fatal("Waited for 3 seconds without ready signal")
}
}()
appId := apps.add(&app)
C.helper_GalliumLoop(C.int(appId), C.CString(args[0]), &cerr.c)
return cerr.err()
}
// appManager is the singleton for managing app instances
type appManager []*App
func (m *appManager) add(app *App) int {
id := len(*m)
*m = append(*m, app)
return id
}
func (m *appManager) get(id int) *App {
return (*m)[id]
}
var apps appManager
// App is the handle that allows you to create windows and menus
type App struct {
// ready is how the cgo onready callback indicates to the Loop goroutine that
// chromium is initialized
ready chan struct{}
}
// NewWindow creates a window that will oad the given URL and will display
// the given title
func (b *App) NewWindow(url, title string) error {
log.Println("=== gallium.NewWindow ===")
cerr := newCerr()
defer cerr.free()
C.GalliumCreateWindow(C.CString(url), C.CString(title), &cerr.c)
return nil
}