forked from sternix/wl
-
Notifications
You must be signed in to change notification settings - Fork 7
/
context.go
129 lines (112 loc) · 2.29 KB
/
context.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
129
package wl
import (
"context"
"errors"
"io"
"log"
"net"
"os"
"sync"
"time"
)
func init() {
log.SetFlags(0)
}
type Context struct {
mu sync.RWMutex
conn *net.UnixConn
currentId ProxyId
objects map[ProxyId]Proxy
dispatchChan chan struct{}
exitChan chan struct{}
}
func (ctx *Context) Register(proxy Proxy) {
ctx.mu.Lock()
defer ctx.mu.Unlock()
ctx.currentId += 1
proxy.SetId(ctx.currentId)
proxy.SetContext(ctx)
ctx.objects[ctx.currentId] = proxy
}
func (ctx *Context) lookupProxy(id ProxyId) Proxy {
ctx.mu.RLock()
defer ctx.mu.RUnlock()
proxy, ok := ctx.objects[id]
if !ok {
return nil
}
return proxy
}
func (ctx *Context) unregister(proxy Proxy) {
ctx.mu.Lock()
defer ctx.mu.Unlock()
delete(ctx.objects, proxy.Id())
}
func (c *Context) Close() {
c.conn.Close()
c.exitChan <- struct{}{}
close(c.dispatchChan)
}
func (c *Context) Dispatch() chan<- struct{} {
return c.dispatchChan
}
func Connect(addr string) (ret *Display, err error) {
runtime_dir := os.Getenv("XDG_RUNTIME_DIR")
if runtime_dir == "" {
return nil, errors.New("XDG_RUNTIME_DIR not set in the environment.")
}
if addr == "" {
addr = os.Getenv("WAYLAND_DISPLAY")
}
if addr == "" {
addr = "wayland-0"
}
addr = runtime_dir + "/" + addr
c := new(Context)
c.objects = make(map[ProxyId]Proxy)
c.currentId = 0
c.dispatchChan = make(chan struct{})
c.exitChan = make(chan struct{})
c.conn, err = net.DialUnix("unix", nil, &net.UnixAddr{Name: addr, Net: "unix"})
if err != nil {
return nil, err
}
c.conn.SetReadDeadline(time.Time{})
//dispatch events in separate gorutine
go c.run()
return NewDisplay(c), nil
}
func (c *Context) run() {
ctx := context.Background()
loop:
for {
select {
case <-c.dispatchChan:
ev, err := c.readEvent()
if err != nil {
if err == io.EOF {
// connection closed
break loop
}
if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
log.Print("Timeout Error")
continue
}
log.Fatal(err)
}
proxy := c.lookupProxy(ev.pid)
if proxy != nil {
if dispatcher, ok := proxy.(Dispatcher); ok {
dispatcher.Dispatch(ctx, ev)
bytePool.Give(ev.data)
} else {
log.Print("Not dispatched")
}
} else {
log.Print("Proxy NULL")
}
case <-c.exitChan:
break loop
}
}
}