From 4b230bd4a05f391483ee1f9f39827086fe172fac Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Fri, 12 May 2023 22:14:48 +0100 Subject: [PATCH 01/27] Listen for, and respond to, icon updates --- modules/systray/main.go | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/modules/systray/main.go b/modules/systray/main.go index 643b1058..502af190 100644 --- a/modules/systray/main.go +++ b/modules/systray/main.go @@ -54,6 +54,7 @@ var trayMeta = fynedesk.ModuleMetadata{ type tray struct { conn *dbus.Conn menu *menu.Dbusmenu + ni *notifier.StatusNotifierItem box *fyne.Container nodes map[dbus.Sender]*widget.Button @@ -116,6 +117,7 @@ func NewTray() fynedesk.Module { } watchErr := t.conn.AddMatchSignal(dbus.WithMatchInterface("org.freedesktop.DBus"), dbus.WithMatchObjectPath("/org/freedesktop/DBus")) + _ = t.conn.AddMatchSignal(dbus.WithMatchInterface("org.kde.StatusNotifierItem")) if watchErr != nil { fyne.LogError("Failed to monitor systray name loss", watchErr) return t @@ -125,18 +127,36 @@ func NewTray() fynedesk.Module { t.conn.Signal(c) go func() { for v := range c { - if v.Name != "org.freedesktop.DBus.NameOwnerChanged" { - log.Println("Also", v.Name) - continue - } + switch v.Name { + case "org.freedesktop.DBus.NameOwnerChanged": + name := v.Body[0] + newOwner := v.Body[2] + if newOwner == "" { + if item, ok := t.nodes[dbus.Sender(name.(string))]; ok { + t.box.Remove(item) + t.box.Refresh() + } + } + case "org.kde.StatusNotifierItem.NewIcon": + ic, err := t.ni.GetIconPixmap(t.conn.Context()) + if err != nil { + fyne.LogError("Failed to load replacement systray image", err) + break + } + + img := pixelsToImage(ic[0]) + w := &bytes.Buffer{} + _ = png.Encode(w, img) - name := v.Body[0] - newOwner := v.Body[2] - if newOwner == "" { - if item, ok := t.nodes[dbus.Sender(name.(string))]; ok { - t.box.Remove(item) - t.box.Refresh() + ico, ok := t.nodes[dbus.Sender(v.Sender)] + if ok { + unique := strconv.Itoa(resourceID) + ".png" + resourceID++ + ico.SetIcon(fyne.NewStaticResource(unique, w.Bytes())) } + default: + log.Println("Also", v.Name) + continue } } }() @@ -149,6 +169,7 @@ func (t *tray) Destroy() { func (t *tray) RegisterStatusNotifierItem(service string, sender dbus.Sender) (err *dbus.Error) { ni := notifier.NewStatusNotifierItem(t.conn.Object(string(sender), dbus.ObjectPath(service))) + t.ni = ni ico, ok := t.nodes[sender] if !ok { From 03660fb7b398168d53838a675634022a7fd6d589 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Fri, 12 May 2023 22:21:53 +0100 Subject: [PATCH 02/27] Remove duplicate code --- modules/systray/main.go | 79 ++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 44 deletions(-) diff --git a/modules/systray/main.go b/modules/systray/main.go index 502af190..3f01deb7 100644 --- a/modules/systray/main.go +++ b/modules/systray/main.go @@ -18,6 +18,7 @@ import ( "strconv" "time" + "fyshos.com/fynedesk/internal/icon" "github.com/godbus/dbus/v5" "github.com/godbus/dbus/v5/introspect" "github.com/godbus/dbus/v5/prop" @@ -28,7 +29,6 @@ import ( "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" "fyshos.com/fynedesk" - "fyshos.com/fynedesk/internal/icon" "fyshos.com/fynedesk/modules/systray/generated/menu" "fyshos.com/fynedesk/modules/systray/generated/notifier" "fyshos.com/fynedesk/modules/systray/generated/watcher" @@ -138,21 +138,9 @@ func NewTray() fynedesk.Module { } } case "org.kde.StatusNotifierItem.NewIcon": - ic, err := t.ni.GetIconPixmap(t.conn.Context()) - if err != nil { - fyne.LogError("Failed to load replacement systray image", err) - break - } - - img := pixelsToImage(ic[0]) - w := &bytes.Buffer{} - _ = png.Encode(w, img) - ico, ok := t.nodes[dbus.Sender(v.Sender)] if ok { - unique := strconv.Itoa(resourceID) + ".png" - resourceID++ - ico.SetIcon(fyne.NewStaticResource(unique, w.Bytes())) + t.updateIcon(ico, t.ni) } default: log.Println("Also", v.Name) @@ -169,7 +157,6 @@ func (t *tray) Destroy() { func (t *tray) RegisterStatusNotifierItem(service string, sender dbus.Sender) (err *dbus.Error) { ni := notifier.NewStatusNotifierItem(t.conn.Object(string(sender), dbus.ObjectPath(service))) - t.ni = ni ico, ok := t.nodes[sender] if !ok { @@ -189,35 +176,8 @@ func (t *tray) RegisterStatusNotifierItem(service string, sender dbus.Sender) (e t.box.Add(ico) } - ic, _ := ni.GetIconPixmap(t.conn.Context()) - if len(ic) > 0 { - img := pixelsToImage(ic[0]) - unique := strconv.Itoa(resourceID) + ".png" - resourceID++ - w := &bytes.Buffer{} - _ = png.Encode(w, img) - ico.SetIcon(fyne.NewStaticResource(unique, w.Bytes())) - } else { - name, _ := ni.GetIconName(t.conn.Context()) - path, _ := ni.GetIconThemePath(t.conn.Context()) - fullPath := "" - if path != "" { - fullPath = filepath.Join(path, name+".png") - if _, err := os.Stat(fullPath); err != nil { // not found, search instead - fullPath = icon.FdoLookupIconPathInTheme("64", filepath.Join(path, "hicolor"), "", name) - } - } else { - fullPath = icon.FdoLookupIconPath("", 64, name) - } - img, err := ioutil.ReadFile(fullPath) - if err != nil { - fyne.LogError("Failed to load status icon", err) - ico.SetIcon(wmtheme.BrokenImageIcon) - } else { - ico.SetIcon(fyne.NewStaticResource(name, img)) - } - } - + t.ni = ni + t.updateIcon(ico, ni) ico.Refresh() t.box.Refresh() @@ -337,6 +297,37 @@ func (t *tray) showMenu(sender string, name dbus.ObjectPath, from fyne.CanvasObj fynedesk.Instance().WindowManager().ShowOverlay(w, size, pos) } +func (t *tray) updateIcon(ico *widget.Button, ni *notifier.StatusNotifierItem) { + ic, _ := ni.GetIconPixmap(t.conn.Context()) + if len(ic) > 0 { + img := pixelsToImage(ic[0]) + unique := strconv.Itoa(resourceID) + ".png" + resourceID++ + w := &bytes.Buffer{} + _ = png.Encode(w, img) + ico.SetIcon(fyne.NewStaticResource(unique, w.Bytes())) + } else { + name, _ := ni.GetIconName(t.conn.Context()) + path, _ := ni.GetIconThemePath(t.conn.Context()) + fullPath := "" + if path != "" { + fullPath = filepath.Join(path, name+".png") + if _, err := os.Stat(fullPath); err != nil { // not found, search instead + fullPath = icon.FdoLookupIconPathInTheme("64", filepath.Join(path, "hicolor"), "", name) + } + } else { + fullPath = icon.FdoLookupIconPath("", 64, name) + } + img, err := ioutil.ReadFile(fullPath) + if err != nil { + fyne.LogError("Failed to load status icon", err) + ico.SetIcon(wmtheme.BrokenImageIcon) + } else { + ico.SetIcon(fyne.NewStaticResource(name, img)) + } + } +} + func createPropSpec() map[string]map[string]*prop.Prop { return map[string]map[string]*prop.Prop{ "org.kde.StatusNotifierWatcher": { From c5cc0cf6d35496c38b583e8aab7e19dbac8accfa Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Fri, 12 May 2023 22:42:35 +0100 Subject: [PATCH 03/27] Store the notifier item per icon --- modules/systray/main.go | 54 +++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/modules/systray/main.go b/modules/systray/main.go index 3f01deb7..5552925b 100644 --- a/modules/systray/main.go +++ b/modules/systray/main.go @@ -18,21 +18,22 @@ import ( "strconv" "time" - "fyshos.com/fynedesk/internal/icon" "github.com/godbus/dbus/v5" "github.com/godbus/dbus/v5/introspect" "github.com/godbus/dbus/v5/prop" - "fyne.io/fyne/v2" - "fyne.io/fyne/v2/container" - deskDriver "fyne.io/fyne/v2/driver/desktop" - "fyne.io/fyne/v2/theme" - "fyne.io/fyne/v2/widget" "fyshos.com/fynedesk" + "fyshos.com/fynedesk/internal/icon" "fyshos.com/fynedesk/modules/systray/generated/menu" "fyshos.com/fynedesk/modules/systray/generated/notifier" "fyshos.com/fynedesk/modules/systray/generated/watcher" wmtheme "fyshos.com/fynedesk/theme" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + deskDriver "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) const ( @@ -54,17 +55,21 @@ var trayMeta = fynedesk.ModuleMetadata{ type tray struct { conn *dbus.Conn menu *menu.Dbusmenu - ni *notifier.StatusNotifierItem box *fyne.Container - nodes map[dbus.Sender]*widget.Button + nodes map[dbus.Sender]*node +} + +type node struct { + ico *widget.Button + ni *notifier.StatusNotifierItem } // NewTray creates a new module that will show a system tray in the status area func NewTray() fynedesk.Module { iconSize := wmtheme.NarrowBarWidth grid := container.New(collapsingGridWrap(fyne.NewSize(iconSize, iconSize))) - t := &tray{box: grid, nodes: make(map[dbus.Sender]*widget.Button)} + t := &tray{box: grid, nodes: make(map[dbus.Sender]*node)} conn, _ := dbus.ConnectSessionBus() t.conn = conn @@ -133,14 +138,14 @@ func NewTray() fynedesk.Module { newOwner := v.Body[2] if newOwner == "" { if item, ok := t.nodes[dbus.Sender(name.(string))]; ok { - t.box.Remove(item) + t.box.Remove(item.ico) t.box.Refresh() } } case "org.kde.StatusNotifierItem.NewIcon": - ico, ok := t.nodes[dbus.Sender(v.Sender)] + item, ok := t.nodes[dbus.Sender(v.Sender)] if ok { - t.updateIcon(ico, t.ni) + t.updateIcon(item) } default: log.Println("Also", v.Name) @@ -158,8 +163,9 @@ func (t *tray) Destroy() { func (t *tray) RegisterStatusNotifierItem(service string, sender dbus.Sender) (err *dbus.Error) { ni := notifier.NewStatusNotifierItem(t.conn.Object(string(sender), dbus.ObjectPath(service))) - ico, ok := t.nodes[sender] + item, ok := t.nodes[sender] if !ok { + var ico *widget.Button ico = widget.NewButton("", func() { if m, err := ni.GetMenu(t.conn.Context()); err == nil { t.showMenu(string(sender), m, ico) @@ -172,13 +178,13 @@ func (t *tray) RegisterStatusNotifierItem(service string, sender dbus.Sender) (e } }) ico.Importance = widget.LowImportance - t.nodes[sender] = ico + item = &node{ico, ni} + t.nodes[sender] = item t.box.Add(ico) } - t.ni = ni - t.updateIcon(ico, ni) - ico.Refresh() + t.nodes[sender].ni = ni + t.updateIcon(item) t.box.Refresh() return nil @@ -297,18 +303,18 @@ func (t *tray) showMenu(sender string, name dbus.ObjectPath, from fyne.CanvasObj fynedesk.Instance().WindowManager().ShowOverlay(w, size, pos) } -func (t *tray) updateIcon(ico *widget.Button, ni *notifier.StatusNotifierItem) { - ic, _ := ni.GetIconPixmap(t.conn.Context()) +func (t *tray) updateIcon(i *node) { + ic, _ := i.ni.GetIconPixmap(t.conn.Context()) if len(ic) > 0 { img := pixelsToImage(ic[0]) unique := strconv.Itoa(resourceID) + ".png" resourceID++ w := &bytes.Buffer{} _ = png.Encode(w, img) - ico.SetIcon(fyne.NewStaticResource(unique, w.Bytes())) + i.ico.SetIcon(fyne.NewStaticResource(unique, w.Bytes())) } else { - name, _ := ni.GetIconName(t.conn.Context()) - path, _ := ni.GetIconThemePath(t.conn.Context()) + name, _ := i.ni.GetIconName(t.conn.Context()) + path, _ := i.ni.GetIconThemePath(t.conn.Context()) fullPath := "" if path != "" { fullPath = filepath.Join(path, name+".png") @@ -321,9 +327,9 @@ func (t *tray) updateIcon(ico *widget.Button, ni *notifier.StatusNotifierItem) { img, err := ioutil.ReadFile(fullPath) if err != nil { fyne.LogError("Failed to load status icon", err) - ico.SetIcon(wmtheme.BrokenImageIcon) + i.ico.SetIcon(wmtheme.BrokenImageIcon) } else { - ico.SetIcon(fyne.NewStaticResource(name, img)) + i.ico.SetIcon(fyne.NewStaticResource(name, img)) } } } From 998a421af9a55a806134b307d1858aec942c70d4 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 3 Jan 2024 16:00:08 +0000 Subject: [PATCH 04/27] Add polkit support :) --- internal/ui/desk.go | 5 +- internal/ui/embed_wm.go | 6 ++ internal/x11/wm/desk.go | 17 +++++ wm.go | 1 + wm/auth.go | 163 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 190 insertions(+), 2 deletions(-) create mode 100644 wm/auth.go diff --git a/internal/ui/desk.go b/internal/ui/desk.go index 75898dee..dbd4d09e 100644 --- a/internal/ui/desk.go +++ b/internal/ui/desk.go @@ -330,13 +330,14 @@ func (l *desktop) Screens() fynedesk.ScreenList { // NewDesktop creates a new desktop in fullscreen for main usage. // The WindowManager passed in will be used to manage the screen it is loaded on. // An ApplicationProvider is used to lookup application icons from the operating system. -func NewDesktop(app fyne.App, wm fynedesk.WindowManager, icons fynedesk.ApplicationProvider, screenProvider fynedesk.ScreenList) fynedesk.Desktop { - desk := newDesktop(app, wm, icons) +func NewDesktop(app fyne.App, mgr fynedesk.WindowManager, icons fynedesk.ApplicationProvider, screenProvider fynedesk.ScreenList) fynedesk.Desktop { + desk := newDesktop(app, mgr, icons) desk.run = desk.runFull screenProvider.AddChangeListener(desk.setupRoot) desk.screens = screenProvider desk.setupRoot() + wm.StartAuthAgent() go desk.startXscreensaver() return desk } diff --git a/internal/ui/embed_wm.go b/internal/ui/embed_wm.go index f5efc2d8..3761a6aa 100644 --- a/internal/ui/embed_wm.go +++ b/internal/ui/embed_wm.go @@ -43,6 +43,12 @@ func (e *embededWM) ShowMenuOverlay(*fyne.Menu, fyne.Size, fyne.Position) { // no-op, handled by desktop in embed mode } +func (e *embededWM) ShowModal(w fyne.Window, s fyne.Size) { + w.Resize(s) + w.CenterOnScreen() + w.Show() +} + func (e *embededWM) TopWindow() fynedesk.Window { if len(e.windows) == 0 { return nil diff --git a/internal/x11/wm/desk.go b/internal/x11/wm/desk.go index 8852683b..3a612656 100644 --- a/internal/x11/wm/desk.go +++ b/internal/x11/wm/desk.go @@ -264,6 +264,23 @@ func (x *x11WM) ShowMenuOverlay(m *fyne.Menu, s fyne.Size, p fyne.Position) { x.ShowOverlay(win, s, p) } +func (x *x11WM) ShowModal(w fyne.Window, s fyne.Size) { + w.SetTitle(windowNameMenu) + w.SetFixedSize(true) + w.Resize(s) + w.CenterOnScreen() + + w.Show() + x.menuSize = s + + root := fynedesk.Instance().Screens().Primary() + scale := root.CanvasScale() + p := fyne.NewPos((float32(root.Width)/scale-s.Width)/2, (float32(root.Height)/scale-s.Height)/2) + + x.menuPos = p + x.menuWin = w +} + func (x *x11WM) X() *xgbutil.XUtil { return x.x } diff --git a/wm.go b/wm.go index 9e8eee88..366f631a 100644 --- a/wm.go +++ b/wm.go @@ -17,6 +17,7 @@ type WindowManager interface { Run() ShowOverlay(fyne.Window, fyne.Size, fyne.Position) ShowMenuOverlay(*fyne.Menu, fyne.Size, fyne.Position) + ShowModal(fyne.Window, fyne.Size) } // Stack describes an ordered list of windows. diff --git a/wm/auth.go b/wm/auth.go new file mode 100644 index 00000000..a3b0d8fa --- /dev/null +++ b/wm/auth.go @@ -0,0 +1,163 @@ +package wm + +import ( + "bytes" + "fmt" + "image/color" + "log" + "os" + "os/exec" + "os/user" + "sync" + + "fyshos.com/fynedesk" + wmTheme "fyshos.com/fynedesk/theme" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + deskDriver "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" + + "github.com/godbus/dbus/v5" +) + +type subj struct { + Kind string + Details map[string]dbus.Variant +} + +type auth struct { + windows map[string]fyne.Window +} + +func (a *auth) register() { + conn2, _ := dbus.SystemBus() + err := conn2.ExportAll(a, "/AuthenticationAgent", "org.freedesktop.PolicyKit1.AuthenticationAgent") + if err != nil { + fyne.LogError("Could not start auth agent server", err) + } + + obj := conn2.Object("org.freedesktop.PolicyKit1", "/org/freedesktop/PolicyKit1/Authority") + call := obj.Call("org.freedesktop.PolicyKit1.Authority.RegisterAuthenticationAgent", 0, + + &subj{"unix-session", map[string]dbus.Variant{ + "session-id": dbus.MakeVariant("c1"), + }}, "en_US", + "/AuthenticationAgent") + if call.Err != nil { + fyne.LogError("Failed to register auth agent", call.Err) + } +} + +type ident struct { + ID string + Details map[string]dbus.Variant +} + +func (a *auth) BeginAuthentication(action_id, message, icon_name string, details map[string]string, cookie string, ids []ident, sender dbus.Sender) (err *dbus.Error) { + wg := &sync.WaitGroup{} + wg.Add(1) + pass := widget.NewPasswordEntry() + + username := "" + uid := "" + _, err2 := fmt.Sscanf(ids[0].Details["uid"].String(), "@u %s", &uid) + if err2 != nil { + currentUser, err2 := user.Current() + if err2 == nil { + username = currentUser.Username + } else { + fyne.LogError("Failed to look up fallback user", err2) + } + } else { + usr, err2 := user.LookupId(uid) + if err2 == nil { + username = usr.Username + } else { + fyne.LogError("Failed to look up user "+uid, err2) + } + } + f := widget.NewForm( + widget.NewFormItem("Ident", widget.NewLabel(username)), + widget.NewFormItem("Password", pass), + ) + w := fyne.CurrentApp().Driver().(deskDriver.Driver).CreateSplashWindow() + a.windows[cookie] = w + + var auth *widget.Button + auth = widget.NewButton("Authorize", func() { + auth.Disable() + cmd := exec.Command("/usr/lib/polkit-1/polkit-agent-helper-1", username) + + buffer := bytes.Buffer{} + buffer.Write([]byte(cookie + "\n")) + buffer.Write([]byte(pass.Text + "\n")) + cmd.Stdin = &buffer + + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err3 := cmd.Run() + + if err3 != nil { + log.Println("Auth err", err3) + } else { + w.Close() + } + auth.Enable() + }) + auth.Importance = widget.HighImportance + cancel := widget.NewButton("Cancel", func() { + w.Close() + }) + pass.OnSubmitted = func(string) { + auth.OnTapped() + } + + header := widget.NewRichTextFromMarkdown(fmt.Sprintf("### Authorise\n\n_%s_", message)) + header.Truncation = fyne.TextTruncateEllipsis + bottomPad := canvas.NewRectangle(color.Transparent) + bottomPad.SetMinSize(fyne.NewSquareSize(10)) + content := container.NewBorder( + header, + container.NewVBox( + container.NewHBox(layout.NewSpacer(), + container.NewGridWithColumns(2, cancel, auth), + layout.NewSpacer()), bottomPad), + nil, nil, f) + + r, g, b, _ := theme.OverlayBackgroundColor().RGBA() + bgCol := &color.NRGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: 230} + + bg := canvas.NewRectangle(bgCol) + icon := canvas.NewImageFromResource(wmTheme.LockIcon) + iconBox := container.NewWithoutLayout(icon) + icon.Resize(fyne.NewSize(92, 92)) + icon.Move(fyne.NewPos(300-92-theme.Padding(), theme.Padding())) + w.SetContent(container.NewStack( + iconBox, bg, + container.NewPadded(content))) + + w.SetOnClosed(func() { + delete(a.windows, cookie) + wg.Done() + }) + fynedesk.Instance().WindowManager().ShowModal(w, fyne.NewSize(300, 210)) + + wg.Wait() + return nil +} + +func (a *auth) CancelAuthentication(cookie string, sender dbus.Sender) (err *dbus.Error) { + if w, ok := a.windows[cookie]; ok { + w.Close() // OnClose will tidy the session + } + return nil +} + +func StartAuthAgent() { + a := &auth{} + go a.register() +} From d8d100d382a9993c02351e324b1bf30b1f0af485 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 3 Jan 2024 16:02:37 +0000 Subject: [PATCH 05/27] And close open requests if cancelled --- wm/auth.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wm/auth.go b/wm/auth.go index a3b0d8fa..ced853fe 100644 --- a/wm/auth.go +++ b/wm/auth.go @@ -158,6 +158,6 @@ func (a *auth) CancelAuthentication(cookie string, sender dbus.Sender) (err *dbu } func StartAuthAgent() { - a := &auth{} + a := &auth{windows: make(map[string]fyne.Window)} go a.register() } From c7629f1125c0b0dd12b732add36f784c41bf58d5 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 3 Jan 2024 16:11:05 +0000 Subject: [PATCH 06/27] Avoid expensive check callbacks where we can --- internal/x11/win/client.go | 31 +++++----------- internal/x11/win/frame.go | 74 ++++++++++++-------------------------- internal/x11/wm/events.go | 13 ++----- 3 files changed, 33 insertions(+), 85 deletions(-) diff --git a/internal/x11/win/client.go b/internal/x11/win/client.go index 996f0252..7aa97918 100644 --- a/internal/x11/win/client.go +++ b/internal/x11/win/client.go @@ -38,12 +38,9 @@ type client struct { // NewClient creates a new X11 client for the specified window ID and X window manager func NewClient(win xproto.Window, wm x11.XWM) x11.XWin { c := &client{win: win, wm: wm, desk: fynedesk.Instance().Desktop()} - err := xproto.ChangeWindowAttributesChecked(wm.Conn(), win, xproto.CwEventMask, + xproto.ChangeWindowAttributes(wm.Conn(), win, xproto.CwEventMask, []uint32{xproto.EventMaskPropertyChange | xproto.EventMaskEnterWindow | xproto.EventMaskLeaveWindow | - xproto.EventMaskVisibilityChange}).Check() - if err != nil { - fyne.LogError("Could not change window attributes", err) - } + xproto.EventMaskVisibilityChange}) windowAllowedActionsSet(wm.X(), win, x11.AllowedActions) initialHints := x11.WindowExtendedHintsGet(wm.X(), c.win) @@ -92,10 +89,7 @@ func (c *client) Close() { } if !askNicely { - err := xproto.DestroyWindowChecked(c.wm.Conn(), c.win).Check() - if err != nil { - fyne.LogError("Close Error", err) - } + xproto.DestroyWindow(c.wm.Conn(), c.win) return } @@ -118,10 +112,7 @@ func (c *client) Close() { return } - err = xproto.SendEventChecked(c.wm.Conn(), false, c.win, 0, string(cm.Bytes())).Check() - if err != nil { - fyne.LogError("Window Delete Error", err) - } + xproto.SendEvent(c.wm.Conn(), false, c.win, 0, string(cm.Bytes())) } func (c *client) Desktop() int { @@ -316,11 +307,8 @@ func (c *client) RaiseAbove(win fynedesk.Window) { return } - err := xproto.ConfigureWindowChecked(c.wm.Conn(), c.id, xproto.ConfigWindowSibling|xproto.ConfigWindowStackMode, - []uint32{uint32(topID), uint32(xproto.StackModeAbove)}).Check() - if err != nil { - fyne.LogError("Restack Error", err) - } + xproto.ConfigureWindow(c.wm.Conn(), c.id, xproto.ConfigWindowSibling|xproto.ConfigWindowStackMode, + []uint32{uint32(topID), uint32(xproto.StackModeAbove)}) } func (c *client) RaiseToTop() { @@ -430,12 +418,9 @@ func (c *client) positionNewWindow() { decorated, fynedesk.Instance().Screens()) } - err = xproto.ConfigureWindowChecked(c.wm.Conn(), c.win, xproto.ConfigWindowX|xproto.ConfigWindowY| + xproto.ConfigureWindow(c.wm.Conn(), c.win, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, []uint32{uint32(x), uint32(y), - uint32(w), uint32(h)}).Check() - if err != nil { - fyne.LogError("", err) - } + uint32(w), uint32(h)}) } func (c *client) stateMessage(state int) { diff --git a/internal/x11/win/frame.go b/internal/x11/win/frame.go index 3cf7191b..5bcab777 100644 --- a/internal/x11/win/frame.go +++ b/internal/x11/win/frame.go @@ -155,12 +155,9 @@ func newFrame(c *client) *frame { } if full || maximized { - err = xproto.ConfigureWindowChecked(c.wm.Conn(), c.win, xproto.ConfigWindowX|xproto.ConfigWindowY| + xproto.ConfigureWindow(c.wm.Conn(), c.win, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{uint32(offsetX), uint32(offsetY), uint32(framed.childWidth), uint32(framed.childHeight)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } + []uint32{uint32(offsetX), uint32(offsetY), uint32(framed.childWidth), uint32(framed.childHeight)}) } windowStateSet(c.wm.X(), c.win, icccm.StateNormal) @@ -194,20 +191,14 @@ func (f *frame) addBorder() { } f.applyTheme(true) - err := xproto.ConfigureWindowChecked(f.client.wm.Conn(), f.client.win, xproto.ConfigWindowX|xproto.ConfigWindowY| + xproto.ConfigureWindow(f.client.wm.Conn(), f.client.win, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{uint32(x), uint32(y), uint32(f.childWidth), uint32(f.childHeight)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } - err = xproto.ConfigureWindowChecked(f.client.wm.Conn(), f.client.id, xproto.ConfigWindowX|xproto.ConfigWindowY| + []uint32{uint32(x), uint32(y), uint32(f.childWidth), uint32(f.childHeight)}) + xproto.ConfigureWindow(f.client.wm.Conn(), f.client.id, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{uint32(f.x), uint32(f.y), uint32(w), uint32(h)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } + []uint32{uint32(f.x), uint32(f.y), uint32(w), uint32(h)}) - err = ewmh.FrameExtentsSet(f.client.wm.X(), f.client.win, &ewmh.FrameExtents{Left: int(borderWidth), Right: int(borderWidth), Top: int(titleHeight), Bottom: int(borderWidth)}) + err := ewmh.FrameExtentsSet(f.client.wm.X(), f.client.win, &ewmh.FrameExtents{Left: int(borderWidth), Right: int(borderWidth), Top: int(titleHeight), Bottom: int(borderWidth)}) if err != nil { fyne.LogError("", err) } @@ -215,12 +206,9 @@ func (f *frame) addBorder() { } func (f *frame) applyBorderlessTheme() { - err := xproto.ConfigureWindowChecked(f.client.wm.Conn(), f.client.win, xproto.ConfigWindowX|xproto.ConfigWindowY| + xproto.ConfigureWindow(f.client.wm.Conn(), f.client.win, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{uint32(0), uint32(0), uint32(f.width), uint32(f.height)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } + []uint32{uint32(0), uint32(0), uint32(f.width), uint32(f.height)}) } func (f *frame) applyTheme(force bool) { @@ -290,11 +278,8 @@ func (f *frame) copyDecorationPixels(width, height, xoff, yoff uint32, img image i += 4 } } - err := xproto.PutImageChecked(f.client.wm.Conn(), xproto.ImageFormatZPixmap, xproto.Drawable(pid), draw, - uint16(width), uint16(height), 0, int16(yoff), 0, depth, data).Check() - if err != nil { - fyne.LogError("Put image error", err) - } + xproto.PutImage(f.client.wm.Conn(), xproto.ImageFormatZPixmap, xproto.Drawable(pid), draw, + uint16(width), uint16(height), 0, int16(yoff), 0, depth, data) } func (f *frame) createPixmaps(depth byte) error { @@ -621,11 +606,8 @@ func (f *frame) mouseMotion(x, y int16) { if refresh { f.applyTheme(true) } - err := xproto.ChangeWindowAttributesChecked(f.client.wm.Conn(), f.client.id, xproto.CwCursor, - []uint32{uint32(cursor)}).Check() - if err != nil { - fyne.LogError("Set Cursor Error", err) - } + xproto.ChangeWindowAttributes(f.client.wm.Conn(), f.client.id, xproto.CwCursor, + []uint32{uint32(cursor)}) } func (f *frame) lookupResizeCursor(x, y int16) xproto.Cursor { @@ -802,20 +784,14 @@ func (f *frame) removeBorder() { } f.applyTheme(true) - err := xproto.ConfigureWindowChecked(f.client.wm.Conn(), f.client.id, xproto.ConfigWindowX|xproto.ConfigWindowY| + xproto.ConfigureWindow(f.client.wm.Conn(), f.client.id, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{uint32(f.x), uint32(f.y), uint32(f.width), uint32(f.height)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } - err = xproto.ConfigureWindowChecked(f.client.wm.Conn(), f.client.win, xproto.ConfigWindowX|xproto.ConfigWindowY| + []uint32{uint32(f.x), uint32(f.y), uint32(f.width), uint32(f.height)}) + xproto.ConfigureWindow(f.client.wm.Conn(), f.client.win, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{0, 0, uint32(f.childWidth), uint32(f.childHeight)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } + []uint32{0, 0, uint32(f.childWidth), uint32(f.childHeight)}) - err = ewmh.FrameExtentsSet(f.client.wm.X(), f.client.win, &ewmh.FrameExtents{Left: 0, Right: 0, Top: 0, Bottom: 0}) + err := ewmh.FrameExtentsSet(f.client.wm.X(), f.client.win, &ewmh.FrameExtents{Left: 0, Right: 0, Top: 0, Bottom: 0}) if err != nil { fyne.LogError("", err) } @@ -892,18 +868,12 @@ func (f *frame) updateGeometry(x, y int16, w, h uint16, force bool) { f.childWidth = uint16(innerW) f.childHeight = uint16(innerH) - err := xproto.ConfigureWindowChecked(f.client.wm.Conn(), f.client.id, xproto.ConfigWindowX|xproto.ConfigWindowY| + xproto.ConfigureWindow(f.client.wm.Conn(), f.client.id, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{uint32(f.x), uint32(f.y), uint32(f.width), uint32(f.height)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } - err = xproto.ConfigureWindowChecked(f.client.wm.Conn(), f.client.win, xproto.ConfigWindowX|xproto.ConfigWindowY| + []uint32{uint32(f.x), uint32(f.y), uint32(f.width), uint32(f.height)}) + xproto.ConfigureWindow(f.client.wm.Conn(), f.client.win, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{innerX, innerY, uint32(f.childWidth), uint32(f.childHeight)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } + []uint32{innerX, innerY, uint32(f.childWidth), uint32(f.childHeight)}) newScreen := fynedesk.Instance().Screens().ScreenForWindow(f.client) if newScreen != currentScreen { diff --git a/internal/x11/wm/events.go b/internal/x11/wm/events.go index 1a9f51a3..e7537508 100644 --- a/internal/x11/wm/events.go +++ b/internal/x11/wm/events.go @@ -45,11 +45,7 @@ func (x *x11WM) handleActiveWin(ev xproto.ClientMessageEvent) { } // ask for focus, when it is lost return to root window - err = xproto.SetInputFocusChecked(x.x.Conn(), 1, ev.Window, xproto.TimeCurrentTime).Check() - if err != nil { - fyne.LogError("Could not set focus", err) - return - } + xproto.SetInputFocus(x.x.Conn(), 1, ev.Window, xproto.TimeCurrentTime).Check() } if notifyFocus { protocolAtm, err := xprop.Atm(x.x, "WM_PROTOCOLS") @@ -228,11 +224,8 @@ func (x *x11WM) handleKeyRelease(ev xproto.KeyReleaseEvent) { } func (x *x11WM) handleMouseEnter(ev xproto.EnterNotifyEvent) { - err := xproto.ChangeWindowAttributesChecked(x.x.Conn(), ev.Event, xproto.CwCursor, - []uint32{uint32(x11.DefaultCursor)}).Check() - if err != nil { - fyne.LogError("Set Cursor Error", err) - } + xproto.ChangeWindowAttributes(x.x.Conn(), ev.Event, xproto.CwCursor, + []uint32{uint32(x11.DefaultCursor)}) if mouseNotify, ok := fynedesk.Instance().(notify.MouseNotify); ok { mouseNotify.MouseOutNotify() } From 190af60f243da337df7196ec020b71208333a04c Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 3 Jan 2024 16:20:13 +0000 Subject: [PATCH 07/27] Fallback to a nil icon so the UI can choose what to display --- internal/icon/fdo.go | 38 +++++++++++++-------------- internal/icon/macos.go | 7 +++-- internal/x11/win/client_properties.go | 6 +++-- internal/x11/win/property.go | 17 +++++++----- wm/border.go | 5 +--- 5 files changed, 36 insertions(+), 37 deletions(-) diff --git a/internal/icon/fdo.go b/internal/icon/fdo.go index 8f0a2d25..76bb9b26 100644 --- a/internal/icon/fdo.go +++ b/internal/icon/fdo.go @@ -13,8 +13,6 @@ import ( "fyne.io/fyne/v2" "fyshos.com/fynedesk" - wmTheme "fyshos.com/fynedesk/theme" - _ "github.com/fyne-io/image/xpm" // load XPM icons to supported image format ) @@ -26,7 +24,7 @@ var ( "Office", "Science", "Settings", "System", "Utility"} ) -//fdoApplicationData is a structure that contains information about .desktop files +// fdoApplicationData is a structure that contains information about .desktop files type fdoApplicationData struct { name string // Application name iconName string // Icon name @@ -38,12 +36,12 @@ type fdoApplicationData struct { iconCache fyne.Resource } -//Name returns the name associated with an fdo app +// Name returns the name associated with an fdo app func (data *fdoApplicationData) Name() string { return data.name } -//Categories returns a list of the categories this icon has configured +// Categories returns a list of the categories this icon has configured func (data *fdoApplicationData) Categories() []string { return data.categories } @@ -52,12 +50,12 @@ func (data *fdoApplicationData) Hidden() bool { return data.hide } -//IconName returns the name of the icon that an fdo app wishes to use +// IconName returns the name of the icon that an fdo app wishes to use func (data *fdoApplicationData) IconName() string { return data.iconName } -//IconPath returns the path of the icon that an fdo app wishes to use +// IconPath returns the path of the icon that an fdo app wishes to use func (data *fdoApplicationData) Icon(theme string, size int) fyne.Resource { if data.iconCache != nil { return data.iconCache @@ -67,7 +65,7 @@ func (data *fdoApplicationData) Icon(theme string, size int) fyne.Resource { if path == "" { path = FdoLookupIconPath(theme, size, data.iconName) if path == "" { - return wmTheme.BrokenImageIcon + return nil } } @@ -75,7 +73,7 @@ func (data *fdoApplicationData) Icon(theme string, size int) fyne.Resource { return data.iconCache } -//extractArgs sanitises argument parameters from an Exec configuration +// extractArgs sanitises argument parameters from an Exec configuration func extractArgs(args []string) []string { var ret []string for _, arg := range args { @@ -88,7 +86,7 @@ func extractArgs(args []string) []string { return ret } -//Run executes the command for this fdo app +// Run executes the command for this fdo app func (data *fdoApplicationData) Run(env []string) error { vars := os.Environ() vars = append(vars, env...) @@ -135,7 +133,7 @@ func loadIcon(path string) fyne.Resource { return fyne.NewStaticResource(filepath.Base(path), data) } -//fdoLookupXdgDataDirs returns a string slice of all XDG_DATA_DIRS +// fdoLookupXdgDataDirs returns a string slice of all XDG_DATA_DIRS func fdoLookupXdgDataDirs() []string { dataLocation := os.Getenv("XDG_DATA_DIRS") locationLookup := strings.Split(dataLocation, ":") @@ -177,7 +175,7 @@ func fdoForEachApplicationFile(f func(data fynedesk.AppData) bool) { } } -//lookupApplicationByMetadata looks up an application by comparing the requested name to the contents of .desktop files +// lookupApplicationByMetadata looks up an application by comparing the requested name to the contents of .desktop files func (f *fdoIconProvider) lookupApplicationByMetadata(appName string) fynedesk.AppData { var returnIcon fynedesk.AppData f.cache.forEachCachedApplication(func(_ string, icon fynedesk.AppData) bool { @@ -190,7 +188,7 @@ func (f *fdoIconProvider) lookupApplicationByMetadata(appName string) fynedesk.A return returnIcon } -//lookupApplication looks up an application by name and returns an fdoApplicationData struct +// lookupApplication looks up an application by name and returns an fdoApplicationData struct func (f *fdoIconProvider) lookupApplication(appName string) fynedesk.AppData { if appName == "" { return nil @@ -388,7 +386,7 @@ func FdoLookupIconPathInTheme(iconSize string, dir string, parentDir string, ico return "" } -//FdoLookupIconPath will take the name of an icon and find a matching image file +// FdoLookupIconPath will take the name of an icon and find a matching image file func FdoLookupIconPath(theme string, size int, iconName string) string { locationLookup := fdoLookupXdgDataDirs() iconTheme := theme @@ -442,7 +440,7 @@ func fdoLookupAvailableThemes() []string { return themes } -//newFdoIconData creates and returns a struct that contains needed fields from a .desktop file +// newFdoIconData creates and returns a struct that contains needed fields from a .desktop file func newFdoIconData(desktopPath string) fynedesk.AppData { file, err := os.Open(desktopPath) if err != nil { @@ -495,7 +493,7 @@ type fdoIconProvider struct { cache *appCache } -//AvailableApps returns all of the available applications in a AppData slice +// AvailableApps returns all of the available applications in a AppData slice func (f *fdoIconProvider) AvailableApps() []fynedesk.AppData { var icons []fynedesk.AppData fdoForEachApplicationFile(func(icon fynedesk.AppData) bool { @@ -508,17 +506,17 @@ func (f *fdoIconProvider) AvailableApps() []fynedesk.AppData { return icons } -//AvailableThemes returns all available icon themes in a string slice +// AvailableThemes returns all available icon themes in a string slice func (f *fdoIconProvider) AvailableThemes() []string { return fdoLookupAvailableThemes() } -//FindAppFromName matches an icon name to a location and returns an AppData interface +// FindAppFromName matches an icon name to a location and returns an AppData interface func (f *fdoIconProvider) FindAppFromName(appName string) fynedesk.AppData { return f.lookupApplication(appName) } -//FindAppsMatching returns a list of icons that match a partial name of an app and returns an AppData slice +// FindAppsMatching returns a list of icons that match a partial name of an app and returns an AppData slice func (f *fdoIconProvider) FindAppsMatching(appName string) []fynedesk.AppData { var icons []fynedesk.AppData f.cache.forEachCachedApplication(func(_ string, icon fynedesk.AppData) bool { @@ -536,7 +534,7 @@ func (f *fdoIconProvider) FindAppsMatching(appName string) []fynedesk.AppData { return icons } -//FindAppFromWinInfo matches window information to an icon location and returns an AppData interface +// FindAppFromWinInfo matches window information to an icon location and returns an AppData interface func (f *fdoIconProvider) FindAppFromWinInfo(win fynedesk.Window) fynedesk.AppData { app := f.lookupApplication(win.Properties().Command()) if app != nil { diff --git a/internal/icon/macos.go b/internal/icon/macos.go index 7403bd6b..9dcd0131 100644 --- a/internal/icon/macos.go +++ b/internal/icon/macos.go @@ -16,7 +16,6 @@ import ( "fyne.io/fyne/v2" "fyshos.com/fynedesk" - wmtheme "fyshos.com/fynedesk/theme" ) type macOSAppBundle struct { @@ -52,20 +51,20 @@ func (m *macOSAppBundle) Icon(_ string, _ int) fyne.Resource { src, err := os.Open(m.iconPath) if err != nil { fyne.LogError("Failed to read icon data for "+m.iconPath, err) - return wmtheme.BrokenImageIcon + return nil } icon, err := icns.Decode(src) if err != nil { fyne.LogError("Failed to parse icon data for "+m.iconPath, err) - return wmtheme.BrokenImageIcon + return nil } var data bytes.Buffer err = png.Encode(&data, icon) if err != nil { fyne.LogError("Failed to encode icon data for "+m.iconPath, err) - return wmtheme.BrokenImageIcon + return nil } iconName := filepath.Base(m.iconPath) diff --git a/internal/x11/win/client_properties.go b/internal/x11/win/client_properties.go index d3578733..9b6a6c93 100644 --- a/internal/x11/win/client_properties.go +++ b/internal/x11/win/client_properties.go @@ -52,9 +52,11 @@ func (c *clientProperties) Icon() fyne.Resource { settings := fynedesk.Instance().Settings() iconSize := int(settings.LauncherIconSize() * settings.LauncherZoomScale()) xIcon := windowIcon(c.c.wm.X(), c.c.win, iconSize, iconSize) - if len(xIcon.Bytes()) != 0 { - c.iconCache = fyne.NewStaticResource(c.Title(), xIcon.Bytes()) + if xIcon == nil { + return nil } + + c.iconCache = fyne.NewStaticResource(c.Title(), xIcon.Bytes()) return c.iconCache } diff --git a/internal/x11/win/property.go b/internal/x11/win/property.go index 163de30d..a7b061b6 100644 --- a/internal/x11/win/property.go +++ b/internal/x11/win/property.go @@ -7,7 +7,6 @@ import ( "bytes" "math" - "fyne.io/fyne/v2" "github.com/BurntSushi/xgb/xproto" "github.com/BurntSushi/xgbutil" "github.com/BurntSushi/xgbutil/ewmh" @@ -16,6 +15,8 @@ import ( "github.com/BurntSushi/xgbutil/xgraphics" "github.com/BurntSushi/xgbutil/xprop" + "fyne.io/fyne/v2" + "fyshos.com/fynedesk" "fyshos.com/fynedesk/internal/x11" ) @@ -69,16 +70,18 @@ func windowCommand(x *xgbutil.XUtil, win xproto.Window) string { return command } -func windowIcon(x *xgbutil.XUtil, win xproto.Window, width int, height int) bytes.Buffer { - var w bytes.Buffer +func windowIcon(x *xgbutil.XUtil, win xproto.Window, width int, height int) *bytes.Buffer { img, err := xgraphics.FindIcon(x, win, width, height) if err != nil { - fyne.LogError("Could not get window icon", err) - return w + fyne.LogError("ICON: Could not get window icon", err) + return nil } - err = img.WritePng(&w) + + w := &bytes.Buffer{} + err = img.WritePng(w) if err != nil { - fyne.LogError("Could not convert icon to png", err) + fyne.LogError("ICON: Could not convert icon to png", err) + return nil } return w } diff --git a/wm/border.go b/wm/border.go index 88f46e06..b9530dad 100644 --- a/wm/border.go +++ b/wm/border.go @@ -33,10 +33,6 @@ func NewBorder(win fynedesk.Window, icon fyne.Resource, canMaximize bool) *Borde if app != nil { icon = app.Icon(iconTheme, int(wmTheme.TitleHeight*2)) } - - if icon == nil { - icon = wmTheme.BrokenImageIcon - } } max := &widget.Button{Icon: wmTheme.MaximizeIcon, Importance: widget.LowImportance, OnTapped: func() { @@ -188,6 +184,7 @@ func (c *Border) CreateRenderer() fyne.WidgetRenderer { // SetIcon tells the border to change the icon that should be used func (c *Border) SetIcon(icon fyne.Resource) { if icon == nil { + c.appIcon.Icon = nil return } From cd79e63d15f3a80e7b4c9f334b4b51cbdc780b1b Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 3 Jan 2024 16:25:58 +0000 Subject: [PATCH 08/27] Avoid issues by updating to Go 1.19 here as well --- .github/workflows/platform_tests.yml | 4 ++-- .github/workflows/static_analysis.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/platform_tests.yml b/.github/workflows/platform_tests.yml index 7e0f6c5b..226dd2ac 100644 --- a/.github/workflows/platform_tests.yml +++ b/.github/workflows/platform_tests.yml @@ -9,7 +9,7 @@ jobs: strategy: fail-fast: false matrix: - go-version: ['1.17', '1.20'] + go-version: ['1.19', '1.21'] os: [ubuntu-latest, macos-latest] steps: @@ -41,4 +41,4 @@ jobs: uses: shogo82148/actions-goveralls@v1 with: path-to-profile: coverage.out - if: ${{ runner.os == 'Linux' && matrix.go-version == '1.17' }} + if: ${{ runner.os == 'Linux' && matrix.go-version == '1.19' }} diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index 6949127f..7be33e16 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -12,7 +12,7 @@ jobs: persist-credentials: false - uses: WillAbides/setup-go-faster@v1.7.0 with: - go-version: '1.17.x' + go-version: '1.19.x' - name: Get dependencies run: | @@ -38,4 +38,4 @@ jobs: run: golint -set_exit_status $(go list -tags ci ./...) - name: Staticcheck - run: staticcheck -go 1.17 ./... + run: staticcheck -go 1.19 ./... From 993694d145a4c5d594e1fc1c26a771cba6f7268f Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 3 Jan 2024 17:20:36 +0000 Subject: [PATCH 09/27] Fix subtle bug caused by variable overwrite --- internal/icon/fdo.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/icon/fdo.go b/internal/icon/fdo.go index 76bb9b26..2e7d3c34 100644 --- a/internal/icon/fdo.go +++ b/internal/icon/fdo.go @@ -360,8 +360,8 @@ func FdoLookupIconPathInTheme(iconSize string, dir string, parentDir string, ico } if len(inheritedThemes) > 0 { for _, theme := range inheritedThemes { - dir = filepath.Join(parentDir, "icons", theme) - iconPath := FdoLookupIconPathInTheme(iconSize, dir, parentDir, iconName) + childDir := filepath.Join(parentDir, "icons", theme) + iconPath := FdoLookupIconPathInTheme(iconSize, childDir, parentDir, iconName) if iconPath != "" { return iconPath } From 79a7398faf8a7b9571a93b632826705724770e17 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 3 Jan 2024 17:21:26 +0000 Subject: [PATCH 10/27] Fix whitespace in newer linter --- internal/icon/fdo_test.go | 24 +++++++++---------- internal/ui/baricon.go | 4 ++-- internal/ui/barlayout.go | 6 ++--- .../notifier/status_notifier_item.go | 9 ++++--- .../watcher/status_notifier_watcher.go | 3 ++- 5 files changed, 25 insertions(+), 21 deletions(-) diff --git a/internal/icon/fdo_test.go b/internal/icon/fdo_test.go index 2e3c608d..46a5c614 100644 --- a/internal/icon/fdo_test.go +++ b/internal/icon/fdo_test.go @@ -36,21 +36,21 @@ func setTestEnv(t *testing.T) { } } -//applications/app1.desktop and icons/default_theme/apps/32x32/app1.png +// applications/app1.desktop and icons/default_theme/apps/32x32/app1.png func TestFdoLookupDefaultTheme(t *testing.T) { setTestEnv(t) data := NewFDOIconProvider().(*fdoIconProvider).lookupApplication("app1") assert.Equal(t, true, exists(data)) } -//applications/com.fyne.app.desktop and icons/default_theme/apps/scalable/app2.svg +// applications/com.fyne.app.desktop and icons/default_theme/apps/scalable/app2.svg func TestFdoFileNameMisMatchAndScalable(t *testing.T) { setTestEnv(t) data := NewFDOIconProvider().(*fdoIconProvider).lookupApplication("app2") assert.Equal(t, true, exists(data)) } -//check the category from app1 +// check the category from app1 func TestFdoIconCategory(t *testing.T) { setTestEnv(t) data := NewFDOIconProvider().(*fdoIconProvider).lookupApplication("app1") @@ -61,7 +61,7 @@ func TestFdoIconCategory(t *testing.T) { assert.Equal(t, "Utility", data.(*fdoApplicationData).mainCategory()) } -//applications/app3.desktop and applications/app3.png +// applications/app3.desktop and applications/app3.png func TestFdoIconNameIsPath(t *testing.T) { setTestEnv(t) dataLocation := os.Getenv("XDG_DATA_DIRS") @@ -75,56 +75,56 @@ func TestFdoIconNameIsPath(t *testing.T) { assert.Equal(t, true, exists(data)) } -//check NoDisplay from app4 +// check NoDisplay from app4 func TestFdoIconHide(t *testing.T) { setTestEnv(t) data := NewFDOIconProvider().(*fdoIconProvider).lookupApplication("app4") assert.Equal(t, true, data.Hidden()) } -//applications/app4.desktop and pixmaps/app4.png +// applications/app4.desktop and pixmaps/app4.png func TestFdoIconInPixmaps(t *testing.T) { setTestEnv(t) data := NewFDOIconProvider().(*fdoIconProvider).lookupApplication("app4") assert.Equal(t, true, exists(data)) } -//applications/app5.desktop and icons/hicolor/32x32/apps/app5.png +// applications/app5.desktop and icons/hicolor/32x32/apps/app5.png func TestFdoIconHicolorFallback(t *testing.T) { setTestEnv(t) data := NewFDOIconProvider().(*fdoIconProvider).lookupApplication("app5") assert.Equal(t, true, exists(data)) } -//applications/app6.desktop and icons/hicolor/scalable/apps/app6.svg +// applications/app6.desktop and icons/hicolor/scalable/apps/app6.svg func TestFdoIconHicolorFallbackScalable(t *testing.T) { setTestEnv(t) data := NewFDOIconProvider().(*fdoIconProvider).lookupApplication("app6") assert.Equal(t, true, exists(data)) } -//applications/app7.desktop and icons/default_theme/apps/16x16/app7.png +// applications/app7.desktop and icons/default_theme/apps/16x16/app7.png func TestFdoLookupDefaultThemeDifferentSize(t *testing.T) { setTestEnv(t) data := NewFDOIconProvider().(*fdoIconProvider).lookupApplication("app7") assert.Equal(t, true, exists(data)) } -//applications/app8.desktop and icons/third_theme/apps/32/app8.png +// applications/app8.desktop and icons/third_theme/apps/32/app8.png func TestFdoLookupAnyThemeFallback(t *testing.T) { setTestEnv(t) data := NewFDOIconProvider().(*fdoIconProvider).lookupApplication("app8") assert.Equal(t, true, exists(data)) } -//applications/xterm.desktop and icons/third_theme/emblems/16x16/app9.png +// applications/xterm.desktop and icons/third_theme/emblems/16x16/app9.png func TestFdoLookupIconNotInApps(t *testing.T) { setTestEnv(t) data := NewFDOIconProvider().(*fdoIconProvider).lookupApplication("xterm") assert.Equal(t, true, exists(data)) } -//missing - not able to match +// missing - not able to match func TestFdoLookupMissing(t *testing.T) { setTestEnv(t) provider := NewFDOIconProvider() diff --git a/internal/ui/baricon.go b/internal/ui/baricon.go index 29b11dde..7e3aa818 100644 --- a/internal/ui/baricon.go +++ b/internal/ui/baricon.go @@ -82,7 +82,7 @@ type barIcon struct { windowData *appWindow // The window data associated with this icon (if it is a task window) } -//Tapped means barIcon has been clicked +// Tapped means barIcon has been clicked func (bi *barIcon) Tapped(*fyne.PointEvent) { bi.onTapped() } @@ -112,7 +112,7 @@ func removeFromBar(icon fynedesk.AppData) { settings.(*deskSettings).setLauncherIcons(icons) } -//TappedSecondary means barIcon has been clicked by a secondary binding +// TappedSecondary means barIcon has been clicked by a secondary binding func (bi *barIcon) TappedSecondary(*fyne.PointEvent) { app := bi.appData if app == nil && bi.windowData != nil { diff --git a/internal/ui/barlayout.go b/internal/ui/barlayout.go index 6e7fdd10..63d9d953 100644 --- a/internal/ui/barlayout.go +++ b/internal/ui/barlayout.go @@ -18,7 +18,7 @@ const ( separatorWidth = 2 ) -//barLayout returns a layout used for zooming linear groups of icons +// barLayout returns a layout used for zooming linear groups of icons type barLayout struct { bar *bar @@ -26,12 +26,12 @@ type barLayout struct { mousePosition fyne.Position // Current coordinates of the mouse cursor } -//setPointerInside tells the barLayout that the mouse is inside of the Layout. +// setPointerInside tells the barLayout that the mouse is inside of the Layout. func (bl *barLayout) setPointerInside(inside bool) { bl.mouseInside = inside } -//setPointerPosition tells the barLayout that the mouse position has been updated. +// setPointerPosition tells the barLayout that the mouse position has been updated. func (bl *barLayout) setPointerPosition(position fyne.Position) { bl.mousePosition = position } diff --git a/modules/systray/generated/notifier/status_notifier_item.go b/modules/systray/generated/notifier/status_notifier_item.go index 6afbdb08..227025d9 100644 --- a/modules/systray/generated/notifier/status_notifier_item.go +++ b/modules/systray/generated/notifier/status_notifier_item.go @@ -317,7 +317,8 @@ func (o *StatusNotifierItem) GetIconName(ctx context.Context) (iconName string, // GetIconPixmap gets org.kde.StatusNotifierItem.IconPixmap property. // // Annotations: -// @org.qtproject.QtDBus.QtTypeName = KDbusImageVector +// +// @org.qtproject.QtDBus.QtTypeName = KDbusImageVector func (o *StatusNotifierItem) GetIconPixmap(ctx context.Context) (iconPixmap []struct { V0 int32 V1 int32 @@ -336,7 +337,8 @@ func (o *StatusNotifierItem) GetOverlayIconName(ctx context.Context) (overlayIco // GetOverlayIconPixmap gets org.kde.StatusNotifierItem.OverlayIconPixmap property. // // Annotations: -// @org.qtproject.QtDBus.QtTypeName = KDbusImageVector +// +// @org.qtproject.QtDBus.QtTypeName = KDbusImageVector func (o *StatusNotifierItem) GetOverlayIconPixmap(ctx context.Context) (overlayIconPixmap []struct { V0 int32 V1 int32 @@ -355,7 +357,8 @@ func (o *StatusNotifierItem) GetAttentionIconName(ctx context.Context) (attentio // GetAttentionIconPixmap gets org.kde.StatusNotifierItem.AttentionIconPixmap property. // // Annotations: -// @org.qtproject.QtDBus.QtTypeName = KDbusImageVector +// +// @org.qtproject.QtDBus.QtTypeName = KDbusImageVector func (o *StatusNotifierItem) GetAttentionIconPixmap(ctx context.Context) (attentionIconPixmap []struct { V0 int32 V1 int32 diff --git a/modules/systray/generated/watcher/status_notifier_watcher.go b/modules/systray/generated/watcher/status_notifier_watcher.go index 4e9832db..7a8dbd80 100644 --- a/modules/systray/generated/watcher/status_notifier_watcher.go +++ b/modules/systray/generated/watcher/status_notifier_watcher.go @@ -188,7 +188,8 @@ func (o *StatusNotifierWatcher) RegisterStatusNotifierHost(ctx context.Context, // GetRegisteredStatusNotifierItems gets org.kde.StatusNotifierWatcher.RegisteredStatusNotifierItems property. // // Annotations: -// @org.qtproject.QtDBus.QtTypeName.Out0 = QStringList +// +// @org.qtproject.QtDBus.QtTypeName.Out0 = QStringList func (o *StatusNotifierWatcher) GetRegisteredStatusNotifierItems(ctx context.Context) (registeredStatusNotifierItems []string, err error) { err = o.object.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, InterfaceStatusNotifierWatcher, "RegisteredStatusNotifierItems").Store(®isteredStatusNotifierItems) return From 23f47dda7a1b6fbd7258138857843e49c2d553a8 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 3 Jan 2024 17:25:06 +0000 Subject: [PATCH 11/27] Update runner for Go versions --- .github/workflows/platform_tests.yml | 4 ++-- .github/workflows/static_analysis.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/platform_tests.yml b/.github/workflows/platform_tests.yml index 226dd2ac..90d00704 100644 --- a/.github/workflows/platform_tests.yml +++ b/.github/workflows/platform_tests.yml @@ -13,10 +13,10 @@ jobs: os: [ubuntu-latest, macos-latest] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: persist-credentials: false - - uses: WillAbides/setup-go-faster@v1.7.0 + - uses: WillAbides/setup-go-faster@v1.13.0 with: go-version: ${{ matrix.go-version }} diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index 7be33e16..96862355 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -7,10 +7,10 @@ jobs: checks: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: persist-credentials: false - - uses: WillAbides/setup-go-faster@v1.7.0 + - uses: WillAbides/setup-go-faster@v1.13.0 with: go-version: '1.19.x' From 575bc345ca6a8e1085b21b8fdba6f23e0a2e27f4 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 3 Jan 2024 17:27:45 +0000 Subject: [PATCH 12/27] Fix new lint issues --- wm/auth.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wm/auth.go b/wm/auth.go index ced853fe..ff8f01ce 100644 --- a/wm/auth.go +++ b/wm/auth.go @@ -57,7 +57,7 @@ type ident struct { Details map[string]dbus.Variant } -func (a *auth) BeginAuthentication(action_id, message, icon_name string, details map[string]string, cookie string, ids []ident, sender dbus.Sender) (err *dbus.Error) { +func (a *auth) BeginAuthentication(actionID, message, iconName string, details map[string]string, cookie string, ids []ident, sender dbus.Sender) (err *dbus.Error) { wg := &sync.WaitGroup{} wg.Add(1) pass := widget.NewPasswordEntry() @@ -157,6 +157,7 @@ func (a *auth) CancelAuthentication(cookie string, sender dbus.Sender) (err *dbu return nil } +// StartAuthAgent asks our policy kit agent to start listening for auth requests. func StartAuthAgent() { a := &auth{windows: make(map[string]fyne.Window)} go a.register() From 61ec176b080e7d0e9604bc706f182a3b07ee6de0 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 3 Jan 2024 17:43:30 +0000 Subject: [PATCH 13/27] Trying new CI config --- .github/workflows/static_analysis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index 96862355..ba75b1c9 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -12,7 +12,7 @@ jobs: persist-credentials: false - uses: WillAbides/setup-go-faster@v1.13.0 with: - go-version: '1.19.x' + go-version: '1.21.x' - name: Get dependencies run: | @@ -20,7 +20,7 @@ jobs: go install golang.org/x/tools/cmd/goimports@latest go install github.com/fzipp/gocyclo/cmd/gocyclo@latest go install golang.org/x/lint/golint@latest - go install honnef.co/go/tools/cmd/staticcheck@v0.2.2 + go install honnef.co/go/tools/cmd/staticcheck@v0.4.6 - name: Cleanup repository run: rm -rf vendor/ From 55ee4d9169de1accb8672abe252ff651afbc9e18 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 3 Jan 2024 17:53:17 +0000 Subject: [PATCH 14/27] Fix deprecated usage --- internal/icon/fdo.go | 14 +++++++------- internal/icon/fdo_test.go | 3 +-- internal/icon/macos.go | 3 +-- internal/ui/notifications.go | 2 +- internal/ui/switcher.go | 2 +- modules/status/battery_other.go | 7 +++---- modules/systray/main.go | 3 +-- 7 files changed, 15 insertions(+), 19 deletions(-) diff --git a/internal/icon/fdo.go b/internal/icon/fdo.go index 2e7d3c34..66edeb49 100644 --- a/internal/icon/fdo.go +++ b/internal/icon/fdo.go @@ -2,7 +2,7 @@ package icon // import "fyshos.com/fynedesk/internal/icon" import ( "bufio" - "io/ioutil" + "io/fs" "math" "os" "os/exec" @@ -124,7 +124,7 @@ func (data fdoApplicationData) mainCategory() string { } func loadIcon(path string) fyne.Resource { - data, err := ioutil.ReadFile(path) + data, err := os.ReadFile(path) if err != nil { fyne.LogError("Failed to load image", err) return nil @@ -154,7 +154,7 @@ func fdoForEachApplicationFile(f func(data fynedesk.AppData) bool) { locationLookup := fdoLookupXdgDataDirs() for _, dataDir := range locationLookup { testLocation := filepath.Join(dataDir, "applications") - files, err := ioutil.ReadDir(testLocation) + files, err := os.ReadDir(testLocation) if err != nil { continue } @@ -211,7 +211,7 @@ func (f *fdoIconProvider) lookupApplication(appName string) fynedesk.AppData { return f.lookupApplicationByMetadata(appName) } -func fdoClosestSizeIcon(files []os.FileInfo, iconSize int, format string, baseDir string, joiner string, iconName string) string { +func fdoClosestSizeIcon(files []fs.DirEntry, iconSize int, format string, baseDir string, joiner string, iconName string) string { var sizes []int for _, f := range files { if format == "32x32" { @@ -270,7 +270,7 @@ func fdoClosestSizeIcon(files []os.FileInfo, iconSize int, format string, baseDi } func lookupAnyIconSizeInThemeDir(dir string, joiner string, iconName string, iconSize int) string { - files, err := ioutil.ReadDir(dir) + files, err := os.ReadDir(dir) if err != nil { return "" } @@ -285,7 +285,7 @@ func lookupAnyIconSizeInThemeDir(dir string, joiner string, iconName string, ico } directory := filepath.Join(dir, joiner) - files, err = ioutil.ReadDir(directory) + files, err = os.ReadDir(directory) if err != nil { return "" } @@ -424,7 +424,7 @@ func fdoLookupAvailableThemes() []string { var themes []string locationLookup := fdoLookupXdgDataDirs() for _, dataDir := range locationLookup { - files, err := ioutil.ReadDir(filepath.Join(dataDir, "icons")) + files, err := os.ReadDir(filepath.Join(dataDir, "icons")) if err != nil { continue } diff --git a/internal/icon/fdo_test.go b/internal/icon/fdo_test.go index 46a5c614..f785bd3f 100644 --- a/internal/icon/fdo_test.go +++ b/internal/icon/fdo_test.go @@ -2,7 +2,6 @@ package icon import ( "fmt" - "io/ioutil" "os" "path/filepath" "testing" @@ -66,7 +65,7 @@ func TestFdoIconNameIsPath(t *testing.T) { setTestEnv(t) dataLocation := os.Getenv("XDG_DATA_DIRS") output := fmt.Sprintf("[Desktop Entry]\nName=App3\nExec=app3\nIcon=%s\n", filepath.Join(dataLocation, "icons", "app3.png")) - err := ioutil.WriteFile(filepath.Join(dataLocation, "applications", "app3.desktop"), []byte(output), 0644) + err := os.WriteFile(filepath.Join(dataLocation, "applications", "app3.desktop"), []byte(output), 0644) if err != nil { fyne.LogError("Could not create desktop for Icon Name path example", err) t.FailNow() diff --git a/internal/icon/macos.go b/internal/icon/macos.go index 9dcd0131..9202910a 100644 --- a/internal/icon/macos.go +++ b/internal/icon/macos.go @@ -4,7 +4,6 @@ import ( "bytes" _ "image/jpeg" // support JPEG images "image/png" // PNG support is required as we use it directly - "io/ioutil" "os" "os/exec" "path/filepath" @@ -109,7 +108,7 @@ type macOSAppProvider struct { func (m *macOSAppProvider) forEachApplication(f func(name, path, category string) bool) { for _, root := range m.rootDirs { category := filepath.Base(root) - files, err := ioutil.ReadDir(root) + files, err := os.ReadDir(root) if err != nil { fyne.LogError("Could not read applications directory "+root, err) return diff --git a/internal/ui/notifications.go b/internal/ui/notifications.go index a907ca75..e12f716d 100644 --- a/internal/ui/notifications.go +++ b/internal/ui/notifications.go @@ -23,7 +23,7 @@ type notification struct { func (n *notification) show(list *fyne.Container) { title := widget.NewLabel(n.message.Title) title.TextStyle = fyne.TextStyle{Bold: true} - title.Wrapping = fyne.TextTruncate + title.Truncation = fyne.TextTruncateEllipsis text := widget.NewLabel(n.message.Body) text.Wrapping = fyne.TextWrapWord n.renderer = container.NewVBox(title, text) diff --git a/internal/ui/switcher.go b/internal/ui/switcher.go index 637d3941..346ef16c 100644 --- a/internal/ui/switcher.go +++ b/internal/ui/switcher.go @@ -42,7 +42,7 @@ func (s *switchIcon) CreateRenderer() fyne.WidgetRenderer { bg.CornerRadius = theme.InputRadiusSize() img := canvas.NewImageFromResource(res) text := widget.NewLabelWithStyle(title, fyne.TextAlignCenter, fyne.TextStyle{}) - text.Wrapping = fyne.TextTruncate + text.Truncation = fyne.TextTruncateEllipsis return &switchIconRenderer{icon: s, bg: bg, img: img, text: text, objects: []fyne.CanvasObject{bg, img, text}} } diff --git a/modules/status/battery_other.go b/modules/status/battery_other.go index 20f1d738..0089bd40 100644 --- a/modules/status/battery_other.go +++ b/modules/status/battery_other.go @@ -4,7 +4,6 @@ package status import ( - "io/ioutil" "os" "strconv" "strings" @@ -13,7 +12,7 @@ import ( ) func (b *battery) powered() (bool, error) { - status, err := ioutil.ReadFile("/sys/class/power_supply/BAT0/status") + status, err := os.ReadFile("/sys/class/power_supply/BAT0/status") if err != nil { return true, err // assume power if no battery info } @@ -23,11 +22,11 @@ func (b *battery) powered() (bool, error) { func (b *battery) value() (float64, error) { nowFile, fullFile := pickChargeOrEnergy() - fullStr, err1 := ioutil.ReadFile(fullFile) + fullStr, err1 := os.ReadFile(fullFile) if os.IsNotExist(err1) { return 0, err1 // return quietly if the file was not present (desktop?) } - nowStr, err2 := ioutil.ReadFile(nowFile) + nowStr, err2 := os.ReadFile(nowFile) if err1 != nil || err2 != nil { fyne.LogError("Error reading battery info", err1) return 0, err1 diff --git a/modules/systray/main.go b/modules/systray/main.go index 5552925b..08cf8f65 100644 --- a/modules/systray/main.go +++ b/modules/systray/main.go @@ -11,7 +11,6 @@ import ( "image" "image/color" "image/png" - "io/ioutil" "log" "os" "path/filepath" @@ -324,7 +323,7 @@ func (t *tray) updateIcon(i *node) { } else { fullPath = icon.FdoLookupIconPath("", 64, name) } - img, err := ioutil.ReadFile(fullPath) + img, err := os.ReadFile(fullPath) if err != nil { fyne.LogError("Failed to load status icon", err) i.ico.SetIcon(wmtheme.BrokenImageIcon) From 618d413f55bf915390922057e36cf580827000ff Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Fri, 12 Jan 2024 23:01:46 +0000 Subject: [PATCH 15/27] Add a confirmation screen when logging out --- internal/ui/menu.go | 47 ++++++++++++++++++++++++++++++++++++++- internal/x11/wm/events.go | 6 +++-- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/internal/ui/menu.go b/internal/ui/menu.go index 3ed29bc4..d178161a 100644 --- a/internal/ui/menu.go +++ b/internal/ui/menu.go @@ -1,12 +1,16 @@ package ui import ( + "fmt" + "image/color" "os" "sort" "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" deskDriver "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/layout" "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" @@ -49,6 +53,47 @@ func (w *widgetPanel) appendAppCategories(acc *widget.Accordion, win fyne.Window acc.Refresh() } +func (w *widgetPanel) askLogout() { + win := fyne.CurrentApp().Driver().(deskDriver.Driver).CreateSplashWindow() + logout := widget.NewButtonWithIcon("Logout", theme.LogoutIcon(), func() { + win.Close() + w.desk.WindowManager().Close() + }) + logout.Importance = widget.DangerImportance + cancel := widget.NewButton("Cancel", func() { + win.Close() + }) + + header := widget.NewRichTextFromMarkdown(fmt.Sprintf("### Log out")) + header.Truncation = fyne.TextTruncateEllipsis + bottomPad := canvas.NewRectangle(color.Transparent) + bottomPad.SetMinSize(fyne.NewSquareSize(10)) + content := container.NewBorder( + header, + container.NewVBox( + container.NewHBox(layout.NewSpacer(), + container.NewGridWithColumns(2, cancel, logout), + layout.NewSpacer()), bottomPad), + nil, nil, + widget.NewLabel("Are you sure you want to log out?")) + + r, g, b, _ := theme.OverlayBackgroundColor().RGBA() + bgCol := &color.NRGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: 230} + + bg := canvas.NewRectangle(bgCol) + icon := canvas.NewImageFromResource(theme.LogoutIcon()) + iconBox := container.NewWithoutLayout(icon) + icon.Resize(fyne.NewSize(92, 92)) + icon.Move(fyne.NewPos(280-92-theme.Padding(), theme.Padding())) + win.SetContent(container.NewStack( + iconBox, bg, + container.NewPadded(content))) + + win.Resize(fyne.NewSize(280, 150)) + win.CenterOnScreen() + win.Show() +} + func (w *widgetPanel) showAccountMenu(_ fyne.CanvasObject) { w2 := fyne.CurrentApp().Driver().(deskDriver.Driver).CreateSplashWindow() w2.Canvas().SetOnTypedKey(func(k *fyne.KeyEvent) { @@ -58,8 +103,8 @@ func (w *widgetPanel) showAccountMenu(_ fyne.CanvasObject) { }) items1 := []fyne.CanvasObject{ &widget.Button{Icon: theme.LogoutIcon(), Importance: widget.DangerImportance, OnTapped: func() { + w.askLogout() w2.Close() - w.desk.WindowManager().Close() }}} isEmbed := w.desk.(*desktop).root.Title() != RootWindowName if !isEmbed { diff --git a/internal/x11/wm/events.go b/internal/x11/wm/events.go index e7537508..b5420be0 100644 --- a/internal/x11/wm/events.go +++ b/internal/x11/wm/events.go @@ -234,8 +234,10 @@ func (x *x11WM) handleMouseEnter(ev xproto.EnterNotifyEvent) { func (x *x11WM) handleMouseLeave(ev xproto.LeaveNotifyEvent) { if ev.Event == x.menuID { // dismiss overlay menus on mouse out x.menuID = 0 - x.menuWin.Close() - x.menuWin = nil + if x.menuWin != nil { + x.menuWin.Close() + x.menuWin = nil + } } for _, c := range x.clients { From 21446dc7c9ce5b320bc60827602e98714a782d09 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sun, 14 Jan 2024 08:31:35 +0000 Subject: [PATCH 16/27] Move windows when changing desktop Animated and much faster :) --- internal/ui/desk.go | 26 ++++++++++++++++++++------ internal/x11/win/client.go | 29 ++++++++++++++++++++++------- test/window.go | 6 +++++- window.go | 1 + 4 files changed, 48 insertions(+), 14 deletions(-) diff --git a/internal/ui/desk.go b/internal/ui/desk.go index dbd4d09e..87c29347 100644 --- a/internal/ui/desk.go +++ b/internal/ui/desk.go @@ -6,6 +6,7 @@ import ( "strconv" "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" deskDriver "fyne.io/fyne/v2/driver/desktop" @@ -46,15 +47,28 @@ func (l *desktop) Desktop() int { } func (l *desktop) SetDesktop(id int) { + diff := id - l.desk l.desk = id - for _, item := range l.wm.Windows() { - if item.Desktop() == id { - item.Uniconify() - } else { - item.Iconify() - } + display := l.Screens().Primary() // TODO need to iterate/find full virtual height + off := float32(diff*-display.Height) / display.Scale + wins := l.wm.Windows() + + starts := make([]fyne.Position, len(wins)) + deltas := make([]fyne.Delta, len(wins)) + for i, win := range wins { + starts[i] = win.Position() + deltas[i] = fyne.NewDelta(0, off) } + + fyne.NewAnimation(canvas.DurationStandard, func(f float32) { + for i, item := range l.wm.Windows() { + newX := starts[i].X + deltas[i].DX*f + newY := starts[i].Y + deltas[i].DY*f + + item.Move(fyne.NewPos(newX, newY)) + } + }).Start() } func (l *desktop) Layout(objects []fyne.CanvasObject, size fyne.Size) { diff --git a/internal/x11/win/client.go b/internal/x11/win/client.go index 7aa97918..54704580 100644 --- a/internal/x11/win/client.go +++ b/internal/x11/win/client.go @@ -6,14 +6,15 @@ package win import ( "image" - "fyne.io/fyne/v2" - "github.com/BurntSushi/xgb/xproto" "github.com/BurntSushi/xgbutil/ewmh" "github.com/BurntSushi/xgbutil/icccm" "github.com/BurntSushi/xgbutil/xevent" "github.com/BurntSushi/xgbutil/xprop" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyshos.com/fynedesk" "fyshos.com/fynedesk/internal/x11" "fyshos.com/fynedesk/wm" @@ -125,12 +126,18 @@ func (c *client) SetDesktop(id int) { } d := fynedesk.Instance() + diff := id - c.desk c.desk = id - if id == d.Desktop() { - c.Uniconify() - } else { - c.Iconify() - } + + display := d.Screens().Primary() // TODO need to iterate/find full virtual height + off := float32(diff*display.Height) / display.Scale + + start := c.Position() + fyne.NewAnimation(canvas.DurationStandard, func(f float32) { + newY := start.Y + off*f + + c.Move(fyne.NewPos(start.X, newY)) + }).Start() } func (c *client) Expose() { @@ -193,6 +200,14 @@ func (c *client) Maximized() bool { return c.maximized } +func (c *client) Move(pos fyne.Position) { + screen := fynedesk.Instance().Screens().ScreenForWindow(c) + + targetX := int16(pos.X * screen.CanvasScale()) + targetY := int16(pos.Y * screen.CanvasScale()) + c.frame.queueGeometry(targetX, targetY, c.frame.width, c.frame.height, false) +} + func (c *client) NotifyBorderChange() { c.props.refreshCache() if c.Properties().Decorated() { diff --git a/test/window.go b/test/window.go index f518d801..1842f6a3 100644 --- a/test/window.go +++ b/test/window.go @@ -3,8 +3,9 @@ package test import ( "image" - "fyne.io/fyne/v2" "fyshos.com/fynedesk" + + "fyne.io/fyne/v2" ) // Window is an in-memory virtual window for test purposes @@ -80,6 +81,9 @@ func (w *Window) Maximized() bool { return false } +// Move the window, does nothing in test windows +func (w *Window) Move(fyne.Position) {} + // Parent returns a window that this should be positioned within, if set. func (w *Window) Parent() fynedesk.Window { return w.parent diff --git a/window.go b/window.go index 1c5c6758..0761655a 100644 --- a/window.go +++ b/window.go @@ -30,6 +30,7 @@ type Window interface { Parent() Window Properties() WindowProperties // Request the properties set on this window Position() fyne.Position + Move(position fyne.Position) Desktop() int SetDesktop(int) From b11df9e07c246e88cc75065679354c991a819de9 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sun, 14 Jan 2024 08:33:05 +0000 Subject: [PATCH 17/27] Update desktop pager UI when desk changes Fixes issue where tapping app icon would move view but not update pager. --- internal/notify/desktop.go | 6 ++++++ internal/ui/desk.go | 8 ++++++++ modules/desktops/desktops.go | 5 +++++ 3 files changed, 19 insertions(+) create mode 100644 internal/notify/desktop.go diff --git a/internal/notify/desktop.go b/internal/notify/desktop.go new file mode 100644 index 00000000..1ed3ce33 --- /dev/null +++ b/internal/notify/desktop.go @@ -0,0 +1,6 @@ +package notify + +// DesktopNotify allows modules to be informed when user changes virtual desktop +type DesktopNotify interface { + DesktopChangeNotify(int) +} diff --git a/internal/ui/desk.go b/internal/ui/desk.go index 87c29347..c82ea12c 100644 --- a/internal/ui/desk.go +++ b/internal/ui/desk.go @@ -5,6 +5,8 @@ import ( "os/exec" "strconv" + "fyshos.com/fynedesk/internal/notify" + "fyne.io/fyne/v2" "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" @@ -69,6 +71,12 @@ func (l *desktop) SetDesktop(id int) { item.Move(fyne.NewPos(newX, newY)) } }).Start() + + for _, m := range l.Modules() { + if desk, ok := m.(notify.DesktopNotify); ok { + desk.DesktopChangeNotify(id) + } + } } func (l *desktop) Layout(objects []fyne.CanvasObject, size fyne.Size) { diff --git a/modules/desktops/desktops.go b/modules/desktops/desktops.go index 4d518a6a..d3d89bd7 100644 --- a/modules/desktops/desktops.go +++ b/modules/desktops/desktops.go @@ -20,6 +20,11 @@ type desktops struct { gui *pager } +func (d *desktops) DesktopChangeNotify(id int) { + d.current = id + d.gui.refresh() +} + func (d *desktops) Destroy() { } From a9d9cca0dda1c728b82a4fa846a2636c98956bf4 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sun, 14 Jan 2024 21:04:57 +0000 Subject: [PATCH 18/27] Just apply directly to avoid more queues --- internal/x11/win/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/x11/win/client.go b/internal/x11/win/client.go index 54704580..8be82fb9 100644 --- a/internal/x11/win/client.go +++ b/internal/x11/win/client.go @@ -205,7 +205,7 @@ func (c *client) Move(pos fyne.Position) { targetX := int16(pos.X * screen.CanvasScale()) targetY := int16(pos.Y * screen.CanvasScale()) - c.frame.queueGeometry(targetX, targetY, c.frame.width, c.frame.height, false) + c.frame.updateGeometry(targetX, targetY, c.frame.width, c.frame.height, false) } func (c *client) NotifyBorderChange() { From 6458c7b8e39fa15d308908e72af93ed39f09c18f Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sun, 14 Jan 2024 21:40:54 +0000 Subject: [PATCH 19/27] Scroll across multiple monitors Use the virtual space extents instead of primary screen. --- desk.go | 1 + internal/ui/desk.go | 23 +++++++++++++++++++++-- internal/x11/win/client.go | 6 ++++-- test/desktop.go | 6 +++++- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/desk.go b/desk.go index 1d30348e..05a1ad50 100644 --- a/desk.go +++ b/desk.go @@ -9,6 +9,7 @@ type Desktop interface { RecentApps() []AppData Settings() DeskSettings ContentBoundsPixels(*Screen) (x, y, w, h uint32) + RootSizePixels() (w, h uint32) Screens() ScreenList IconProvider() ApplicationProvider diff --git a/internal/ui/desk.go b/internal/ui/desk.go index c82ea12c..32d919b4 100644 --- a/internal/ui/desk.go +++ b/internal/ui/desk.go @@ -52,14 +52,17 @@ func (l *desktop) SetDesktop(id int) { diff := id - l.desk l.desk = id - display := l.Screens().Primary() // TODO need to iterate/find full virtual height - off := float32(diff*-display.Height) / display.Scale + _, height := l.RootSizePixels() + offPix := float32(diff * -int(height)) wins := l.wm.Windows() starts := make([]fyne.Position, len(wins)) deltas := make([]fyne.Delta, len(wins)) for i, win := range wins { starts[i] = win.Position() + + display := l.Screens().ScreenForWindow(win) + off := offPix / display.Scale deltas[i] = fyne.NewDelta(0, off) } @@ -193,6 +196,22 @@ func (l *desktop) ContentBoundsPixels(screen *fynedesk.Screen) (x, y, w, h uint3 return 0, 0, screenW, screenH } +func (l *desktop) RootSizePixels() (w, h uint32) { + for _, screen := range l.Screens().Screens() { + right := uint32(screen.X + screen.Width) + bottom := uint32(screen.Y + screen.Height) + + if right > w { + w = right + } + if bottom > h { + h = bottom + } + } + + return w, h +} + func (l *desktop) IconProvider() fynedesk.ApplicationProvider { return l.icons } diff --git a/internal/x11/win/client.go b/internal/x11/win/client.go index 8be82fb9..3106b6ba 100644 --- a/internal/x11/win/client.go +++ b/internal/x11/win/client.go @@ -129,8 +129,10 @@ func (c *client) SetDesktop(id int) { diff := id - c.desk c.desk = id - display := d.Screens().Primary() // TODO need to iterate/find full virtual height - off := float32(diff*display.Height) / display.Scale + _, height := d.RootSizePixels() + offPix := float32(diff * -int(height)) + display := d.Screens().ScreenForWindow(c) + off := offPix / display.Scale start := c.Position() fyne.NewAnimation(canvas.DurationStandard, func(f float32) { diff --git a/test/desktop.go b/test/desktop.go index 7a10e3d1..aea75370 100644 --- a/test/desktop.go +++ b/test/desktop.go @@ -45,7 +45,11 @@ func (*Desktop) Capture() image.Image { // ContentBoundsPixels returns a default value for how much space maximised apps should use func (*Desktop) ContentBoundsPixels(_ *fynedesk.Screen) (x, y, w, h uint32) { - return 0, 0, uint32(320), uint32(240) + return 0, 0, 320, 240 +} + +func (*Desktop) RootSizePixels() (w, h uint32) { + return 320, 240 } // Desktop returns the index of the current desktop (in test this is always 0) From 981bb1f681e67c90b486b96c8d523b300c651289 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sun, 14 Jan 2024 21:49:46 +0000 Subject: [PATCH 20/27] Add missing doc --- test/desktop.go | 1 + 1 file changed, 1 insertion(+) diff --git a/test/desktop.go b/test/desktop.go index aea75370..af53ac11 100644 --- a/test/desktop.go +++ b/test/desktop.go @@ -48,6 +48,7 @@ func (*Desktop) ContentBoundsPixels(_ *fynedesk.Screen) (x, y, w, h uint32) { return 0, 0, 320, 240 } +// RootSizePixels returns the total number of pixels required to fit all the screens func (*Desktop) RootSizePixels() (w, h uint32) { return 320, 240 } From 75132c0703c8e2626ab80813b349973eca194a10 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sun, 14 Jan 2024 21:53:50 +0000 Subject: [PATCH 21/27] Fix static warning --- internal/ui/menu.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/ui/menu.go b/internal/ui/menu.go index d178161a..31983d59 100644 --- a/internal/ui/menu.go +++ b/internal/ui/menu.go @@ -1,7 +1,6 @@ package ui import ( - "fmt" "image/color" "os" "sort" @@ -64,7 +63,7 @@ func (w *widgetPanel) askLogout() { win.Close() }) - header := widget.NewRichTextFromMarkdown(fmt.Sprintf("### Log out")) + header := widget.NewRichTextFromMarkdown("### Log out") header.Truncation = fyne.TextTruncateEllipsis bottomPad := canvas.NewRectangle(color.Transparent) bottomPad.SetMinSize(fyne.NewSquareSize(10)) From 5e3a2c4c13b53d04fbc1daf57f2c4c62d0d27188 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 15 Jan 2024 19:53:04 +0000 Subject: [PATCH 22/27] Update Fyne and go mod files --- go.mod | 31 +++++++++++------------ go.sum | 78 ++++++++++++++++++++++------------------------------------ 2 files changed, 44 insertions(+), 65 deletions(-) diff --git a/go.mod b/go.mod index 27683bbb..f8b37e2b 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,7 @@ module fyshos.com/fynedesk go 1.17 require ( - fyne.io/fyne/v2 v2.4.0 - github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298 // indirect - github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 // indirect + fyne.io/fyne/v2 v2.4.4-0.20240107115323-8458aff4b006 github.com/BurntSushi/xgb v0.0.0-20201008132610-5f9e7b3c49cd github.com/BurntSushi/xgbutil v0.0.0-20160919175755-f7c97cef3b4e github.com/FyshOS/backgrounds v0.0.0-20230616202904-0a8b6ebaa184 @@ -21,14 +19,16 @@ require ( ) require ( - fyne.io/systray v1.10.1-0.20230722100817-88df1e0ffa9a // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/fredbi/uri v1.0.0 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + fyne.io/systray v1.10.1-0.20231230205326-d160fd363db9 // indirect + github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298 // indirect + github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/fredbi/uri v1.1.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe // indirect - github.com/fyne-io/glfw-js v0.0.0-20220120001248-ee7290d23504 // indirect + github.com/fyne-io/glfw-js v0.0.0-20240101223322-6e1efdc71b7a // indirect github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 // indirect - github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b // indirect + github.com/go-gl/glfw/v3.3/glfw v0.0.0-20231223183121-56fa3ac82ce7 // indirect github.com/go-text/render v0.0.0-20230619120952-35bccb6164b8 // indirect github.com/go-text/typesetting v0.0.0-20230616162802-9c17dd34aa4a // indirect github.com/gopherjs/gopherjs v1.17.2 // indirect @@ -36,18 +36,17 @@ require ( github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/pkg/errors v0.8.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rymdport/portal v0.0.0-20231123202536-da45518a87bb // indirect github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect - github.com/tevino/abool v1.2.0 // indirect github.com/yuin/goldmark v1.5.5 // indirect - golang.org/x/image v0.11.0 // indirect - golang.org/x/mobile v0.0.0-20230531173138-3c911d8e3eda // indirect - golang.org/x/net v0.14.0 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/text v0.12.0 // indirect + golang.org/x/image v0.14.0 // indirect + golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - honnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2 // indirect ) replace github.com/BurntSushi/xgbutil => github.com/fyne-io/xgbutil v0.0.0-20191220152344-7d838166824d diff --git a/go.sum b/go.sum index e52f76be..612135a3 100644 --- a/go.sum +++ b/go.sum @@ -37,10 +37,10 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -fyne.io/fyne/v2 v2.4.0 h1:LlyOyHmvkSo9IBm3aY+NVWSBIw+GMnssmyyIMK8F7zM= -fyne.io/fyne/v2 v2.4.0/go.mod h1:AWM1iPM2YfliduZ4u/kQzP9E6ARIWm0gg+57GpYzWro= -fyne.io/systray v1.10.1-0.20230722100817-88df1e0ffa9a h1:6Xf9fP3/mt72NrqlQhJWhQGcNf6GoG9X96NTaXr+K6A= -fyne.io/systray v1.10.1-0.20230722100817-88df1e0ffa9a/go.mod h1:oM2AQqGJ1AMo4nNqZFYU8xYygSBZkW2hmdJ7n4yjedE= +fyne.io/fyne/v2 v2.4.4-0.20240107115323-8458aff4b006 h1:7zQ59DzG2vWbcHvE/ElPhrkP5Qy8CO15fJenSm22v74= +fyne.io/fyne/v2 v2.4.4-0.20240107115323-8458aff4b006/go.mod h1:lcFfOoGu75+eS+ERtXM8OZQy+czyIfHxohlc9wSCslE= +fyne.io/systray v1.10.1-0.20231230205326-d160fd363db9 h1:E/gHmMVyk8TuI6JIgNIv/Qu1JABMVFBIkQ8lYRa5gkQ= +fyne.io/systray v1.10.1-0.20231230205326-d160fd363db9/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs= github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298 h1:1qlsVAQJXZHsaM8b6OLVo6muQUQd4CwkH/D3fnnbHXA= github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298/go.mod h1:D+QujdIlUNfa0igpNMk6UIvlb6C252URs4yupRUV4lQ= github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 h1:lTG4HQym5oPKjL7nGs+csTgiDna685ZXjxijkne828g= @@ -71,8 +71,9 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -83,15 +84,16 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fredbi/uri v1.0.0 h1:s4QwUAZ8fz+mbTsukND+4V5f+mJ/wjaTokwstGUAemg= -github.com/fredbi/uri v1.0.0/go.mod h1:1xC40RnIOGCaQzswaOvrzvG/3M3F0hyDVb3aO/1iGy0= +github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= +github.com/fredbi/uri v1.1.0 h1:OqLpTXtyRg9ABReqvDGdJPqZUxs8cyBDOMXBbskCaB8= +github.com/fredbi/uri v1.1.0/go.mod h1:aYTUoAXBOq7BLfVJ8GnKmfcuURosB1xyHDIfWeC/iW4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe h1:A/wiwvQ0CAjPkuJytaD+SsXkPU0asQ+guQEIg1BJGX4= github.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe/go.mod h1:d4clgH0/GrRwWjRzJJQXxT/h1TyuNSfF/X64zb/3Ggg= -github.com/fyne-io/glfw-js v0.0.0-20220120001248-ee7290d23504 h1:+31CdF/okdokeFNoy9L/2PccG3JFidQT3ev64/r4pYU= -github.com/fyne-io/glfw-js v0.0.0-20220120001248-ee7290d23504/go.mod h1:gLRWYfYnMA9TONeppRSikMdXlHQ97xVsPojddUv3b/E= +github.com/fyne-io/glfw-js v0.0.0-20240101223322-6e1efdc71b7a h1:ybgRdYvAHTn93HW79bLiBiJwVL4jVeyGQRZMgImoeWs= +github.com/fyne-io/glfw-js v0.0.0-20240101223322-6e1efdc71b7a/go.mod h1:gsGA2dotD4v0SR6PmPCYvS9JuOeMwAtmfvDE7mbYXMY= github.com/fyne-io/image v0.0.0-20221020213044-f609c6a24345 h1:ONkcbJmsWUOHyjUm0wlnkFc/uaacFFtStVbsG6qJfew= github.com/fyne-io/image v0.0.0-20221020213044-f609c6a24345/go.mod h1:eO7W361vmlPOrykIg+Rsh1SZ3tQBaOsfzZhsIOb/Lm0= github.com/fyne-io/xgbutil v0.0.0-20191220152344-7d838166824d h1:8+poQtDqiRfAZmeyYRlInuaIBsQEflmxtpJeZklvNuE= @@ -102,9 +104,8 @@ github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6/go.mod h1:9YTyiznxEY1fVin github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211213063430-748e38ca8aec/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b h1:GgabKamyOYguHqHjSkDACcgoPIz3w0Dis/zJ1wyHHHU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20231223183121-56fa3ac82ce7 h1:7tf/0aw5DxRQjr7WaNqgtjidub6v21L2cogKIbMcTYw= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20231223183121-56fa3ac82ce7/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-text/render v0.0.0-20230619120952-35bccb6164b8 h1:VkKnvzbvHqgEfm351rfr8Uclu5fnwq8HP2ximUzJsBM= github.com/go-text/render v0.0.0-20230619120952-35bccb6164b8/go.mod h1:h29xCucjNsDcYb7+0rJokxVwYAq+9kQ19WiFuBKkYtc= github.com/go-text/typesetting v0.0.0-20230616162802-9c17dd34aa4a h1:VjN8ttdfklC0dnAdKbZqGNESdERUxtE3l8a/4Grgarc= @@ -172,6 +173,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -181,7 +183,6 @@ github.com/gopherjs/gopherjs v0.0.0-20211219123610-ec9572f70e60/go.mod h1:cz9oNY github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/goxjs/gl v0.0.0-20210104184919-e3fafc6f8f2a/go.mod h1:dy/f2gjY09hwVfIyATps4G2ai7/hLwLkc5TrPqONuXY= -github.com/goxjs/glfw v0.0.0-20191126052801-d2efb5f20838/go.mod h1:oS8P8gVOT4ywTcjV6wZlOU4GuVFQ8F5328KY3MJ79CY= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= @@ -250,6 +251,7 @@ github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -259,6 +261,8 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/rymdport/portal v0.0.0-20231123202536-da45518a87bb h1:ejEomhJX7G4p8dFImv2zcQd2Oa0IpWIeB/FUZRnpQKg= +github.com/rymdport/portal v0.0.0-20231123202536-da45518a87bb/go.mod h1:RYYAnv4sssTQ7ceErKl7UD8auER/0yFV7CgmfS/uAD8= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= @@ -279,7 +283,6 @@ github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ= github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -287,19 +290,15 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA= -github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.5.5 h1:IJznPe8wOzfIKETmMkd06F8nXkmlhaHqFRM9l1hAGsU= github.com/yuin/goldmark v1.5.5/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= @@ -323,7 +322,6 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -338,8 +336,8 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo= -golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8= +golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4= +golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -355,8 +353,8 @@ golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mobile v0.0.0-20211207041440-4e6c2922fdee/go.mod h1:pe2sM7Uk+2Su1y7u/6Z8KJ24D7lepUjFZbhFOrmDfuQ= -golang.org/x/mobile v0.0.0-20230531173138-3c911d8e3eda h1:O+EUvnBNPwI4eLthn8W5K+cS8zQZfgTABPLNm6Bna34= -golang.org/x/mobile v0.0.0-20230531173138-3c911d8e3eda/go.mod h1:aAjjkJNdrh3PMckS4B10TGS2nag27cbKR1y2BpUxsiY= +golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a h1:sYbmY3FwUWCBTodZL1S3JUuOvaW6kM2o+clDzzDNBWg= +golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a/go.mod h1:Ede7gF0KGoHlj822RtphAHK1jLdrcuRBZg0sF1Q+SPc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= @@ -366,8 +364,6 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -405,10 +401,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -432,8 +426,6 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -479,15 +471,9 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -496,10 +482,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +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.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -556,8 +540,6 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -679,8 +661,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2 h1:oomkgU6VaQDsV6qZby2uz1Lap0eXmku8+2em3A/l700= -honnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2/go.mod h1:sUMDUKNB2ZcVjt92UnLy3cdGs+wDAcrPdV3JP6sVgA4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From b9aa17af3a2119cf567e6e04eecc9544b96b04c3 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 15 Jan 2024 19:56:34 +0000 Subject: [PATCH 23/27] Removing more error checks to speed up --- internal/x11/wm/desk.go | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/internal/x11/wm/desk.go b/internal/x11/wm/desk.go index 3a612656..80810fcf 100644 --- a/internal/x11/wm/desk.go +++ b/internal/x11/wm/desk.go @@ -478,20 +478,14 @@ func (x *x11WM) configureRoots() { xproto.SendEvent(x.x.Conn(), false, x.rootID, xproto.EventMaskStructureNotify, string(notifyEv.Bytes())) // we need to trigger a move so that the correct scale is picked up - err = xproto.ConfigureWindowChecked(x.x.Conn(), x.rootID, xproto.ConfigWindowX|xproto.ConfigWindowY| + xproto.ConfigureWindow(x.x.Conn(), x.rootID, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{uint32(screen.X + 1), uint32(screen.Y + 1), uint32(screen.Width - 2), uint32(screen.Height - 2)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } + []uint32{uint32(screen.X + 1), uint32(screen.Y + 1), uint32(screen.Width - 2), uint32(screen.Height - 2)}) // and then set the correct location - err = xproto.ConfigureWindowChecked(x.x.Conn(), x.rootID, xproto.ConfigWindowX|xproto.ConfigWindowY| + xproto.ConfigureWindow(x.x.Conn(), x.rootID, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{uint32(screen.X), uint32(screen.Y), uint32(screen.Width), uint32(screen.Height)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } + []uint32{uint32(screen.X), uint32(screen.Y), uint32(screen.Width), uint32(screen.Height)}) } } @@ -547,12 +541,9 @@ func (x *x11WM) configureWindow(win xproto.Window, ev xproto.ConfigureRequestEve x.configureRoots() // we added a root window, so reconfigure return } - err := xproto.ConfigureWindowChecked(x.x.Conn(), win, xproto.ConfigWindowX|xproto.ConfigWindowY| + xproto.ConfigureWindow(x.x.Conn(), win, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, - []uint32{uint32(xcoord), uint32(ycoord), uint32(width), uint32(height)}).Check() - if err != nil { - fyne.LogError("Configure Window Error", err) - } + []uint32{uint32(xcoord), uint32(ycoord), uint32(width), uint32(height)}) } func (x *x11WM) destroyWindow(win xproto.Window) { @@ -653,11 +644,8 @@ func (x *x11WM) setActiveScreenFromWindow(win fynedesk.Window) { } func (x *x11WM) setInitialWindowAttributes(win xproto.Window) { - err := xproto.ChangeWindowAttributesChecked(x.x.Conn(), win, xproto.CwCursor, - []uint32{uint32(x11.DefaultCursor)}).Check() - if err != nil { - fyne.LogError("Set Cursor Error", err) - } + xproto.ChangeWindowAttributes(x.x.Conn(), win, xproto.CwCursor, + []uint32{uint32(x11.DefaultCursor)}) } func (x *x11WM) setupBindings() { @@ -738,7 +726,7 @@ func (x *x11WM) showWindow(win xproto.Window, parent xproto.Window) { screen := fynedesk.Instance().Screens().Primary() w, h := x.menuSize.Width*screen.CanvasScale(), x.menuSize.Height*screen.CanvasScale() mx, my := screen.X+int(x.menuPos.X*screen.CanvasScale()), screen.Y+int(x.menuPos.Y*screen.CanvasScale()) - xproto.ConfigureWindowChecked(x.Conn(), win, xproto.ConfigWindowX|xproto.ConfigWindowY| + xproto.ConfigureWindow(x.Conn(), win, xproto.ConfigWindowX|xproto.ConfigWindowY| xproto.ConfigWindowWidth|xproto.ConfigWindowHeight, []uint32{uint32(mx), uint32(my), uint32(w), uint32(h)}) From 95ecf15439599f29b77912444e7ef6e0ea3c3f01 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 15 Jan 2024 19:57:18 +0000 Subject: [PATCH 24/27] Tweaks to menu and switcher to look a bit better --- internal/ui/switcher.go | 5 +++++ internal/x11/wm/desk.go | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/internal/ui/switcher.go b/internal/ui/switcher.go index 346ef16c..6bd6dcaf 100644 --- a/internal/ui/switcher.go +++ b/internal/ui/switcher.go @@ -4,6 +4,8 @@ import ( "image/color" "time" + wmTheme "fyshos.com/fynedesk/theme" + "fyne.io/fyne/v2" "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" @@ -37,6 +39,9 @@ func (s *switchIcon) CreateRenderer() fyne.WidgetRenderer { } else { res = s.win.Properties().Icon() } + if res == nil { + res = wmTheme.BrokenImageIcon + } bg := canvas.NewRectangle(color.Transparent) bg.CornerRadius = theme.InputRadiusSize() diff --git a/internal/x11/wm/desk.go b/internal/x11/wm/desk.go index 80810fcf..19b687db 100644 --- a/internal/x11/wm/desk.go +++ b/internal/x11/wm/desk.go @@ -261,6 +261,14 @@ func (x *x11WM) ShowMenuOverlay(m *fyne.Menu, s fyne.Size, p fyne.Position) { pop.OnDismiss = win.Close pop.Show() pop.Resize(s) + go func() { + // TODO figure why sometimes this doesn't draw (size and minsize are correct) + // and then remove this workaround goroutine + time.Sleep(time.Second / 10) + pop.Resize(s) + time.Sleep(time.Second / 4) + pop.Resize(s) + }() x.ShowOverlay(win, s, p) } From 227f8011b09f003eff6fe06d8b41fc187dd96165 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 15 Jan 2024 20:01:33 +0000 Subject: [PATCH 25/27] Desktop arrangement is up/down now by default --- modules/desktops/desktops.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/desktops/desktops.go b/modules/desktops/desktops.go index d3d89bd7..ca4fce6e 100644 --- a/modules/desktops/desktops.go +++ b/modules/desktops/desktops.go @@ -42,13 +42,13 @@ func (d *desktops) Shortcuts() map[*fynedesk.Shortcut]func() { } } - mapping[&fynedesk.Shortcut{Name: "Switch to Previous Desktop", KeyName: fyne.KeyLeft, Modifier: fynedesk.UserModifier}] = func() { + mapping[&fynedesk.Shortcut{Name: "Switch to Previous Desktop", KeyName: fyne.KeyUp, Modifier: fynedesk.UserModifier}] = func() { if d.current == 0 { return } d.setDesktop(d.current - 1) } - mapping[&fynedesk.Shortcut{Name: "Switch to Next Desktop", KeyName: fyne.KeyRight, Modifier: fynedesk.UserModifier}] = func() { + mapping[&fynedesk.Shortcut{Name: "Switch to Next Desktop", KeyName: fyne.KeyDown, Modifier: fynedesk.UserModifier}] = func() { if d.current == deskCount-1 { return } From e5bad782a7c46f204a8ffeb45aae5506f996af25 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 15 Jan 2024 20:28:47 +0000 Subject: [PATCH 26/27] Better defaults :) --- internal/ui/settings.go | 6 +++--- internal/x11/wm/desk.go | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/internal/ui/settings.go b/internal/ui/settings.go index d5887b91..13f29ed1 100644 --- a/internal/ui/settings.go +++ b/internal/ui/settings.go @@ -234,13 +234,13 @@ func (d *deskSettings) load() { d.launcherZoomScale = 2.0 } - moduleNames := fyne.CurrentApp().Preferences().StringWithFallback("modulenames", "Battery|Brightness|Compositor|Sound|Launcher: Calculate|Launcher: Open URLs|Network|Virtual Desktops") + moduleNames := fyne.CurrentApp().Preferences().StringWithFallback("modulenames", "Battery|Brightness|Compositor|Sound|Launcher: Calculate|Launcher: Open URLs|Network|Virtual Desktops|SystemTray") if moduleNames != "" { d.moduleNames = strings.Split(moduleNames, "|") } d.modifier = fyne.KeyModifier(fyne.CurrentApp().Preferences().IntWithFallback("keyboardmodifier", int(fyne.KeyModifierSuper))) - d.narrowLeftLauncher = fyne.CurrentApp().Preferences().Bool("launchernarrowleft") - d.narrowPanel = fyne.CurrentApp().Preferences().Bool("narrowpanel") + d.narrowLeftLauncher = fyne.CurrentApp().Preferences().BoolWithFallback("launchernarrowleft", true) + d.narrowPanel = fyne.CurrentApp().Preferences().BoolWithFallback("narrowpanel", true) d.borderButtonPosition = fyne.CurrentApp().Preferences().StringWithFallback("borderbuttonposition", "Left") diff --git a/internal/x11/wm/desk.go b/internal/x11/wm/desk.go index 19b687db..3b190a86 100644 --- a/internal/x11/wm/desk.go +++ b/internal/x11/wm/desk.go @@ -93,6 +93,8 @@ const ( keyCodeEnter = 108 keyCodeLeft = 113 keyCodeRight = 114 + keyCodeUp = 111 + keyCodeDown = 116 keyCodeBrightLess = 232 keyCodeBrightMore = 233 @@ -333,6 +335,10 @@ func (x *x11WM) keyNameToCode(n fyne.KeyName) xproto.Keycode { return keyCodeLeft case fyne.KeyRight: return keyCodeRight + case fyne.KeyUp: + return keyCodeUp + case fyne.KeyDown: + return keyCodeDown case deskDriver.KeyPrintScreen: return keyCodePrintScreen case fyne.KeyTab: From ca3bca0c40a833df8ac3a90b0d2021eb2304646b Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 17 Jan 2024 09:33:17 +0000 Subject: [PATCH 27/27] Don't try and load systray on macOS or Windows test platforms --- internal/ui/settings.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/internal/ui/settings.go b/internal/ui/settings.go index 13f29ed1..8a5efae5 100644 --- a/internal/ui/settings.go +++ b/internal/ui/settings.go @@ -2,6 +2,7 @@ package ui import ( "os" + "runtime" "strings" "sync" @@ -234,7 +235,11 @@ func (d *deskSettings) load() { d.launcherZoomScale = 2.0 } - moduleNames := fyne.CurrentApp().Preferences().StringWithFallback("modulenames", "Battery|Brightness|Compositor|Sound|Launcher: Calculate|Launcher: Open URLs|Network|Virtual Desktops|SystemTray") + defaultModules := "Battery|Brightness|Compositor|Sound|Launcher: Calculate|Launcher: Open URLs|Network|Virtual Desktops|SystemTray" + if runtime.GOOS == "darwin" || runtime.GOOS == "windows" { // testing + defaultModules = "Battery|Brightness|Sound|Launcher: Calculate|Launcher: Open URLs|Network|Virtual Desktops" + } + moduleNames := fyne.CurrentApp().Preferences().StringWithFallback("modulenames", defaultModules) if moduleNames != "" { d.moduleNames = strings.Split(moduleNames, "|") }