-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
driver.go
128 lines (105 loc) · 2.91 KB
/
driver.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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// Package glfw provides a full Fyne desktop driver that uses the system OpenGL libraries.
// This supports Windows, Mac OS X and Linux using the gl and glfw packages from go-gl.
package glfw
import (
"runtime"
"strconv"
"strings"
"sync"
"fyne.io/fyne"
"fyne.io/fyne/internal/driver"
"fyne.io/fyne/internal/painter"
)
const mainGoroutineID = 1
var (
canvasMutex sync.RWMutex
canvases = make(map[fyne.CanvasObject]fyne.Canvas)
isWayland = false
)
// Declare conformity with Driver
var _ fyne.Driver = (*gLDriver)(nil)
type gLDriver struct {
windowLock sync.RWMutex
windows []fyne.Window
device *glDevice
done chan interface{}
drawDone chan interface{}
}
func (d *gLDriver) RenderedTextSize(text string, size int, style fyne.TextStyle) fyne.Size {
return painter.RenderedTextSize(text, size, style)
}
func (d *gLDriver) CanvasForObject(obj fyne.CanvasObject) fyne.Canvas {
canvasMutex.RLock()
defer canvasMutex.RUnlock()
return canvases[obj]
}
func (d *gLDriver) AbsolutePositionForObject(co fyne.CanvasObject) fyne.Position {
c := d.CanvasForObject(co)
if c == nil {
return fyne.NewPos(0, 0)
}
glc := c.(*glCanvas)
return driver.AbsolutePositionForObject(co, glc.objectTrees())
}
func (d *gLDriver) Device() fyne.Device {
if d.device == nil {
d.device = &glDevice{}
}
return d.device
}
func (d *gLDriver) Quit() {
defer func() {
recover() // we could be called twice - no safe way to check if d.done is closed
}()
close(d.done)
}
func (d *gLDriver) Run() {
if goroutineID() != mainGoroutineID {
panic("Run() or ShowAndRun() must be called from main goroutine")
}
d.runGL()
}
func (d *gLDriver) addWindow(w *window) {
d.windowLock.Lock()
defer d.windowLock.Unlock()
d.windows = append(d.windows, w)
}
// a trivial implementation of "focus previous" - return to the most recently opened, or master if set.
// This may not do the right thing if your app has 3 or more windows open, but it was agreed this was not much
// of an issue, and the added complexity to track focus was not needed at this time.
func (d *gLDriver) focusPreviousWindow() {
d.windowLock.RLock()
wins := d.windows
d.windowLock.RUnlock()
var chosen fyne.Window
for _, w := range wins {
chosen = w
if w.(*window).master {
break
}
}
if chosen == nil || chosen.(*window).view() == nil {
return
}
chosen.RequestFocus()
}
func (d *gLDriver) windowList() []fyne.Window {
d.windowLock.RLock()
defer d.windowLock.RUnlock()
return d.windows
}
func goroutineID() int {
b := make([]byte, 64)
b = b[:runtime.Stack(b, false)]
// string format expects "goroutine X [running..."
id := strings.Split(strings.TrimSpace(string(b)), " ")[1]
num, _ := strconv.Atoi(id)
return num
}
// NewGLDriver sets up a new Driver instance implemented using the GLFW Go library and OpenGL bindings.
func NewGLDriver() fyne.Driver {
d := new(gLDriver)
d.done = make(chan interface{})
d.drawDone = make(chan interface{})
return d
}