1
0
Fork 0
golang-golang-x-clipboard/cmd/gclip-gui/main.go
Daniel Baumann 79ead63b61
Adding upstream version 0.7.0+dfsg.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-05-24 12:03:12 +02:00

239 lines
4.9 KiB
Go

// Copyright 2021 The golang.design Initiative Authors.
// All rights reserved. Use of this source code is governed
// by a MIT license that can be found in the LICENSE file.
//
// Written by Changkun Ou <changkun.de>
//go:build android || ios || linux || darwin || windows
// +build android ios linux darwin windows
// This is a very basic example for verification purpose that
// demonstrates how the golang.design/x/clipboard can interact
// with macOS/Linux/Windows/Android/iOS system clipboard.
//
// The gclip GUI application writes a string to the system clipboard
// periodically then reads it back and renders it if possible.
//
// Because of the system limitation, on mobile devices, only string
// data is supported at the moment. Hence, one must use clipboard.FmtText.
// Other supplied formats result in a panic.
//
// This example is intentded as cross platform application.
// To build it, one must use gomobile (https://golang.org/x/mobile).
// You may follow the instructions provided in the GoMobile's wiki page:
// https://github.com/golang/go/wiki/Mobile.
//
// - For desktop:
//
// go build -o gclip-gui
//
// - For Android:
//
// gomobile build -v -target=android -o gclip-gui.apk
//
// - For iOS:
//
// gomobile build -v -target=ios -bundleid design.golang.gclip-gui.app
//
package main
import (
"fmt"
"image"
"image/color"
"log"
"os"
"sync"
"time"
"golang.design/x/clipboard"
"golang.org/x/image/font"
"golang.org/x/image/font/basicfont"
"golang.org/x/image/math/fixed"
"golang.org/x/mobile/app"
"golang.org/x/mobile/event/lifecycle"
"golang.org/x/mobile/event/paint"
"golang.org/x/mobile/event/size"
"golang.org/x/mobile/exp/gl/glutil"
"golang.org/x/mobile/geom"
"golang.org/x/mobile/gl"
)
type Label struct {
sz size.Event
images *glutil.Images
m *glutil.Image
drawer *font.Drawer
mu sync.Mutex
data string
}
func NewLabel(images *glutil.Images) *Label {
return &Label{
images: images,
data: "Hello! Gclip.",
drawer: nil,
}
}
func (l *Label) SetLabel(s string) {
l.mu.Lock()
defer l.mu.Unlock()
l.data = s
}
const (
fontWidth = 5
fontHeight = 7
lineWidth = 100
lineHeight = 120
)
func (l *Label) Draw(sz size.Event) {
l.mu.Lock()
s := l.data
l.mu.Unlock()
imgW, imgH := lineWidth*basicfont.Face7x13.Width, lineHeight*basicfont.Face7x13.Height
if sz.WidthPx == 0 && sz.HeightPx == 0 {
return
}
if imgW > sz.WidthPx {
imgW = sz.WidthPx
}
if l.sz != sz {
l.sz = sz
if l.m != nil {
l.m.Release()
}
l.m = l.images.NewImage(imgW, imgH)
}
// Clear the drawing image.
for i := 0; i < len(l.m.RGBA.Pix); i++ {
l.m.RGBA.Pix[i] = 0
}
l.drawer = &font.Drawer{
Dst: l.m.RGBA,
Src: image.NewUniform(color.RGBA{0, 100, 125, 255}),
Face: basicfont.Face7x13,
Dot: fixed.P(5, 10),
}
l.drawer.DrawString(s)
l.m.Upload()
l.m.Draw(
sz,
geom.Point{X: 0, Y: 50},
geom.Point{X: geom.Pt(imgW), Y: 50},
geom.Point{X: 0, Y: geom.Pt(imgH)},
l.m.RGBA.Bounds(),
)
}
func (l *Label) Release() {
if l.m != nil {
l.m.Release()
l.m = nil
l.images = nil
}
}
// GclipApp is the application instance.
type GclipApp struct {
app app.App
ctx gl.Context
siz size.Event
images *glutil.Images
l *Label
counter int
}
// WatchClipboard watches the system clipboard every seconds.
func (g *GclipApp) WatchClipboard() {
go func() {
tk := time.NewTicker(time.Second)
for range tk.C {
// Write something to the clipboard
w := fmt.Sprintf("(gclip: %d)", g.counter)
clipboard.Write(clipboard.FmtText, []byte(w))
g.counter++
log.Println(w)
// Read it back and render it, if possible.
data := clipboard.Read(clipboard.FmtText)
if len(data) == 0 {
continue
}
// Set the current clipboard data as label content and render on the screen.
r := fmt.Sprintf("clipboard: %s", string(data))
g.l.SetLabel(r)
g.app.Send(paint.Event{})
}
}()
}
func (g *GclipApp) OnStart(e lifecycle.Event) {
g.ctx, _ = e.DrawContext.(gl.Context)
g.images = glutil.NewImages(g.ctx)
g.l = NewLabel(g.images)
g.app.Send(paint.Event{})
}
func (g *GclipApp) OnStop() {
g.l.Release()
g.images.Release()
g.ctx = nil
}
func (g *GclipApp) OnSize(size size.Event) {
g.siz = size
}
func (g *GclipApp) OnDraw() {
if g.ctx == nil {
return
}
defer g.app.Send(paint.Event{})
defer g.app.Publish()
g.ctx.ClearColor(0, 0, 0, 1)
g.ctx.Clear(gl.COLOR_BUFFER_BIT)
g.l.Draw(g.siz)
}
func init() {
err := clipboard.Init()
if err != nil {
panic(err)
}
}
func main() {
app.Main(func(a app.App) {
gclip := GclipApp{app: a}
gclip.app.Send(size.Event{WidthPx: 800, HeightPx: 500})
gclip.WatchClipboard()
for e := range gclip.app.Events() {
switch e := gclip.app.Filter(e).(type) {
case lifecycle.Event:
switch e.Crosses(lifecycle.StageVisible) {
case lifecycle.CrossOn:
gclip.OnStart(e)
case lifecycle.CrossOff:
gclip.OnStop()
os.Exit(0)
}
case size.Event:
gclip.OnSize(e)
case paint.Event:
gclip.OnDraw()
}
}
})
}