代码拉取完成,页面将自动刷新
同步操作将从 tupelo-shen/mysnapd 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2020-2021 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package portal
import (
"fmt"
"syscall"
"time"
"github.com/godbus/dbus"
"gitee.com/mysnapcore/mysnapd/osutil"
)
const (
desktopPortalBusName = "org.freedesktop.portal.Desktop"
desktopPortalObjectPath = "/org/freedesktop/portal/desktop"
desktopPortalOpenURIIface = "org.freedesktop.portal.OpenURI"
desktopPortalRequestIface = "org.freedesktop.portal.Request"
)
type ResponseError struct {
msg string
}
func (u *ResponseError) Error() string { return u.msg }
func (u *ResponseError) Is(err error) bool {
_, ok := err.(*ResponseError)
return ok
}
func MakeResponseError(msg string) error {
osutil.MustBeTestBinary("only to be used in tests")
return &ResponseError{msg: msg}
}
// desktopPortal gets a reference to the xdg-desktop-portal D-Bus service
func desktopPortal(bus *dbus.Conn) (dbus.BusObject, error) {
// We call StartServiceByName since old versions of
// xdg-desktop-portal do not include the AssumedAppArmorLabel
// key in their service activation file.
var startResult uint32
err := bus.BusObject().Call("org.freedesktop.DBus.StartServiceByName", 0, desktopPortalBusName, uint32(0)).Store(&startResult)
if dbusErr, ok := err.(dbus.Error); ok {
// If it is not possible to activate the service
// (i.e. there is no .service file or the systemd unit
// has been masked), assume it is already
// running. Subsequent method calls will fail if this
// assumption is false.
if dbusErr.Name == "org.freedesktop.DBus.Error.ServiceUnknown" || dbusErr.Name == "org.freedesktop.systemd1.Masked" {
err = nil
startResult = 2 // DBUS_START_REPLY_ALREADY_RUNNING
}
}
if err != nil {
return nil, err
}
switch startResult {
case 1: // DBUS_START_REPLY_SUCCESS
case 2: // DBUS_START_REPLY_ALREADY_RUNNING
default:
return nil, fmt.Errorf("unexpected response from StartServiceByName (code %v)", startResult)
}
return bus.Object(desktopPortalBusName, desktopPortalObjectPath), nil
}
// portalResponseSuccess is a numeric value indicating a success carrying out
// the request, returned by the `response` member of
// org.freedesktop.portal.Request.Response signal
const portalResponseSuccess = 0
// timeout for asking the user to make a choice, same value as in usersession/userd/launcher.go
var defaultPortalRequestTimeout = 5 * time.Minute
func portalCall(bus *dbus.Conn, call func() (dbus.ObjectPath, error)) error {
// see https://flatpak.github.io/xdg-desktop-portal/portal-docs.html for
// details of the interaction, in short:
// 1. caller issues a request to the desktop portal
// 2. desktop portal responds with a handle to a dbus object capturing the Request
// 3. caller waits for the org.freedesktop.portal.Request.Response
// 3a. caller can terminate the request earlier by calling close
// set up signal handling before we call the portal, so that we do not
// miss the signals
signals := make(chan *dbus.Signal, 1)
bus.Signal(signals)
defer func() {
bus.RemoveSignal(signals)
close(signals)
}()
// TODO: this should use dbus.Conn.AddMatchSignal, but that
// does not exist in the external copies of godbus on some
// supported platforms.
const matchRule = "type='signal',sender='" + desktopPortalBusName + "',interface='" + desktopPortalRequestIface + "',member='Response'"
if err := bus.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, matchRule).Store(); err != nil {
return err
}
defer bus.BusObject().Call("org.freedesktop.DBus.RemoveMatch", 0, matchRule)
requestPath, err := call()
if err != nil {
return err
}
request := bus.Object(desktopPortalBusName, requestPath)
timeout := time.NewTimer(defaultPortalRequestTimeout)
defer timeout.Stop()
for {
select {
case <-timeout.C:
request.Call(desktopPortalRequestIface+".Close", 0).Store()
return &ResponseError{msg: "timeout waiting for user response"}
case signal := <-signals:
if signal.Path != requestPath || signal.Name != desktopPortalRequestIface+".Response" {
// This isn't the signal we're waiting for
continue
}
var response uint32
var results map[string]interface{} // don't care
if err := dbus.Store(signal.Body, &response, &results); err != nil {
return &ResponseError{msg: fmt.Sprintf("cannot unpack response: %v", err)}
}
if response == portalResponseSuccess {
return nil
}
return &ResponseError{msg: fmt.Sprintf("request declined by the user (code %v)", response)}
}
}
}
func OpenFile(bus *dbus.Conn, filename string) error {
portal, err := desktopPortal(bus)
if err != nil {
return err
}
fd, err := syscall.Open(filename, syscall.O_RDONLY, 0)
if err != nil {
return &ResponseError{msg: err.Error()}
}
defer syscall.Close(fd)
return portalCall(bus, func() (dbus.ObjectPath, error) {
var (
parent string
options map[string]dbus.Variant
request dbus.ObjectPath
)
err := portal.Call(desktopPortalOpenURIIface+".OpenFile", 0, parent, dbus.UnixFD(fd), options).Store(&request)
return request, err
})
}
func OpenURI(bus *dbus.Conn, uri string) error {
portal, err := desktopPortal(bus)
if err != nil {
return err
}
return portalCall(bus, func() (dbus.ObjectPath, error) {
var (
parent string
options map[string]dbus.Variant
request dbus.ObjectPath
)
err := portal.Call(desktopPortalOpenURIIface+".OpenURI", 0, parent, uri, options).Store(&request)
return request, err
})
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。