-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathclipboard.go
108 lines (91 loc) · 2.03 KB
/
clipboard.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
// Package clipboard gives access to the system's text clipboard.
package clipboard
import (
"sync"
)
var listeners struct {
sync.Mutex
m map[chan<- string]struct{}
}
type requestType int
const (
watchRequest requestType = iota
unwatchRequest
getRequest
setRequest
)
type reply struct {
s string
err error
}
type request struct {
t requestType
s string
c chan reply
}
// Use a control channel to relay clipboard requests into a handler goroutine.
// This is required because on some systems all clipboard calls must originate
// from the same thread.
var ctl = make(chan request, 1)
// Get returns the current clipboard value.
func Get() (string, error) {
c := make(chan reply, 1)
ctl <- request{getRequest, "", c}
select {
case r := <-c:
return r.s, r.err
}
}
// Set sets the clipboard value.
func Set(s string) error {
c := make(chan reply, 1)
ctl <- request{setRequest, s, c}
select {
case r := <-c:
return r.err
}
}
// Notify causes c to receive future clipboard values.
// If c is already receiving clipboard values, Notify is a no-op.
//
// This package will not block sending to c. It is the caller's responsibility
// to either ensure enough buffer is available.
func Notify(c chan<- string) {
listeners.Lock()
defer listeners.Unlock()
if listeners.m == nil {
listeners.m = make(map[chan<- string]struct{})
}
if len(listeners.m) == 0 {
defer func() {
r := make(chan reply, 1)
ctl <- request{watchRequest, "", r}
<-r
}()
}
listeners.m[c] = struct{}{}
}
// Unnotify causes c to no longer receive clipboard values.
// If c is not receiving clipboard values, Unnotify is a no-op.
//
// It is guaranteed that c receives no more values after Unnotify returns.
func Unnotify(c chan<- string) {
listeners.Lock()
defer listeners.Unlock()
delete(listeners.m, c)
if len(listeners.m) == 0 {
r := make(chan reply, 1)
ctl <- request{unwatchRequest, "", r}
<-r
}
}
func broadcast(s string) {
listeners.Lock()
defer listeners.Unlock()
for c := range listeners.m {
select {
case c <- s:
default:
}
}
}