V3 alpha linux dbus (#2996)

* [v3 linux/systray] dbus generation

* [v3 linux] systemtray dbus implementation

* [v3] add 'id' for MenuSeparator

This is needed in order to have a unique value for all
menuItem(s) such that the Linux implementation doesn't have to
generate new identifiers.
Allowing the reuse keeps a 1-1 mapping in place without any extra effort.

* [v3 example/systray] add radio group to example

* [v3 linux] stub out ExportStatusNotifierItem callbacks

Can only seem to get the `SecondaryActivate` to fire when doing a
3-finger click!  I was expecting a right-click interaction to trigger it.
This commit is contained in:
Travis McLane
2023-10-21 11:39:46 +11:00
committed by GitHub
parent 8463c01123
commit 18746c7819
15 changed files with 1896 additions and 6 deletions
+14
View File
@@ -2,6 +2,7 @@ package main
import (
_ "embed"
"fmt"
"log"
"runtime"
@@ -71,6 +72,19 @@ func main() {
println("Click me!")
ctx.ClickedMenuItem().SetLabel("Disabled!").SetEnabled(false)
})
myMenu.AddSeparator()
// Callbacks can be shared. This is useful for radio groups
radioCallback := func(ctx *application.Context) {
menuItem := ctx.ClickedMenuItem()
menuItem.SetLabel(menuItem.Label() + "!")
fmt.Println("radioCallback: ")
}
// Radio groups are created implicitly by placing radio items next to each other in a menu
myMenu.AddRadio("Radio 1", true).OnClick(radioCallback)
myMenu.AddRadio("Radio 2", false).OnClick(radioCallback)
myMenu.AddRadio("Radio 3", false).OnClick(radioCallback)
myMenu.AddSeparator()
myMenu.Add("Quit").OnClick(func(ctx *application.Context) {
app.Quit()
+1
View File
@@ -8,6 +8,7 @@ require (
github.com/go-git/go-git/v5 v5.3.0
github.com/go-ole/go-ole v1.2.6
github.com/go-task/task/v3 v3.31.0
github.com/godbus/dbus/v5 v5.1.0
github.com/google/go-cmp v0.5.9
github.com/google/uuid v1.3.0
github.com/gorilla/pat v1.0.1
+2
View File
@@ -119,6 +119,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZ
github.com/go-task/task/v3 v3.31.0 h1:o6iyj9gPJXxvxPi/u/l8e025PmM2BqKgtLNPS2i7hV4=
github.com/go-task/task/v3 v3.31.0/go.mod h1:/CPDAu9nS3+soqY/e1tTrSo/zxk76lnljEV9aBTeKrg=
github.com/goccy/go-json v0.9.6/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+60
View File
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<node name="/" xmlns:dox="http://www.canonical.com/dbus/dox.dtd">
<interface name="com.canonical.dbusmenu">
<!-- Properties -->
<property name="Version" type="u" access="read"/>
<property name="TextDirection" type="s" access="read"/>
<property name="Status" type="s" access="read"/>
<property name="IconThemePath" type="as" access="read"/>
<!-- Functions -->
<method name="GetLayout">
<arg type="i" name="parentId" direction="in"/>
<arg type="i" name="recursionDepth" direction="in"/>
<arg type="as" name="propertyNames" direction="in"/>
<arg type="u" name="revision" direction="out"/>
<arg type="(ia{sv}av)" name="layout" direction="out"/>
</method>
<method name="GetGroupProperties">
<arg type="ai" name="ids" direction="in"/>
<arg type="as" name="propertyNames" direction="in"/>
<arg type="a(ia{sv})" name="properties" direction="out"/>
</method>
<method name="GetProperty">
<arg type="i" name="id" direction="in"/>
<arg type="s" name="name" direction="in"/>
<arg type="v" name="value" direction="out"/>
</method>
<method name="Event">
<arg type="i" name="id" direction="in"/>
<arg type="s" name="eventId" direction="in"/>
<arg type="v" name="data" direction="in"/>
<arg type="u" name="timestamp" direction="in"/>
</method>
<method name="EventGroup">
<arg type="a(isvu)" name="events" direction="in"/>
<arg type="ai" name="idErrors" direction="out"/>
</method>
<method name="AboutToShow">
<arg type="i" name="id" direction="in"/>
<arg type="b" name="needUpdate" direction="out"/>
</method>
<method name="AboutToShowGroup">
<arg type="ai" name="ids" direction="in"/>
<arg type="ai" name="updatesNeeded" direction="out"/>
<arg type="ai" name="idErrors" direction="out"/>
</method>
<!-- Signals -->
<signal name="ItemsPropertiesUpdated">
<arg type="a(ia{sv})" name="updatedProps" direction="out"/>
<arg type="a(ias)" name="removedProps" direction="out"/>
</signal>
<signal name="LayoutUpdated">
<arg type="u" name="revision" direction="out"/>
<arg type="i" name="parent" direction="out"/>
</signal>
<signal name="ItemActivationRequested">
<arg type="i" name="id" direction="out"/>
<arg type="u" name="timestamp" direction="out"/>
</signal>
</interface>
</node>
+5
View File
@@ -0,0 +1,5 @@
//Note that you need to have github.com/knightpp/dbus-codegen-go installed from "custom" branch
//go:generate dbus-codegen-go -prefix org.kde -package notifier -output internal/generated/notifier/status_notifier_item.go internal/StatusNotifierItem.xml
//go:generate dbus-codegen-go -prefix com.canonical -package menu -output internal/generated/menu/dbus_menu.go internal/DbusMenu.xml
+85
View File
@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<node name="/StatusNotifierItem">
<!-- Based on:
https://invent.kde.org/frameworks/knotifications/-/blob/master/src/org.kde.StatusNotifierItem.xml
-->
<interface name="org.kde.StatusNotifierItem">
<property name="Category" type="s" access="read"/>
<property name="Id" type="s" access="read"/>
<property name="Title" type="s" access="read"/>
<property name="Status" type="s" access="read"/>
<property name="WindowId" type="i" access="read"/>
<!-- An additional path to add to the theme search path to find the icons specified above. -->
<property name="IconThemePath" type="s" access="read"/>
<property name="Menu" type="o" access="read"/>
<property name="ItemIsMenu" type="b" access="read"/>
<!-- main icon -->
<!-- names are preferred over pixmaps -->
<property name="IconName" type="s" access="read"/>
<!-- struct containing width, height and image data -->
<property name="IconPixmap" type="a(iiay)" access="read">
<annotation name="org.qtproject.QtDBus.QtTypeName" value="KDbusImageVector"/>
</property>
<property name="OverlayIconName" type="s" access="read"/>
<property name="OverlayIconPixmap" type="a(iiay)" access="read">
<annotation name="org.qtproject.QtDBus.QtTypeName" value="KDbusImageVector"/>
</property>
<!-- Requesting attention icon -->
<property name="AttentionIconName" type="s" access="read"/>
<!-- same definition as image -->
<property name="AttentionIconPixmap" type="a(iiay)" access="read">
<annotation name="org.qtproject.QtDBus.QtTypeName" value="KDbusImageVector"/>
</property>
<property name="AttentionMovieName" type="s" access="read"/>
<!-- tooltip data -->
<!-- (iiay) is an image -->
<property name="ToolTip" type="(sa(iiay)ss)" access="read">
<annotation name="org.qtproject.QtDBus.QtTypeName" value="KDbusToolTipStruct"/>
</property>
<!-- interaction: the systemtray wants the application to do something -->
<method name="ContextMenu">
<!-- we're passing the coordinates of the icon, so the app knows where to put the popup window -->
<arg name="x" type="i" direction="in"/>
<arg name="y" type="i" direction="in"/>
</method>
<method name="Activate">
<arg name="x" type="i" direction="in"/>
<arg name="y" type="i" direction="in"/>
</method>
<method name="SecondaryActivate">
<arg name="x" type="i" direction="in"/>
<arg name="y" type="i" direction="in"/>
</method>
<method name="Scroll">
<arg name="delta" type="i" direction="in"/>
<arg name="orientation" type="s" direction="in"/>
</method>
<!-- Signals: the client wants to change something in the status -->
<signal name="NewTitle"> </signal>
<signal name="NewIcon"> </signal>
<signal name="NewAttentionIcon"> </signal>
<signal name="NewOverlayIcon"> </signal>
<!-- We disable this as we don't support tooltip, so no need to go through it
<signal name="NewToolTip">
</signal>
-->
<signal name="NewStatus">
<arg name="status" type="s"/>
</signal>
<!-- The following items are not supported by specs, but widely used -->
<signal name="NewIconThemePath">
<arg type="s" name="icon_theme_path" direction="out"/>
</signal>
<signal name="NewMenu"/>
<!-- ayatana labels -->
<!-- These are commented out because GDBusProxy would otherwise require them,
but they are not available for KDE indicators
-->
<!-- <signal name="XAyatanaNewLabel">
<arg type="s" name="label" direction="out" />
<arg type="s" name="guide" direction="out" />
</signal>
<property name="XAyatanaLabel" type="s" access="read" />
<property name="XAyatanaLabelGuide" type="s" access="read" /> -->
</interface>
</node>
+4
View File
@@ -0,0 +1,4 @@
package dbus
//go:generate dbus-codegen-go -prefix org.kde -package notifier -output notifier/status_notifier_item.go StatusNotifierItem.xml
//go:generate dbus-codegen-go -prefix com.canonical -package menu -output menu/dbus_menu.go DbusMenu.xml
+2
View File
@@ -0,0 +1,2 @@
dbus-codegen-go -prefix com.canonical -package menu -output dbus_menu.go DbusMenu.xml
dbus-codegen-go -prefix org.kde -package notifier -output status_notifier_item.go StatusNotifierItem.xml
View File
+483
View File
@@ -0,0 +1,483 @@
// Code generated by dbus-codegen-go DO NOT EDIT.
package menu
import (
"context"
"errors"
"fmt"
"github.com/godbus/dbus/v5"
"github.com/godbus/dbus/v5/introspect"
)
var (
// Introspection for com.canonical.dbusmenu
IntrospectDataDbusmenu = introspect.Interface{
Name: "com.canonical.dbusmenu",
Methods: []introspect.Method{{Name: "GetLayout", Args: []introspect.Arg{
{Name: "parentId", Type: "i", Direction: "in"},
{Name: "recursionDepth", Type: "i", Direction: "in"},
{Name: "propertyNames", Type: "as", Direction: "in"},
{Name: "revision", Type: "u", Direction: "out"},
{Name: "layout", Type: "(ia{sv}av)", Direction: "out"},
}},
{Name: "GetGroupProperties", Args: []introspect.Arg{
{Name: "ids", Type: "ai", Direction: "in"},
{Name: "propertyNames", Type: "as", Direction: "in"},
{Name: "properties", Type: "a(ia{sv})", Direction: "out"},
}},
{Name: "GetProperty", Args: []introspect.Arg{
{Name: "id", Type: "i", Direction: "in"},
{Name: "name", Type: "s", Direction: "in"},
{Name: "value", Type: "v", Direction: "out"},
}},
{Name: "Event", Args: []introspect.Arg{
{Name: "id", Type: "i", Direction: "in"},
{Name: "eventId", Type: "s", Direction: "in"},
{Name: "data", Type: "v", Direction: "in"},
{Name: "timestamp", Type: "u", Direction: "in"},
}},
{Name: "EventGroup", Args: []introspect.Arg{
{Name: "events", Type: "a(isvu)", Direction: "in"},
{Name: "idErrors", Type: "ai", Direction: "out"},
}},
{Name: "AboutToShow", Args: []introspect.Arg{
{Name: "id", Type: "i", Direction: "in"},
{Name: "needUpdate", Type: "b", Direction: "out"},
}},
{Name: "AboutToShowGroup", Args: []introspect.Arg{
{Name: "ids", Type: "ai", Direction: "in"},
{Name: "updatesNeeded", Type: "ai", Direction: "out"},
{Name: "idErrors", Type: "ai", Direction: "out"},
}},
},
Signals: []introspect.Signal{{Name: "ItemsPropertiesUpdated", Args: []introspect.Arg{
{Name: "updatedProps", Type: "a(ia{sv})", Direction: "out"},
{Name: "removedProps", Type: "a(ias)", Direction: "out"},
}},
{Name: "LayoutUpdated", Args: []introspect.Arg{
{Name: "revision", Type: "u", Direction: "out"},
{Name: "parent", Type: "i", Direction: "out"},
}},
{Name: "ItemActivationRequested", Args: []introspect.Arg{
{Name: "id", Type: "i", Direction: "out"},
{Name: "timestamp", Type: "u", Direction: "out"},
}},
},
Properties: []introspect.Property{{Name: "Version", Type: "u", Access: "read"},
{Name: "TextDirection", Type: "s", Access: "read"},
{Name: "Status", Type: "s", Access: "read"},
{Name: "IconThemePath", Type: "as", Access: "read"},
},
Annotations: []introspect.Annotation{},
}
)
// Signal is a common interface for all signals.
type Signal interface {
Name() string
Interface() string
Sender() string
path() dbus.ObjectPath
values() []interface{}
}
// Emit sends the given signal to the bus.
func Emit(conn *dbus.Conn, s Signal) error {
return conn.Emit(s.path(), s.Interface()+"."+s.Name(), s.values()...)
}
// ErrUnknownSignal is returned by LookupSignal when a signal cannot be resolved.
var ErrUnknownSignal = errors.New("unknown signal")
// LookupSignal converts the given raw D-Bus signal with variable body
// into one with typed structured body or returns ErrUnknownSignal error.
func LookupSignal(signal *dbus.Signal) (Signal, error) {
switch signal.Name {
case InterfaceDbusmenu + "." + "ItemsPropertiesUpdated":
v0, ok := signal.Body[0].([]struct {
V0 int32
V1 map[string]dbus.Variant
})
if !ok {
return nil, fmt.Errorf("prop .UpdatedProps is %T, not []struct {V0 int32;V1 map[string]dbus.Variant}", signal.Body[0])
}
v1, ok := signal.Body[1].([]struct {
V0 int32
V1 []string
})
if !ok {
return nil, fmt.Errorf("prop .RemovedProps is %T, not []struct {V0 int32;V1 []string}", signal.Body[1])
}
return &Dbusmenu_ItemsPropertiesUpdatedSignal{
sender: signal.Sender,
Path: signal.Path,
Body: &Dbusmenu_ItemsPropertiesUpdatedSignalBody{
UpdatedProps: v0,
RemovedProps: v1,
},
}, nil
case InterfaceDbusmenu + "." + "LayoutUpdated":
v0, ok := signal.Body[0].(uint32)
if !ok {
return nil, fmt.Errorf("prop .Revision is %T, not uint32", signal.Body[0])
}
v1, ok := signal.Body[1].(int32)
if !ok {
return nil, fmt.Errorf("prop .Parent is %T, not int32", signal.Body[1])
}
return &Dbusmenu_LayoutUpdatedSignal{
sender: signal.Sender,
Path: signal.Path,
Body: &Dbusmenu_LayoutUpdatedSignalBody{
Revision: v0,
Parent: v1,
},
}, nil
case InterfaceDbusmenu + "." + "ItemActivationRequested":
v0, ok := signal.Body[0].(int32)
if !ok {
return nil, fmt.Errorf("prop .Id is %T, not int32", signal.Body[0])
}
v1, ok := signal.Body[1].(uint32)
if !ok {
return nil, fmt.Errorf("prop .Timestamp is %T, not uint32", signal.Body[1])
}
return &Dbusmenu_ItemActivationRequestedSignal{
sender: signal.Sender,
Path: signal.Path,
Body: &Dbusmenu_ItemActivationRequestedSignalBody{
Id: v0,
Timestamp: v1,
},
}, nil
default:
return nil, ErrUnknownSignal
}
}
// AddMatchSignal registers a match rule for the given signal,
// opts are appended to the automatically generated signal's rules.
func AddMatchSignal(conn *dbus.Conn, s Signal, opts ...dbus.MatchOption) error {
return conn.AddMatchSignal(append([]dbus.MatchOption{
dbus.WithMatchInterface(s.Interface()),
dbus.WithMatchMember(s.Name()),
}, opts...)...)
}
// RemoveMatchSignal unregisters the previously registered subscription.
func RemoveMatchSignal(conn *dbus.Conn, s Signal, opts ...dbus.MatchOption) error {
return conn.RemoveMatchSignal(append([]dbus.MatchOption{
dbus.WithMatchInterface(s.Interface()),
dbus.WithMatchMember(s.Name()),
}, opts...)...)
}
// Interface name constants.
const (
InterfaceDbusmenu = "com.canonical.dbusmenu"
)
// Dbusmenuer is com.canonical.dbusmenu interface.
type Dbusmenuer interface {
// GetLayout is com.canonical.dbusmenu.GetLayout method.
GetLayout(parentId int32, recursionDepth int32, propertyNames []string) (revision uint32, layout struct {
V0 int32
V1 map[string]dbus.Variant
V2 []dbus.Variant
}, err *dbus.Error)
// GetGroupProperties is com.canonical.dbusmenu.GetGroupProperties method.
GetGroupProperties(ids []int32, propertyNames []string) (properties []struct {
V0 int32
V1 map[string]dbus.Variant
}, err *dbus.Error)
// GetProperty is com.canonical.dbusmenu.GetProperty method.
GetProperty(id int32, name string) (value dbus.Variant, err *dbus.Error)
// Event is com.canonical.dbusmenu.Event method.
Event(id int32, eventId string, data dbus.Variant, timestamp uint32) (err *dbus.Error)
// EventGroup is com.canonical.dbusmenu.EventGroup method.
EventGroup(events []struct {
V0 int32
V1 string
V2 dbus.Variant
V3 uint32
}) (idErrors []int32, err *dbus.Error)
// AboutToShow is com.canonical.dbusmenu.AboutToShow method.
AboutToShow(id int32) (needUpdate bool, err *dbus.Error)
// AboutToShowGroup is com.canonical.dbusmenu.AboutToShowGroup method.
AboutToShowGroup(ids []int32) (updatesNeeded []int32, idErrors []int32, err *dbus.Error)
}
// ExportDbusmenu exports the given object that implements com.canonical.dbusmenu on the bus.
func ExportDbusmenu(conn *dbus.Conn, path dbus.ObjectPath, v Dbusmenuer) error {
return conn.ExportSubtreeMethodTable(map[string]interface{}{
"GetLayout": v.GetLayout,
"GetGroupProperties": v.GetGroupProperties,
"GetProperty": v.GetProperty,
"Event": v.Event,
"EventGroup": v.EventGroup,
"AboutToShow": v.AboutToShow,
"AboutToShowGroup": v.AboutToShowGroup,
}, path, InterfaceDbusmenu)
}
// UnexportDbusmenu unexports com.canonical.dbusmenu interface on the named path.
func UnexportDbusmenu(conn *dbus.Conn, path dbus.ObjectPath) error {
return conn.Export(nil, path, InterfaceDbusmenu)
}
// UnimplementedDbusmenu can be embedded to have forward compatible server implementations.
type UnimplementedDbusmenu struct{}
func (*UnimplementedDbusmenu) iface() string {
return InterfaceDbusmenu
}
func (*UnimplementedDbusmenu) GetLayout(parentId int32, recursionDepth int32, propertyNames []string) (revision uint32, layout struct {
V0 int32
V1 map[string]dbus.Variant
V2 []dbus.Variant
}, err *dbus.Error) {
err = &dbus.ErrMsgUnknownMethod
return
}
func (*UnimplementedDbusmenu) GetGroupProperties(ids []int32, propertyNames []string) (properties []struct {
V0 int32
V1 map[string]dbus.Variant
}, err *dbus.Error) {
err = &dbus.ErrMsgUnknownMethod
return
}
func (*UnimplementedDbusmenu) GetProperty(id int32, name string) (value dbus.Variant, err *dbus.Error) {
err = &dbus.ErrMsgUnknownMethod
return
}
func (*UnimplementedDbusmenu) Event(id int32, eventId string, data dbus.Variant, timestamp uint32) (err *dbus.Error) {
err = &dbus.ErrMsgUnknownMethod
return
}
func (*UnimplementedDbusmenu) EventGroup(events []struct {
V0 int32
V1 string
V2 dbus.Variant
V3 uint32
}) (idErrors []int32, err *dbus.Error) {
err = &dbus.ErrMsgUnknownMethod
return
}
func (*UnimplementedDbusmenu) AboutToShow(id int32) (needUpdate bool, err *dbus.Error) {
err = &dbus.ErrMsgUnknownMethod
return
}
func (*UnimplementedDbusmenu) AboutToShowGroup(ids []int32) (updatesNeeded []int32, idErrors []int32, err *dbus.Error) {
err = &dbus.ErrMsgUnknownMethod
return
}
// NewDbusmenu creates and allocates com.canonical.dbusmenu.
func NewDbusmenu(object dbus.BusObject) *Dbusmenu {
return &Dbusmenu{object}
}
// Dbusmenu implements com.canonical.dbusmenu D-Bus interface.
type Dbusmenu struct {
object dbus.BusObject
}
// GetLayout calls com.canonical.dbusmenu.GetLayout method.
func (o *Dbusmenu) GetLayout(ctx context.Context, parentId int32, recursionDepth int32, propertyNames []string) (revision uint32, layout struct {
V0 int32
V1 map[string]dbus.Variant
V2 []dbus.Variant
}, err error) {
err = o.object.CallWithContext(ctx, InterfaceDbusmenu+".GetLayout", 0, parentId, recursionDepth, propertyNames).Store(&revision, &layout)
return
}
// GetGroupProperties calls com.canonical.dbusmenu.GetGroupProperties method.
func (o *Dbusmenu) GetGroupProperties(ctx context.Context, ids []int32, propertyNames []string) (properties []struct {
V0 int32
V1 map[string]dbus.Variant
}, err error) {
err = o.object.CallWithContext(ctx, InterfaceDbusmenu+".GetGroupProperties", 0, ids, propertyNames).Store(&properties)
return
}
// GetProperty calls com.canonical.dbusmenu.GetProperty method.
func (o *Dbusmenu) GetProperty(ctx context.Context, id int32, name string) (value dbus.Variant, err error) {
err = o.object.CallWithContext(ctx, InterfaceDbusmenu+".GetProperty", 0, id, name).Store(&value)
return
}
// Event calls com.canonical.dbusmenu.Event method.
func (o *Dbusmenu) Event(ctx context.Context, id int32, eventId string, data dbus.Variant, timestamp uint32) (err error) {
err = o.object.CallWithContext(ctx, InterfaceDbusmenu+".Event", 0, id, eventId, data, timestamp).Store()
return
}
// EventGroup calls com.canonical.dbusmenu.EventGroup method.
func (o *Dbusmenu) EventGroup(ctx context.Context, events []struct {
V0 int32
V1 string
V2 dbus.Variant
V3 uint32
}) (idErrors []int32, err error) {
err = o.object.CallWithContext(ctx, InterfaceDbusmenu+".EventGroup", 0, events).Store(&idErrors)
return
}
// AboutToShow calls com.canonical.dbusmenu.AboutToShow method.
func (o *Dbusmenu) AboutToShow(ctx context.Context, id int32) (needUpdate bool, err error) {
err = o.object.CallWithContext(ctx, InterfaceDbusmenu+".AboutToShow", 0, id).Store(&needUpdate)
return
}
// AboutToShowGroup calls com.canonical.dbusmenu.AboutToShowGroup method.
func (o *Dbusmenu) AboutToShowGroup(ctx context.Context, ids []int32) (updatesNeeded []int32, idErrors []int32, err error) {
err = o.object.CallWithContext(ctx, InterfaceDbusmenu+".AboutToShowGroup", 0, ids).Store(&updatesNeeded, &idErrors)
return
}
// GetVersion gets com.canonical.dbusmenu.Version property.
func (o *Dbusmenu) GetVersion(ctx context.Context) (version uint32, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceDbusmenu, "Version").Store(&version)
return
}
// GetTextDirection gets com.canonical.dbusmenu.TextDirection property.
func (o *Dbusmenu) GetTextDirection(ctx context.Context) (textDirection string, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceDbusmenu, "TextDirection").Store(&textDirection)
return
}
// GetStatus gets com.canonical.dbusmenu.Status property.
func (o *Dbusmenu) GetStatus(ctx context.Context) (status string, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceDbusmenu, "Status").Store(&status)
return
}
// GetIconThemePath gets com.canonical.dbusmenu.IconThemePath property.
func (o *Dbusmenu) GetIconThemePath(ctx context.Context) (iconThemePath []string, err error) {
err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceDbusmenu, "IconThemePath").Store(&iconThemePath)
return
}
// Dbusmenu_ItemsPropertiesUpdatedSignal represents com.canonical.dbusmenu.ItemsPropertiesUpdated signal.
type Dbusmenu_ItemsPropertiesUpdatedSignal struct {
sender string
Path dbus.ObjectPath
Body *Dbusmenu_ItemsPropertiesUpdatedSignalBody
}
// Name returns the signal's name.
func (s *Dbusmenu_ItemsPropertiesUpdatedSignal) Name() string {
return "ItemsPropertiesUpdated"
}
// Interface returns the signal's interface.
func (s *Dbusmenu_ItemsPropertiesUpdatedSignal) Interface() string {
return InterfaceDbusmenu
}
// Sender returns the signal's sender unique name.
func (s *Dbusmenu_ItemsPropertiesUpdatedSignal) Sender() string {
return s.sender
}
func (s *Dbusmenu_ItemsPropertiesUpdatedSignal) path() dbus.ObjectPath {
return s.Path
}
func (s *Dbusmenu_ItemsPropertiesUpdatedSignal) values() []interface{} {
return []interface{}{s.Body.UpdatedProps, s.Body.RemovedProps}
}
// Dbusmenu_ItemsPropertiesUpdatedSignalBody is body container.
type Dbusmenu_ItemsPropertiesUpdatedSignalBody struct {
UpdatedProps []struct {
V0 int32
V1 map[string]dbus.Variant
}
RemovedProps []struct {
V0 int32
V1 []string
}
}
// Dbusmenu_LayoutUpdatedSignal represents com.canonical.dbusmenu.LayoutUpdated signal.
type Dbusmenu_LayoutUpdatedSignal struct {
sender string
Path dbus.ObjectPath
Body *Dbusmenu_LayoutUpdatedSignalBody
}
// Name returns the signal's name.
func (s *Dbusmenu_LayoutUpdatedSignal) Name() string {
return "LayoutUpdated"
}
// Interface returns the signal's interface.
func (s *Dbusmenu_LayoutUpdatedSignal) Interface() string {
return InterfaceDbusmenu
}
// Sender returns the signal's sender unique name.
func (s *Dbusmenu_LayoutUpdatedSignal) Sender() string {
return s.sender
}
func (s *Dbusmenu_LayoutUpdatedSignal) path() dbus.ObjectPath {
return s.Path
}
func (s *Dbusmenu_LayoutUpdatedSignal) values() []interface{} {
return []interface{}{s.Body.Revision, s.Body.Parent}
}
// Dbusmenu_LayoutUpdatedSignalBody is body container.
type Dbusmenu_LayoutUpdatedSignalBody struct {
Revision uint32
Parent int32
}
// Dbusmenu_ItemActivationRequestedSignal represents com.canonical.dbusmenu.ItemActivationRequested signal.
type Dbusmenu_ItemActivationRequestedSignal struct {
sender string
Path dbus.ObjectPath
Body *Dbusmenu_ItemActivationRequestedSignalBody
}
// Name returns the signal's name.
func (s *Dbusmenu_ItemActivationRequestedSignal) Name() string {
return "ItemActivationRequested"
}
// Interface returns the signal's interface.
func (s *Dbusmenu_ItemActivationRequestedSignal) Interface() string {
return InterfaceDbusmenu
}
// Sender returns the signal's sender unique name.
func (s *Dbusmenu_ItemActivationRequestedSignal) Sender() string {
return s.sender
}
func (s *Dbusmenu_ItemActivationRequestedSignal) path() dbus.ObjectPath {
return s.Path
}
func (s *Dbusmenu_ItemActivationRequestedSignal) values() []interface{} {
return []interface{}{s.Body.Id, s.Body.Timestamp}
}
// Dbusmenu_ItemActivationRequestedSignalBody is body container.
type Dbusmenu_ItemActivationRequestedSignalBody struct {
Id int32
Timestamp uint32
}
View File
File diff suppressed because it is too large Load Diff
+17
View File
@@ -18,3 +18,20 @@ func pngToImage(data []byte) (*image.RGBA, error) {
draw.Draw(rgba, bounds, img, bounds.Min, draw.Src)
return rgba, nil
}
func ToARGB(img *image.RGBA) (int, int, []byte) {
w, h := img.Bounds().Dx(), img.Bounds().Dy()
data := make([]byte, w*h*4)
i := 0
for y := 0; y < h; y++ {
for x := 0; x < w; x++ {
r, g, b, a := img.At(x, y).RGBA()
data[i] = byte(a)
data[i+1] = byte(r)
data[i+2] = byte(g)
data[i+3] = byte(b)
i += 4
}
}
return w, h, data
}
+7 -2
View File
@@ -72,6 +72,7 @@ func newMenuItem(label string) *MenuItem {
func newMenuItemSeparator() *MenuItem {
result := &MenuItem{
id: uint(atomic.AddUintptr(&menuItemID, 1)),
itemType: separator,
}
return result
@@ -199,7 +200,9 @@ func (m *MenuItem) handleClick() {
if m.itemType == checkbox {
m.checked = !m.checked
ctx.withChecked(m.checked)
m.impl.setChecked(m.checked)
if m.impl != nil {
m.impl.setChecked(m.checked)
}
}
if m.itemType == radio {
for _, member := range m.radioGroupMembers {
@@ -210,7 +213,9 @@ func (m *MenuItem) handleClick() {
}
m.checked = true
ctx.withChecked(true)
m.impl.setChecked(true)
if m.impl != nil {
m.impl.setChecked(true)
}
}
if m.callback != nil {
go m.callback(ctx)
File diff suppressed because it is too large Load Diff