98 lines
2.5 KiB
Go
98 lines
2.5 KiB
Go
//go:build !s390x && !ppc64le && !darwin && !windows && !freebsd && (linux || openbsd || netbsd)
|
|
|
|
package screenshot
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/godbus/dbus/v5"
|
|
"image"
|
|
"image/draw"
|
|
"image/png"
|
|
"net/url"
|
|
"os"
|
|
"sync/atomic"
|
|
)
|
|
|
|
var gTokenCounter uint64 = 0
|
|
|
|
func captureDbus(x, y, width, height int) (img *image.RGBA, e error) {
|
|
c, err := dbus.ConnectSessionBus()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("dbus.SessionBus() failed: %v", err)
|
|
}
|
|
defer func(c *dbus.Conn) {
|
|
err := c.Close()
|
|
if err != nil {
|
|
e = err
|
|
}
|
|
}(c)
|
|
token := atomic.AddUint64(&gTokenCounter, 1)
|
|
options := map[string]dbus.Variant{
|
|
"modal": dbus.MakeVariant(false),
|
|
"interactive": dbus.MakeVariant(false),
|
|
"handle_token": dbus.MakeVariant(token),
|
|
}
|
|
obj := c.Object("org.freedesktop.portal.Desktop", dbus.ObjectPath("/org/freedesktop/portal/desktop"))
|
|
call := obj.Call("org.freedesktop.portal.Screenshot.Screenshot", 0, "", options)
|
|
var path dbus.ObjectPath
|
|
err = call.Store(&path)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("dbus.Store() failed: %v", err)
|
|
}
|
|
ch := make(chan *dbus.Message)
|
|
c.Eavesdrop(ch)
|
|
for msg := range ch {
|
|
o, ok := msg.Headers[dbus.FieldPath]
|
|
if !ok {
|
|
continue
|
|
}
|
|
s, ok := o.Value().(dbus.ObjectPath)
|
|
if !ok {
|
|
return nil, fmt.Errorf("dbus.FieldPath value does't have ObjectPath type")
|
|
}
|
|
if s != path {
|
|
continue
|
|
}
|
|
for _, body := range msg.Body {
|
|
v, ok := body.(map[string]dbus.Variant)
|
|
if !ok {
|
|
continue
|
|
}
|
|
uri, ok := v["uri"]
|
|
if !ok {
|
|
continue
|
|
}
|
|
path, ok := uri.Value().(string)
|
|
if !ok {
|
|
return nil, fmt.Errorf("uri is not a string")
|
|
}
|
|
fpath, err := url.Parse(path)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("url.Parse(%v) failed: %v", path, err)
|
|
}
|
|
if fpath.Scheme != "file" {
|
|
return nil, fmt.Errorf("uri is not a file path")
|
|
}
|
|
file, err := os.Open(fpath.Path)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("os.Open(%s) failed: %v", path, err)
|
|
}
|
|
defer func(file *os.File) {
|
|
_ = file.Close()
|
|
_ = os.Remove(fpath.Path)
|
|
}(file)
|
|
img, err := png.Decode(file)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("png.Decode(%s) failed: %v", path, err)
|
|
}
|
|
canvas, err := createImage(image.Rect(0, 0, width, height))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("createImage(%v) failed: %v", path, err)
|
|
}
|
|
draw.Draw(canvas, image.Rect(0, 0, width, height), img, image.Point{x, y}, draw.Src)
|
|
return canvas, e
|
|
}
|
|
}
|
|
return nil, fmt.Errorf("dbus.Message doesn't contain uri")
|
|
}
|