neko/server/internal/desktop/clipboard.go

123 lines
2.6 KiB
Go
Raw Permalink Normal View History

2020-11-02 04:09:48 +13:00
package desktop
import (
2021-01-29 09:19:31 +13:00
"bytes"
2021-02-15 02:40:17 +13:00
"fmt"
2021-01-29 09:12:35 +13:00
"os/exec"
"strings"
"github.com/demodesk/neko/pkg/types"
"github.com/demodesk/neko/pkg/xevent"
2020-11-02 04:09:48 +13:00
)
func (manager *DesktopManagerCtx) ClipboardGetText() (*types.ClipboardText, error) {
text, err := manager.ClipboardGetBinary("STRING")
if err != nil {
return nil, err
}
// Rich text must not always be available, can fail silently.
html, _ := manager.ClipboardGetBinary("text/html")
return &types.ClipboardText{
Text: string(text),
HTML: string(html),
}, nil
}
func (manager *DesktopManagerCtx) ClipboardSetText(data types.ClipboardText) error {
// TODO: Refactor.
// Current implementation is unable to set multiple targets. HTML
// is set, if available. Otherwise plain text.
if data.HTML != "" {
return manager.ClipboardSetBinary("text/html", []byte(data.HTML))
}
return manager.ClipboardSetBinary("STRING", []byte(data.Text))
}
func (manager *DesktopManagerCtx) ClipboardGetBinary(mime string) ([]byte, error) {
2021-01-29 12:03:22 +13:00
cmd := exec.Command("xclip", "-selection", "clipboard", "-out", "-target", mime)
2021-01-29 09:19:31 +13:00
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
2021-02-02 06:29:39 +13:00
msg := strings.TrimSpace(stderr.String())
return nil, fmt.Errorf("%s", msg)
2021-01-29 09:19:31 +13:00
}
return stdout.Bytes(), nil
2020-11-02 04:09:48 +13:00
}
func (manager *DesktopManagerCtx) ClipboardSetBinary(mime string, data []byte) error {
2021-01-29 12:03:22 +13:00
cmd := exec.Command("xclip", "-selection", "clipboard", "-in", "-target", mime)
2021-01-29 09:19:31 +13:00
var stderr bytes.Buffer
cmd.Stderr = &stderr
2021-02-15 02:40:17 +13:00
stdin, err := cmd.StdinPipe()
2021-01-29 12:03:22 +13:00
if err != nil {
return err
}
2022-05-04 07:57:31 +12:00
// TODO: Refactor.
// We need to wait until the data came to the clipboard.
wait := make(chan struct{})
xevent.Emmiter.Once("clipboard-updated", func(payload ...any) {
2022-05-04 07:57:31 +12:00
wait <- struct{}{}
})
2021-01-29 12:03:22 +13:00
err = cmd.Start()
2021-01-29 09:19:31 +13:00
if err != nil {
2021-02-02 06:29:39 +13:00
msg := strings.TrimSpace(stderr.String())
2021-01-29 09:19:31 +13:00
return fmt.Errorf("%s", msg)
}
2021-02-02 06:29:39 +13:00
_, err = stdin.Write(data)
if err != nil {
return err
}
2021-01-29 12:03:22 +13:00
stdin.Close()
2021-01-29 09:19:31 +13:00
2021-01-29 12:03:22 +13:00
// TODO: Refactor.
// cmd.Wait()
2022-05-04 07:57:31 +12:00
<-wait
2021-01-29 09:19:31 +13:00
return nil
2020-11-02 04:09:48 +13:00
}
func (manager *DesktopManagerCtx) ClipboardGetTargets() ([]string, error) {
2021-01-29 12:03:22 +13:00
cmd := exec.Command("xclip", "-selection", "clipboard", "-out", "-target", "TARGETS")
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
2021-02-02 06:29:39 +13:00
msg := strings.TrimSpace(stderr.String())
return nil, fmt.Errorf("%s", msg)
}
var response []string
2021-02-02 06:29:39 +13:00
targets := strings.Split(stdout.String(), "\n")
for _, target := range targets {
if target == "" {
continue
}
if !strings.Contains(target, "/") {
continue
}
2021-02-03 06:28:32 +13:00
response = append(response, target)
}
return response, nil
}