Skip to content

Commit

Permalink
internal/tray: change the text and behavior of the self tray item a b…
Browse files Browse the repository at this point in the history
…it (#95)

* internal/tray: refactor self item handling

* meta: update some dependencies

* meta: fix a dependency version

* internal/tray: adjust text for self menu item

* internal/tray, internal/tsutil: refactor code for determining the current machine's address

* internal/ui: copy the current machine's address to the clipboard when the menu item is clicked

* internal/ui: notify when the address is copied to the clipboard

* internal/tray: use `DNSOrQuoteHostname()` instead of the raw hostname

* meta: update some dependencies

* internal/ui: attempt to separate clipboard handling from the window

Unfortuantely, it doesn't work when the window isn't shown for some
reason.

* meta: update some dependencies

* meta: update some dependencies

* internal/tsutil: fix some API breakage

* internal/ui: fix a missing button

* cmd/trayscale: disable clipboard notification for self IP address when window is closed

* meta: update some versions in the CI

* meta: update some dependencies
  • Loading branch information
DeedleFake authored Mar 17, 2024
1 parent 6e09d48 commit 5edd774
Show file tree
Hide file tree
Showing 10 changed files with 115 additions and 81 deletions.
9 changes: 5 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
name: Lint and Test

env:
image: ubuntu:23.10
dependencies: libgtk-4-dev libadwaita-1-dev
go-version: 1.21.0
go-version: 1.22.0

on:
workflow_dispatch:
Expand All @@ -16,7 +17,7 @@ jobs:
name: go vet
runs-on: ubuntu-latest
container:
image: ubuntu:23.04
image: ${{ ubuntu }}
steps:
- name: Checkout
uses: actions/checkout@v3
Expand All @@ -35,7 +36,7 @@ jobs:
name: staticcheck
runs-on: ubuntu-latest
container:
image: ubuntu:23.04
image: ${{ ubuntu }}
steps:
- name: Checkout
uses: actions/checkout@v3
Expand All @@ -56,7 +57,7 @@ jobs:
name: go test
runs-on: ubuntu-latest
container:
image: ubuntu:23.04
image: ${{ ubuntu }}
steps:
- name: Checkout
uses: actions/checkout@v3
Expand Down
Binary file modified cmd/trayscale/default.pgo
Binary file not shown.
18 changes: 9 additions & 9 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ require (
github.com/diamondburned/gotk4-adwaita/pkg v0.0.0-20240107232253-5f283b5d35bc
github.com/diamondburned/gotk4/pkg v0.2.2
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf
golang.org/x/net v0.21.0
golang.org/x/net v0.22.0
honnef.co/go/tools v0.4.7
tailscale.com v1.60.1
tailscale.com v1.62.0
)

require (
Expand All @@ -25,12 +25,12 @@ require (
github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/nftables v0.1.1-0.20230115205135-9aa6fdf5a28c // indirect
github.com/google/nftables v0.2.0 // indirect
github.com/hdevalence/ed25519consensus v0.2.0 // indirect
github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 // indirect
github.com/jsimonetti/rtnetlink v1.4.1 // indirect
github.com/mdlayher/netlink v1.7.2 // indirect
github.com/mdlayher/socket v0.5.0 // indirect
github.com/mdlayher/socket v0.5.1 // indirect
github.com/mitchellh/go-ps v1.0.0 // indirect
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect
github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 // indirect
Expand All @@ -43,15 +43,15 @@ require (
go4.org/mem v0.0.0-20220726221520-4f986261bf13 // indirect
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
go4.org/unsafe/assume-no-moving-gc v0.0.0-20231121144256-b99613f794b6 // indirect
golang.org/x/crypto v0.20.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
golang.org/x/exp/typeparams v0.0.0-20240222234643-814bf88cf225 // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f // indirect
golang.org/x/mod v0.16.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.18.0 // indirect
golang.org/x/tools v0.19.0 // indirect
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
nhooyr.io/websocket v1.8.10 // indirect
)
36 changes: 18 additions & 18 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/nftables v0.1.1-0.20230115205135-9aa6fdf5a28c h1:06RMfw+TMMHtRuUOroMeatRCCgSMWXCJQeABvHU69YQ=
github.com/google/nftables v0.1.1-0.20230115205135-9aa6fdf5a28c/go.mod h1:BVIYo3cdnT4qSylnYqcd5YtmXhr51cJPGtnLBe/uLBU=
github.com/google/nftables v0.2.0 h1:PbJwaBmbVLzpeldoeUKGkE2RjstrjPKMl6oLrfEJ6/8=
github.com/google/nftables v0.2.0/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4=
github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU=
github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo=
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s=
Expand All @@ -51,8 +51,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI=
github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI=
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
Expand Down Expand Up @@ -80,16 +80,16 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBs
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
go4.org/unsafe/assume-no-moving-gc v0.0.0-20231121144256-b99613f794b6 h1:lGdhQUN/cnWdSH3291CUuxSEqc+AsGTiDxPP3r2J0l4=
go4.org/unsafe/assume-no-moving-gc v0.0.0-20231121144256-b99613f794b6/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E=
golang.org/x/crypto v0.20.0 h1:jmAMJJZXr5KiCw05dfYK9QnqaqKLYXijU23lsEdcQqg=
golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/exp/typeparams v0.0.0-20240222234643-814bf88cf225 h1:BzKNaIRXh1bD+1557OcFIHlpYBiVbK4zEyn8zBHi1SE=
golang.org/x/exp/typeparams v0.0.0-20240222234643-814bf88cf225/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f h1:phY1HzDcf18Aq9A8KkmRtY9WvOFIxN8wgfvy6Zm1DV8=
golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
Expand All @@ -98,14 +98,14 @@ golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.1-0.20230131160137-e7d7f63158de/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE=
golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI=
honnef.co/go/tools v0.4.7 h1:9MDAWxMoSnB6QoSqiVr7P5mtkT9pOc1kSxchzPCnqJs=
Expand All @@ -116,5 +116,5 @@ nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q=
nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c=
software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k=
software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI=
tailscale.com v1.60.1 h1:RNNIuSWE0HeUS7c5i7rAZTCmoDzsAxy5yc5LF4K7pFs=
tailscale.com v1.60.1/go.mod h1:qgxvJUlfOWeURBEORdcX4EhoCduFHeBW3FNIZBpmIHY=
tailscale.com v1.62.0 h1:iI1fPDNXXETMbVEatos7xSR6Bv6aCuonD7B1X3glnPE=
tailscale.com v1.62.0/go.mod h1:cC0b0vYCoSDOLufJX5J5zDUrvV3lYwOLqlt9NW8y4cY=
45 changes: 21 additions & 24 deletions internal/tray/tray.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ func (t *Tray) ShowChan() <-chan struct{} {
return t.showItem.ClickedCh
}

func (t *Tray) SelfNodeChan() <-chan struct{} {
return t.selfNodeItem.ClickedCh
}

func (t *Tray) setOnlineStatus(online bool) {
systray.SetIcon(statusIcon(online))
}
Expand All @@ -67,31 +71,12 @@ func (t *Tray) Update(s tsutil.Status, previousOnlineStatus bool) {
t.setOnlineStatus(s.Online())
}

var title string
if s.Status != nil && s.Status.Self != nil {
// A naive approach to get first available TS IP.
// Ways to refine: sort and get the "Less"er or prefer
// first IPv4 in the list.
var ipInfo string
if len(s.Status.Self.TailscaleIPs) > 0 {
ipInfo = fmt.Sprintf(
" (%s)",
s.Status.Self.TailscaleIPs[0].String(),
)
}

title = fmt.Sprintf(
"This device: %s%s",
s.Status.Self.HostName,
ipInfo,
)
}

if title == "" {
t.selfNodeItem.Hide()
selfTitle, connected := selfTitle(s)
t.selfNodeItem.SetTitle(fmt.Sprintf("This machine: %v", selfTitle))
if connected {
t.selfNodeItem.Enable()
} else {
t.selfNodeItem.SetTitle(title)
t.selfNodeItem.Show()
t.selfNodeItem.Disable()
}
}

Expand All @@ -116,3 +101,15 @@ func Stop() {
default:
}
}

func selfTitle(s tsutil.Status) (string, bool) {
addr, ok := s.SelfAddr()
if !ok {
if len(s.Status.Self.TailscaleIPs) == 0 {
return "Address unknown", false
}
return "Not connected", false
}

return fmt.Sprintf("%v (%v)", tsutil.DNSOrQuoteHostname(s.Status, s.Status.Self), addr), true
}
16 changes: 16 additions & 0 deletions internal/tsutil/poller.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package tsutil
import (
"context"
"log/slog"
"net/netip"
"os/user"
"slices"
"sync"
"time"

Expand Down Expand Up @@ -181,3 +183,17 @@ func (s Status) OperatorIsCurrent() bool {

return s.Prefs.OperatorUser == current.Username
}

func (s Status) SelfAddr() (netip.Addr, bool) {
if s.Status == nil {
return netip.Addr{}, false
}
if s.Status.Self == nil {
return netip.Addr{}, false
}
if len(s.Status.Self.TailscaleIPs) == 0 {
return netip.Addr{}, false
}

return slices.MinFunc(s.Status.Self.TailscaleIPs, netip.Addr.Compare), true
}
31 changes: 24 additions & 7 deletions internal/ui/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,14 @@ func (a *App) showAbout() {
a.app.AddWindow(&dialog.Window.Window)
}

func (a *App) notify(status bool) {
body := "Tailscale is not connected."
if status {
body = "Tailscale is connected."
}
func (a *App) clip(v *glib.Value) {
gdk.DisplayGetDefault().Clipboard().Set(v)
}

func (a *App) notify(title, body string) {
icon, iconerr := gio.NewIconForString(appID)

n := gio.NewNotification("Tailscale Status")
n := gio.NewNotification(title)
n.SetBody(body)
if iconerr == nil {
n.SetIcon(icon)
Expand Down Expand Up @@ -169,7 +168,12 @@ func (a *App) update(s tsutil.Status) {
a.tray.Update(s, a.online)
if a.online != online {
a.online = online
a.notify(online) // TODO: Notify on startup if not connected?

body := "Tailscale is not connected."
if online {
body = "Tailscale is connected."
}
a.notify("Tailscale Status", body) // TODO: Notify on startup if not connected?
}
if a.win == nil {
return
Expand Down Expand Up @@ -340,14 +344,27 @@ func (a *App) initTray(ctx context.Context) {
select {
case <-ctx.Done():
return

case <-a.tray.ShowChan():
glib.IdleAdd(func() {
if a.app != nil {
a.app.Activate()
}
})

case <-a.tray.QuitChan():
a.Quit()

case <-a.tray.SelfNodeChan():
s := <-a.poller.Get()
addr, ok := s.SelfAddr()
if !ok {
continue
}
a.clip(glib.NewValue(addr.String()))
if a.win != nil {
a.notify("Trayscale", "Copied address to clipboard")
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion internal/ui/page.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func (a *App) newPeerPage(status tsutil.Status, peer *ipnstate.PeerStatus) *peer
row.c.SetHasFrame(false)
row.c.SetTooltipText("Copy to Clipboard")
row.c.ConnectClicked(func() {
row.c.Clipboard().Set(glib.NewValue(row.ip.String()))
a.clip(glib.NewValue(row.ip.String()))
a.toast("Copied to clipboard")
})

Expand Down
15 changes: 8 additions & 7 deletions internal/ui/peerpage.ui
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
</child>
<child>
<object class="AdwActionRow" id="AcceptRoutesRow">
<property name="activatable-widget">AcceptRoutesSwitch</property>
<property name="title">Accept routes</property>
<child>
<object class="GtkSwitch" id="AcceptRoutesSwitch">
Expand Down Expand Up @@ -85,6 +84,12 @@
</child>
<child>
<object class="AdwPreferencesGroup" id="NetCheckGroup">
<property name="header-suffix">
<object class="GtkButton" id="NetCheckButton">
<property name="has-frame">False</property>
<property name="icon-name">view-refresh-symbolic</property>
</object>
</property>
<property name="title">Network Check</property>
<child>
<object class="AdwActionRow" id="LastNetCheckRow">
Expand Down Expand Up @@ -262,15 +267,11 @@
</object>
</child>
</object>
<object class="GtkButton" id="NetCheckButton">
<property name="has-frame">False</property>
<property name="icon-name">view-refresh-symbolic</property>
<object class="GtkDropTarget" id="DropTarget">
<property name="actions">copy</property>
</object>
<object class="GtkButton" id="AdvertiseRouteButton">
<property name="has-frame">False</property>
<property name="icon-name">list-add-symbolic</property>
</object>
<object class="GtkDropTarget" id="DropTarget">
<property name="actions">copy</property>
</object>
</interface>
Loading

0 comments on commit 5edd774

Please sign in to comment.