From 77faf190d8ba16f017a929621ee1e9dd0cf73440 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Tue, 21 Jan 2025 10:15:21 +0000 Subject: [PATCH 01/16] Add option to use FyshOS screen saver Make it the default. And include it in the embedded mode too. --- desk.go | 3 ++ go.mod | 1 + go.sum | 2 + internal/ui/desk.go | 88 +++++++++++++++++++++++++++------- internal/ui/embed_wm.go | 63 +++++++++++++++++++++++- internal/ui/menu.go | 8 ++-- internal/ui/settings.go | 43 +++++++++++++++++ internal/ui/settings_ui.go | 19 +++++++- internal/x11/wm/desk.go | 7 ++- internal/x11/wm/screensaver.go | 62 ++++++++++++++++++++++++ settings.go | 3 ++ test/desktop.go | 4 ++ test/settings.go | 15 +++++- wm.go | 4 ++ 14 files changed, 295 insertions(+), 27 deletions(-) create mode 100644 internal/x11/wm/screensaver.go diff --git a/desk.go b/desk.go index 900b00a0..2e89b2c7 100644 --- a/desk.go +++ b/desk.go @@ -25,6 +25,9 @@ type Desktop interface { Desktop() int SetDesktop(int) + + DelayScreensaver() + TriggerScreensaver(bool) } var instance Desktop diff --git a/go.mod b/go.mod index dda53a64..a1ce6819 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/BurntSushi/xgbutil v0.0.0-20160919175755-f7c97cef3b4e github.com/FyshOS/appie v0.0.0-20250103204932-22db4d5f2ac4 github.com/FyshOS/backgrounds v0.0.0-20230616202904-0a8b6ebaa184 + github.com/FyshOS/saver v0.0.0-20250121095006-5664671ee7e6 github.com/Knetic/govaluate v3.0.0+incompatible github.com/disintegration/imaging v1.6.2 github.com/godbus/dbus/v5 v5.1.0 diff --git a/go.sum b/go.sum index 5be5855f..986a4c6f 100644 --- a/go.sum +++ b/go.sum @@ -59,6 +59,8 @@ github.com/FyshOS/appie v0.0.0-20250103204932-22db4d5f2ac4 h1:lVFM6baY1PmVRonsFc github.com/FyshOS/appie v0.0.0-20250103204932-22db4d5f2ac4/go.mod h1:Gtvb1fKDXbE9HjMtoYdB2MPSSGy6PdtMl0TC9dSF8q0= github.com/FyshOS/backgrounds v0.0.0-20230616202904-0a8b6ebaa184 h1:Za0NHFsT0CCXf/X4hEaywjvEECccrM/xVVL8BzAy6JI= github.com/FyshOS/backgrounds v0.0.0-20230616202904-0a8b6ebaa184/go.mod h1:cOUmJ3HUVmH3W3u9Gj5hM73ZgrDxGNHKMr5T/sBKqLU= +github.com/FyshOS/saver v0.0.0-20250121095006-5664671ee7e6 h1:jxlIwF6vRAmpFfQ3yMvgzz1St7EATnAe4NRELD/WgCM= +github.com/FyshOS/saver v0.0.0-20250121095006-5664671ee7e6/go.mod h1:yIuAuYqnEyKaiNU4MD4xmyLcZl9QdDr2uTmT7lt02tI= github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg= github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= diff --git a/internal/ui/desk.go b/internal/ui/desk.go index dcc8d3af..77e84a0f 100644 --- a/internal/ui/desk.go +++ b/internal/ui/desk.go @@ -4,14 +4,18 @@ import ( "math" "os/exec" "strconv" + "time" "fyshos.com/fynedesk/internal/notify" "github.com/FyshOS/appie" + "github.com/FyshOS/saver" "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/theme" + "fyne.io/fyne/v2/widget" "fyshos.com/fynedesk" wmtheme "fyshos.com/fynedesk/theme" @@ -115,7 +119,12 @@ func (l *desktop) ShowMenuAt(menu *fyne.Menu, pos fyne.Position) { } func (l *desktop) updateBackgrounds(path string) { - l.root.Content().(*fyne.Container).Objects[0].(*background).updateBackground(path) + root := l.root.Content().(*fyne.Container).Objects[0] + if back, ok := root.(*background); ok { + back.updateBackground(path) + } else { // embed mode has another container + root.(*fyne.Container).Objects[0].(*background).updateBackground(path) + } } func (l *desktop) createPrimaryContent() fyne.CanvasObject { @@ -150,6 +159,7 @@ func (l *desktop) RecentApps() []appie.AppData { func (l *desktop) Run() { go l.wm.Run() + go l.watchScreenActivity() l.run() // use the configured run method } @@ -353,7 +363,9 @@ func (l *desktop) registerShortcuts() { l.AddShortcut(fynedesk.NewShortcut("Calculator", fynedesk.KeyCalculator, 0), l.calculator) l.AddShortcut(fynedesk.NewShortcut("Lock screen", fyne.KeyL, fynedesk.UserModifier), - l.lockScreen) + func() { + l.TriggerScreensaver(true) + }) } func (l *desktop) startXscreensaver() { @@ -368,6 +380,44 @@ func (l *desktop) startXscreensaver() { } } +func (l *desktop) TriggerScreensaver(lock bool) { + s := saver.NewScreenSaver(nil) + s.ClockFormat = l.settings.ClockFormatting() + if l.settings.ScreenSaverClock() { + s.Label = "(clock)" + } else { + s.Label = l.settings.ScreenSaverLabel() + } + s.Lock = lock + + l.wm.ShowScreensaver(s) +} + +var lastActivity time.Time + +func (l *desktop) DelayScreensaver() { + lastActivity = time.Now() +} + +var idle bool + +func (l *desktop) watchScreenActivity() { + to := time.NewTicker(5 * time.Second) + + for range to.C { + if lastActivity.Add(time.Minute * 5).Before(time.Now()) { + + if !idle { + idle = true + + l.TriggerScreensaver(false) + } + } else { + idle = false + } + } +} + // Screens returns the screens provider of the current desktop environment for access to screen functionality. func (l *desktop) Screens() fynedesk.ScreenList { return l.screens @@ -384,7 +434,9 @@ func NewDesktop(app fyne.App, mgr fynedesk.WindowManager, icons appie.Provider, desk.setupRoot() wm.StartAuthAgent() - go desk.startXscreensaver() + if desk.Settings().ScreenSaverType() == "XScreensaver" { + go desk.startXscreensaver() + } return desk } @@ -398,7 +450,8 @@ func NewEmbeddedDesktop(app fyne.App, icons appie.Provider) fynedesk.Desktop { desk.showMenu = desk.showMenuEmbed desk.root = desk.newDesktopWindowEmbed() - desk.root.SetContent(desk.createPrimaryContent()) + over := wm.setWindow(desk.root) + desk.root.SetContent(container.NewStack(desk.createPrimaryContent(), over)) return desk } @@ -421,16 +474,17 @@ func (l *desktop) calculator() { } } -func (l *desktop) lockScreen() { - _, err := exec.LookPath("xscreensaver-command") - if err != nil { - fyne.LogError("xscreensaver-command not found", err) - l.WindowManager().Blank() - return - } - err = exec.Command("xscreensaver-command", "-lock").Start() - if err != nil { - fyne.LogError("Failed to lock screen", err) - l.WindowManager().Blank() - } -} +//func (l *desktop) runCommand() { +// w := l.app.NewWindow("Run Command") +// input := widget.NewEntry() +// // TODO add history etc... +// run := widget.NewButton("Run", func() { +// +// }) +// run.Importance = widget.HighImportance +// +// w.SetContent(container.NewVBox(widget.NewLabel("Enter command to run:"), +// container.NewBorder(nil, nil, nil, run, input))) +// w.Resize(fyne.NewSize(250, 40)) +// w.Show() +//} diff --git a/internal/ui/embed_wm.go b/internal/ui/embed_wm.go index 3761a6aa..1f38acc5 100644 --- a/internal/ui/embed_wm.go +++ b/internal/ui/embed_wm.go @@ -2,14 +2,21 @@ package ui import ( "image" - - "fyne.io/fyne/v2" + "image/color" "fyshos.com/fynedesk" + "github.com/FyshOS/saver" + + "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/widget" ) type embededWM struct { windows []fynedesk.Window + root fyne.Window } func (e *embededWM) AddWindow(win fynedesk.Window) { @@ -79,3 +86,55 @@ func (e *embededWM) Close() { windows[0].Close() // ensure our root is asked to close as well } } + +var visible bool + +func (e *embededWM) ShowScreensaver(s *saver.ScreenSaver) { + if visible { + return + } + + visible = true + over := container.NewStack(canvas.NewRectangle(color.Black)) + + s.OnUnlocked = func() { + visible = false + e.root.Canvas().Overlays().Remove(over) + } + + over.Add(s.MakeUI(e.root)) + over.Resize(e.root.Canvas().Size()) + e.root.Canvas().Overlays().Add(over) +} + +func (e *embededWM) setWindow(win fyne.Window) fyne.CanvasObject { + e.root = win + + return newSaverMonitor(fynedesk.Instance().DelayScreensaver) +} + +type saverMonitor struct { + widget.BaseWidget + + cb func() +} + +func newSaverMonitor(cb func()) fyne.CanvasObject { + s := &saverMonitor{cb: cb} + s.ExtendBaseWidget(s) + return s +} + +func (s *saverMonitor) CreateRenderer() fyne.WidgetRenderer { + return widget.NewSimpleRenderer(canvas.NewRectangle(color.Transparent)) +} + +func (s *saverMonitor) MouseIn(*deskDriver.MouseEvent) { +} + +func (s *saverMonitor) MouseMoved(*deskDriver.MouseEvent) { + s.cb() +} + +func (s *saverMonitor) MouseOut() { +} diff --git a/internal/ui/menu.go b/internal/ui/menu.go index fe75ed12..c7089022 100644 --- a/internal/ui/menu.go +++ b/internal/ui/menu.go @@ -109,11 +109,11 @@ func (w *widgetPanel) showAccountMenu(_ fyne.CanvasObject) { w2.Close() }}} isEmbed := w.desk.(*desktop).root.Title() != RootWindowName + items1 = append(items1, &widget.Button{Icon: wmtheme.LockIcon, Importance: widget.LowImportance, OnTapped: func() { + w2.Close() + w.desk.TriggerScreensaver(true) + }}) if !isEmbed { - items1 = append(items1, &widget.Button{Icon: wmtheme.LockIcon, Importance: widget.LowImportance, OnTapped: func() { - w2.Close() - w.desk.(*desktop).lockScreen() - }}) if os.Getenv("FYNE_DESK_RUNNER") != "" { items1 = append(items1, &widget.Button{Icon: theme.ViewRefreshIcon(), Importance: widget.LowImportance, OnTapped: func() { os.Exit(5) diff --git a/internal/ui/settings.go b/internal/ui/settings.go index 590a936d..13829919 100644 --- a/internal/ui/settings.go +++ b/internal/ui/settings.go @@ -2,6 +2,7 @@ package ui import ( "os" + "os/exec" "runtime" "strings" "sync" @@ -27,6 +28,8 @@ type deskSettings struct { moduleNames []string narrowPanel, narrowLeftLauncher bool + screenSaverClock bool + screenSaver, screenSaverLabel string listenerLock sync.Mutex changeListeners []chan fynedesk.DeskSettings @@ -76,6 +79,18 @@ func (d *deskSettings) NarrowLeftLauncher() bool { return d.narrowLeftLauncher } +func (d *deskSettings) ScreenSaverClock() bool { + return d.screenSaverClock +} + +func (d *deskSettings) ScreenSaverType() string { + return d.screenSaver +} + +func (d *deskSettings) ScreenSaverLabel() string { + return d.screenSaverLabel +} + func (d *deskSettings) BorderButtonPosition() string { return d.borderButtonPosition } @@ -182,6 +197,31 @@ func (d *deskSettings) setNarrowWidgetPanel(narrow bool) { d.apply() } +func (d *deskSettings) setScreenSaver(saver string) { + oldSaver := d.screenSaver + d.screenSaver = saver + + fyne.CurrentApp().Preferences().SetString("savertype", saver) + + if oldSaver == "XScreensaver" && saver != "XScreensaver" { + cmd := exec.Command("xscreensaver-command", "-exit") + _ = cmd.Start() + } else if oldSaver != "XScreensaver" && saver == "XScreensaver" { + cmd := exec.Command("xscreensaver", "--no-splash") + _ = cmd.Start() + } +} + +func (d *deskSettings) setScreenSaverClock(show bool) { + d.screenSaverClock = show + fyne.CurrentApp().Preferences().SetBool("saverclock", show) +} + +func (d *deskSettings) setScreenSaverLabel(text string) { + d.screenSaverLabel = text + fyne.CurrentApp().Preferences().SetString("saverlabel", text) +} + func (d *deskSettings) setBorderButtonPosition(pos string) { d.borderButtonPosition = pos fyne.CurrentApp().Preferences().SetString("borderbuttonposition", d.borderButtonPosition) @@ -249,6 +289,9 @@ func (d *deskSettings) load() { d.narrowPanel = fyne.CurrentApp().Preferences().BoolWithFallback("narrowpanel", true) d.borderButtonPosition = fyne.CurrentApp().Preferences().StringWithFallback("borderbuttonposition", "Left") + d.screenSaver = fyne.CurrentApp().Preferences().StringWithFallback("savertype", "FyshOS") + d.screenSaverClock = fyne.CurrentApp().Preferences().BoolWithFallback("saverclock", true) + d.screenSaverLabel = fyne.CurrentApp().Preferences().StringWithFallback("saverlabel", "FyneDesk") d.clockFormatting = fyne.CurrentApp().Preferences().StringWithFallback("clockformatting", "12h") d.loadRecents() diff --git a/internal/ui/settings_ui.go b/internal/ui/settings_ui.go index 276f4df6..d47f68d3 100644 --- a/internal/ui/settings_ui.go +++ b/internal/ui/settings_ui.go @@ -111,6 +111,14 @@ func (d *settingsUI) loadAppearanceScreen() fyne.CanvasObject { borderButton := &widget.Select{Options: []string{"Left", "Right"}} borderButton.SetSelected(d.settings.BorderButtonPosition()) + saverLabel := widget.NewLabelWithStyle("Screensaver", fyne.TextAlignCenter, fyne.TextStyle{Bold: true}) + saverType := &widget.RadioGroup{Options: []string{"FyshOS", "XScreensaver"}, Required: true, Horizontal: true} + saverType.SetSelected(d.settings.ScreenSaverType()) + saverText := widget.NewEntry() + saverText.SetText(d.settings.ScreenSaverLabel()) + saverClock := widget.NewCheck("Clock", nil) + saverClock.Checked = d.settings.ScreenSaverClock() + themeLabel := widget.NewLabel(d.settings.IconTheme()) themeIcons := container.NewHBox() d.populateThemeIcons(themeIcons, d.settings.IconTheme()) @@ -129,7 +137,9 @@ func (d *settingsUI) loadAppearanceScreen() fyne.CanvasObject { lay := container.NewBorder(nil, nil, layoutLabel, container.NewGridWithColumns(2, narrowBar, narrowWidget)) border := container.NewBorder(nil, nil, borderButtonLabel, borderButton) - top := container.NewVBox(bg, time, lay, border) + saver := container.NewBorder(nil, nil, container.NewVBox(saverLabel, widget.NewLabel("")), + container.NewVBox(saverType, container.NewBorder(nil, nil, saverClock, nil, saverText))) + top := container.NewVBox(bg, time, lay, border, saver) themeFormLabel := widget.NewLabelWithStyle("Icon Theme", fyne.TextAlignCenter, fyne.TextStyle{Bold: true}) themeCurrent := container.NewHBox(layout.NewSpacer(), themeLabel, themeIcons) @@ -143,6 +153,9 @@ func (d *settingsUI) loadAppearanceScreen() fyne.CanvasObject { d.settings.setBorderButtonPosition(borderButton.Selected) d.settings.setNarrowLeftLauncher(narrowBar.Checked) d.settings.setNarrowWidgetPanel(narrowWidget.Checked) + d.settings.setScreenSaver(saverType.Selected) + d.settings.setScreenSaverClock(saverClock.Checked) + d.settings.setScreenSaverLabel(saverText.Text) }}) return container.NewBorder(top, applyButton, nil, nil, bottom) @@ -401,7 +414,9 @@ func (d *settingsUI) loadThemeScreen() fyne.CanvasObject { fyne.LogError("Unable to list themes - missing?", err) } else { for _, l := range list { - themeList = append(themeList, l.Name()) + if false { // TODO with 1.21 } !slices.Contains(themeList, l.Name()) { + themeList = append(themeList, l.Name()) + } } } diff --git a/internal/x11/wm/desk.go b/internal/x11/wm/desk.go index 676b0992..b9aae914 100644 --- a/internal/x11/wm/desk.go +++ b/internal/x11/wm/desk.go @@ -15,6 +15,7 @@ import ( "github.com/BurntSushi/xgb" "github.com/BurntSushi/xgb/randr" + "github.com/BurntSushi/xgb/screensaver" "github.com/BurntSushi/xgb/xproto" "github.com/BurntSushi/xgbutil" "github.com/BurntSushi/xgbutil/ewmh" @@ -125,7 +126,8 @@ func NewX11WindowManager(a fyne.App) (fynedesk.WindowManager, error) { xproto.EventMaskButtonRelease | xproto.EventMaskKeyPress | xproto.EventMaskStructureNotify | - xproto.EventMaskSubstructureRedirect + xproto.EventMaskSubstructureRedirect | + screensaver.EventNotifyMask | screensaver.EventCycleMask if err := xproto.ChangeWindowAttributesChecked(conn.Conn(), root, xproto.CwEventMask, []uint32{uint32(eventMask)}).Check(); err != nil { conn.Conn().Close() @@ -163,6 +165,7 @@ func NewX11WindowManager(a fyne.App) (fynedesk.WindowManager, error) { } x11.LoadCursors(conn) + mgr.initScreensaver() listener := make(chan fyne.Settings) a.Settings().AddChangeListener(listener) @@ -456,6 +459,8 @@ func (x *x11WM) runLoop() { x.hideWindow(ev.Window) case xproto.VisibilityNotifyEvent: x.handleVisibilityChange(ev) + case screensaver.NotifyEvent: + // screensaver activate, except we manage it with an internal timer } } diff --git a/internal/x11/wm/screensaver.go b/internal/x11/wm/screensaver.go new file mode 100644 index 00000000..ad26f301 --- /dev/null +++ b/internal/x11/wm/screensaver.go @@ -0,0 +1,62 @@ +package wm + +import ( + "log" + "os/exec" + "time" + + "fyshos.com/fynedesk" + "github.com/BurntSushi/xgb/screensaver" + "github.com/BurntSushi/xgb/xproto" + "github.com/FyshOS/saver" +) + +func (x *x11WM) initScreensaver() { + err := screensaver.Init(x.x.Conn()) + log.Println("ERR", err) + + //screensaver.SelectInput(conn.Conn(), xproto.Drawable(conn.Screen().Root), + // screensaver.EventNotifyMask) + go x.watchScreensaver() +} + +func (x *x11WM) watchScreensaver() { + to := time.NewTicker(5 * time.Second) + + for range to.C { + info, err := screensaver.QueryInfo(x.x.Conn(), xproto.Drawable(x.x.Screen().Root)).Reply() + if err != nil { + log.Println("ERR", err) + continue + } + + if info.MsSinceUserInput <= 5500 { + fynedesk.Instance().DelayScreensaver() + } + } +} + +var visible bool + +func (x *x11WM) ShowScreensaver(s *saver.ScreenSaver) { + if fynedesk.Instance().Settings().ScreenSaverType() == "XScreensaver" { + task := "-activate" + if s.Lock { + task = "-lock" + } + cmd := exec.Command("xscreensaver-command", task) + cmd.Start() + return + } + + if visible { + return + } + + visible = true + s.OnUnlocked = func() { + visible = false + } + + s.ShowWindow() +} diff --git a/settings.go b/settings.go index 15a1d64b..35ecab27 100644 --- a/settings.go +++ b/settings.go @@ -19,6 +19,9 @@ type DeskSettings interface { KeyboardModifier() fyne.KeyModifier ModuleNames() []string + ScreenSaverType() string + ScreenSaverClock() bool + ScreenSaverLabel() string AddChangeListener(listener chan DeskSettings) } diff --git a/test/desktop.go b/test/desktop.go index 9e533e8c..4fb79bb1 100644 --- a/test/desktop.go +++ b/test/desktop.go @@ -120,3 +120,7 @@ func (td *Desktop) ShowMenuAt(menu *fyne.Menu, pos fyne.Position) { func (td *Desktop) WindowManager() fynedesk.WindowManager { return td.wm } + +func (td *Desktop) DelayScreensaver() {} + +func (td *Desktop) TriggerScreensaver(bool) {} diff --git a/test/settings.go b/test/settings.go index bac62761..9cb5b294 100644 --- a/test/settings.go +++ b/test/settings.go @@ -1,8 +1,9 @@ package test import ( - "fyne.io/fyne/v2" "fyshos.com/fynedesk" + + "fyne.io/fyne/v2" ) // Settings is a simple struct for managing settings within our tests @@ -157,6 +158,18 @@ func (s *Settings) ClockFormatting() string { return s.clockFormatting } +func (s *Settings) ScreenSaverClock() bool { + return true +} + +func (s *Settings) ScreenSaverLabel() string { + return "(clock)" +} + +func (s *Settings) ScreenSaverType() string { + return "FyshOS" +} + // SetClockFormatting support setting the format that the clock should display func (s *Settings) SetClockFormatting(format string) { if format == "24h" { diff --git a/wm.go b/wm.go index 47ad37e7..8169687a 100644 --- a/wm.go +++ b/wm.go @@ -3,6 +3,8 @@ package fynedesk import ( "image" + "github.com/FyshOS/saver" + "fyne.io/fyne/v2" ) @@ -18,6 +20,8 @@ type WindowManager interface { ShowOverlay(fyne.Window, fyne.Size, fyne.Position) ShowMenuOverlay(*fyne.Menu, fyne.Size, fyne.Position) ShowModal(fyne.Window, fyne.Size) + + ShowScreensaver(saver *saver.ScreenSaver) } // Stack describes an ordered list of windows. From e4e59c4443b9ce42c6f8f10e441228566ca70883 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Tue, 21 Jan 2025 10:53:17 +0000 Subject: [PATCH 02/16] Merge from develop --- go.mod | 4 ++-- go.sum | 8 ++++---- internal/ui/desk.go | 5 ++--- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index a1ce6819..74645604 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/BurntSushi/toml v1.4.0 // indirect github.com/fyne-io/image v0.0.0-20240417123036-dc0ee9e7c964 // indirect github.com/jackmordaunt/icns v1.0.1-0.20200413110149-9e181b441ab2 // indirect - github.com/jeandeaual/go-locale v0.0.0-20240223122105-ce5225dcaa49 // indirect + github.com/jeandeaual/go-locale v0.0.0-20241217141322-fcc2cadd6f08 // indirect github.com/nicksnyder/go-i18n/v2 v2.4.0 // indirect github.com/rymdport/portal v0.3.0 // indirect howett.net/plist v1.0.1 // indirect @@ -54,7 +54,7 @@ require ( golang.org/x/image v0.18.0 // indirect golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a // indirect golang.org/x/net v0.25.0 // indirect - golang.org/x/sys v0.20.0 // indirect + golang.org/x/sys v0.27.0 // indirect golang.org/x/text v0.16.0 gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 986a4c6f..62e21453 100644 --- a/go.sum +++ b/go.sum @@ -223,8 +223,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1: github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jackmordaunt/icns v1.0.1-0.20200413110149-9e181b441ab2 h1:2bRhR5GcMudCdaY4p8ip89hsvSyxYehLSicCNtygyVY= github.com/jackmordaunt/icns v1.0.1-0.20200413110149-9e181b441ab2/go.mod h1:Hj3TV9xrdt+g9apvBagVi/VzE41gSliEBypxaQDq5QA= -github.com/jeandeaual/go-locale v0.0.0-20240223122105-ce5225dcaa49 h1:Po+wkNdMmN+Zj1tDsJQy7mJlPlwGNQd9JZoPjObagf8= -github.com/jeandeaual/go-locale v0.0.0-20240223122105-ce5225dcaa49/go.mod h1:YiutDnxPRLk5DLUFj6Rw4pRBBURZY07GFr54NdV9mQg= +github.com/jeandeaual/go-locale v0.0.0-20241217141322-fcc2cadd6f08 h1:wMeVzrPO3mfHIWLZtDcSaGAe2I4PW9B/P5nMkRSwCAc= +github.com/jeandeaual/go-locale v0.0.0-20241217141322-fcc2cadd6f08/go.mod h1:ZDXo8KHryOWSIqnsb/CiDq7hQUYryCgdVnxbj8tDG7o= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= @@ -488,8 +488,8 @@ 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.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 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= diff --git a/internal/ui/desk.go b/internal/ui/desk.go index 77e84a0f..792b0f73 100644 --- a/internal/ui/desk.go +++ b/internal/ui/desk.go @@ -14,8 +14,6 @@ import ( "fyne.io/fyne/v2/canvas" "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" wmtheme "fyshos.com/fynedesk/theme" @@ -445,7 +443,8 @@ func NewDesktop(app fyne.App, mgr fynedesk.WindowManager, icons appie.Provider, // If run during CI for testing it will return an in-memory window using the // fyne/test package. func NewEmbeddedDesktop(app fyne.App, icons appie.Provider) fynedesk.Desktop { - desk := newDesktop(app, &embededWM{}, icons) + wm := &embededWM{} + desk := newDesktop(app, wm, icons) desk.run = desk.runEmbed desk.showMenu = desk.showMenuEmbed From 3ce905aa58e3cac56988b6bb6fb8cfc6cd11302a Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sat, 25 Jan 2025 21:18:16 +0000 Subject: [PATCH 03/16] Refactor screensaver X11 code to new file --- internal/ui/desk.go | 52 --------------------------------- internal/ui/screensaver.go | 59 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 52 deletions(-) create mode 100644 internal/ui/screensaver.go diff --git a/internal/ui/desk.go b/internal/ui/desk.go index 792b0f73..46ba484a 100644 --- a/internal/ui/desk.go +++ b/internal/ui/desk.go @@ -4,11 +4,9 @@ import ( "math" "os/exec" "strconv" - "time" "fyshos.com/fynedesk/internal/notify" "github.com/FyshOS/appie" - "github.com/FyshOS/saver" "fyne.io/fyne/v2" "fyne.io/fyne/v2/canvas" @@ -366,56 +364,6 @@ func (l *desktop) registerShortcuts() { }) } -func (l *desktop) startXscreensaver() { - _, err := exec.LookPath("xscreensaver") - if err != nil { - fyne.LogError("xscreensaver command not found", err) - return - } - err = exec.Command("xscreensaver", "-no-splash").Start() - if err != nil { - fyne.LogError("Failed to lock screen", err) - } -} - -func (l *desktop) TriggerScreensaver(lock bool) { - s := saver.NewScreenSaver(nil) - s.ClockFormat = l.settings.ClockFormatting() - if l.settings.ScreenSaverClock() { - s.Label = "(clock)" - } else { - s.Label = l.settings.ScreenSaverLabel() - } - s.Lock = lock - - l.wm.ShowScreensaver(s) -} - -var lastActivity time.Time - -func (l *desktop) DelayScreensaver() { - lastActivity = time.Now() -} - -var idle bool - -func (l *desktop) watchScreenActivity() { - to := time.NewTicker(5 * time.Second) - - for range to.C { - if lastActivity.Add(time.Minute * 5).Before(time.Now()) { - - if !idle { - idle = true - - l.TriggerScreensaver(false) - } - } else { - idle = false - } - } -} - // Screens returns the screens provider of the current desktop environment for access to screen functionality. func (l *desktop) Screens() fynedesk.ScreenList { return l.screens diff --git a/internal/ui/screensaver.go b/internal/ui/screensaver.go new file mode 100644 index 00000000..863dfb28 --- /dev/null +++ b/internal/ui/screensaver.go @@ -0,0 +1,59 @@ +package ui + +import ( + "os/exec" + "time" + + "github.com/FyshOS/saver" + + "fyne.io/fyne/v2" +) + +func (l *desktop) startXscreensaver() { + _, err := exec.LookPath("xscreensaver") + if err != nil { + fyne.LogError("xscreensaver command not found", err) + return + } + err = exec.Command("xscreensaver", "-no-splash").Start() + if err != nil { + fyne.LogError("Failed to lock screen", err) + } +} + +func (l *desktop) TriggerScreensaver(lock bool) { + s := saver.NewScreenSaver(nil) + s.ClockFormat = l.settings.ClockFormatting() + if l.settings.ScreenSaverClock() { + s.Label = "(clock)" + } else { + s.Label = l.settings.ScreenSaverLabel() + } + s.Lock = lock + + go l.wm.ShowScreensaver(s) +} + +var lastActivity time.Time + +func (l *desktop) DelayScreensaver() { + lastActivity = time.Now() +} + +func (l *desktop) watchScreenActivity() { + idle := false + to := time.NewTicker(5 * time.Second) + + for range to.C { + if lastActivity.Add(time.Minute * 5).Before(time.Now()) { + + if !idle { + idle = true + + l.TriggerScreensaver(false) + } + } else { + idle = false + } + } +} From 0719c0ad9a0b1b9d7e71636c2ebc2023e00597c4 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sat, 25 Jan 2025 21:20:09 +0000 Subject: [PATCH 04/16] Don't allow system keys when screensaver up --- internal/x11/wm/events.go | 8 ++++++++ internal/x11/wm/screensaver.go | 13 ++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/internal/x11/wm/events.go b/internal/x11/wm/events.go index c600816e..3eb7d1e5 100644 --- a/internal/x11/wm/events.go +++ b/internal/x11/wm/events.go @@ -170,6 +170,10 @@ func (x *x11WM) handleInitialHints(ev xproto.ClientMessageEvent, hint string) { } func (x *x11WM) handleKeyPress(ev xproto.KeyPressEvent) { + if screenSaverActive { + return + } + userMod := ev.State&xproto.ModMask4 != 0 if fynedesk.Instance().Settings().KeyboardModifier() == fyne.KeyModifierAlt { userMod = ev.State&xproto.ModMask1 != 0 @@ -216,6 +220,10 @@ func (x *x11WM) handleKeyPress(ev xproto.KeyPressEvent) { } func (x *x11WM) handleKeyRelease(ev xproto.KeyReleaseEvent) { + if screenSaverActive { + return + } + userMod := keyCodeSuper if fynedesk.Instance().Settings().KeyboardModifier() == fyne.KeyModifierAlt { userMod = keyCodeAlt diff --git a/internal/x11/wm/screensaver.go b/internal/x11/wm/screensaver.go index ad26f301..a150ba1d 100644 --- a/internal/x11/wm/screensaver.go +++ b/internal/x11/wm/screensaver.go @@ -13,7 +13,10 @@ import ( func (x *x11WM) initScreensaver() { err := screensaver.Init(x.x.Conn()) - log.Println("ERR", err) + if err != nil { + log.Println("Failed to init screensaver extension") + return + } //screensaver.SelectInput(conn.Conn(), xproto.Drawable(conn.Screen().Root), // screensaver.EventNotifyMask) @@ -36,7 +39,7 @@ func (x *x11WM) watchScreensaver() { } } -var visible bool +var screenSaverActive bool func (x *x11WM) ShowScreensaver(s *saver.ScreenSaver) { if fynedesk.Instance().Settings().ScreenSaverType() == "XScreensaver" { @@ -49,13 +52,13 @@ func (x *x11WM) ShowScreensaver(s *saver.ScreenSaver) { return } - if visible { + if screenSaverActive { return } - visible = true + screenSaverActive = true s.OnUnlocked = func() { - visible = false + screenSaverActive = false } s.ShowWindow() From 1c6b1d2950163fc8b648a21d6def8c4e69a38cb6 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sat, 25 Jan 2025 21:22:25 +0000 Subject: [PATCH 05/16] Latest saver library --- go.mod | 2 +- go.sum | 4 ++-- internal/ui/menu.go | 5 ++++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index d65905a3..3661d7cd 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/BurntSushi/xgbutil v0.0.0-20160919175755-f7c97cef3b4e github.com/FyshOS/appie v0.0.0-20250103211310-00f097d8e19d github.com/FyshOS/backgrounds v0.0.0-20230616202904-0a8b6ebaa184 - github.com/FyshOS/saver v0.0.0-20250121095006-5664671ee7e6 + github.com/FyshOS/saver v0.0.0-20250125211336-528339462781 github.com/Knetic/govaluate v3.0.0+incompatible github.com/disintegration/imaging v1.6.2 github.com/godbus/dbus/v5 v5.1.0 diff --git a/go.sum b/go.sum index 895c3af1..8d8d02e7 100644 --- a/go.sum +++ b/go.sum @@ -59,8 +59,8 @@ github.com/FyshOS/appie v0.0.0-20250103211310-00f097d8e19d h1:bkIQPpxGMalOufoLbL github.com/FyshOS/appie v0.0.0-20250103211310-00f097d8e19d/go.mod h1:Gtvb1fKDXbE9HjMtoYdB2MPSSGy6PdtMl0TC9dSF8q0= github.com/FyshOS/backgrounds v0.0.0-20230616202904-0a8b6ebaa184 h1:Za0NHFsT0CCXf/X4hEaywjvEECccrM/xVVL8BzAy6JI= github.com/FyshOS/backgrounds v0.0.0-20230616202904-0a8b6ebaa184/go.mod h1:cOUmJ3HUVmH3W3u9Gj5hM73ZgrDxGNHKMr5T/sBKqLU= -github.com/FyshOS/saver v0.0.0-20250121095006-5664671ee7e6 h1:jxlIwF6vRAmpFfQ3yMvgzz1St7EATnAe4NRELD/WgCM= -github.com/FyshOS/saver v0.0.0-20250121095006-5664671ee7e6/go.mod h1:yIuAuYqnEyKaiNU4MD4xmyLcZl9QdDr2uTmT7lt02tI= +github.com/FyshOS/saver v0.0.0-20250125211336-528339462781 h1:jGmHNeimIf4DDEe8jkoUNX9r10+qGtkUG+3PMpjGSEs= +github.com/FyshOS/saver v0.0.0-20250125211336-528339462781/go.mod h1:yIuAuYqnEyKaiNU4MD4xmyLcZl9QdDr2uTmT7lt02tI= github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg= github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= diff --git a/internal/ui/menu.go b/internal/ui/menu.go index c7089022..f530b46e 100644 --- a/internal/ui/menu.go +++ b/internal/ui/menu.go @@ -111,7 +111,10 @@ func (w *widgetPanel) showAccountMenu(_ fyne.CanvasObject) { isEmbed := w.desk.(*desktop).root.Title() != RootWindowName items1 = append(items1, &widget.Button{Icon: wmtheme.LockIcon, Importance: widget.LowImportance, OnTapped: func() { w2.Close() - w.desk.TriggerScreensaver(true) + go func() { + time.Sleep(time.Millisecond * 300) + w.desk.TriggerScreensaver(true) + }() }}) if !isEmbed { if os.Getenv("FYNE_DESK_RUNNER") != "" { From f3484b0d8a7634ecd725805e52ce0a2bd10349a1 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sat, 25 Jan 2025 21:36:41 +0000 Subject: [PATCH 06/16] Always lock --- desk.go | 2 +- internal/ui/desk.go | 2 +- internal/ui/menu.go | 2 +- internal/ui/screensaver.go | 6 +++--- test/desktop.go | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/desk.go b/desk.go index 2e89b2c7..64bf63d5 100644 --- a/desk.go +++ b/desk.go @@ -27,7 +27,7 @@ type Desktop interface { SetDesktop(int) DelayScreensaver() - TriggerScreensaver(bool) + TriggerScreensaver() } var instance Desktop diff --git a/internal/ui/desk.go b/internal/ui/desk.go index 46ba484a..49960324 100644 --- a/internal/ui/desk.go +++ b/internal/ui/desk.go @@ -360,7 +360,7 @@ func (l *desktop) registerShortcuts() { l.calculator) l.AddShortcut(fynedesk.NewShortcut("Lock screen", fyne.KeyL, fynedesk.UserModifier), func() { - l.TriggerScreensaver(true) + l.TriggerScreensaver() }) } diff --git a/internal/ui/menu.go b/internal/ui/menu.go index f530b46e..5b17b75e 100644 --- a/internal/ui/menu.go +++ b/internal/ui/menu.go @@ -113,7 +113,7 @@ func (w *widgetPanel) showAccountMenu(_ fyne.CanvasObject) { w2.Close() go func() { time.Sleep(time.Millisecond * 300) - w.desk.TriggerScreensaver(true) + w.desk.TriggerScreensaver() }() }}) if !isEmbed { diff --git a/internal/ui/screensaver.go b/internal/ui/screensaver.go index 863dfb28..fc640612 100644 --- a/internal/ui/screensaver.go +++ b/internal/ui/screensaver.go @@ -21,7 +21,7 @@ func (l *desktop) startXscreensaver() { } } -func (l *desktop) TriggerScreensaver(lock bool) { +func (l *desktop) TriggerScreensaver() { s := saver.NewScreenSaver(nil) s.ClockFormat = l.settings.ClockFormatting() if l.settings.ScreenSaverClock() { @@ -29,7 +29,7 @@ func (l *desktop) TriggerScreensaver(lock bool) { } else { s.Label = l.settings.ScreenSaverLabel() } - s.Lock = lock + s.Lock = true go l.wm.ShowScreensaver(s) } @@ -50,7 +50,7 @@ func (l *desktop) watchScreenActivity() { if !idle { idle = true - l.TriggerScreensaver(false) + l.TriggerScreensaver() } } else { idle = false diff --git a/test/desktop.go b/test/desktop.go index 4fb79bb1..9990286d 100644 --- a/test/desktop.go +++ b/test/desktop.go @@ -123,4 +123,4 @@ func (td *Desktop) WindowManager() fynedesk.WindowManager { func (td *Desktop) DelayScreensaver() {} -func (td *Desktop) TriggerScreensaver(bool) {} +func (td *Desktop) TriggerScreensaver() {} From db1b915dd2b78e3814aa05f31fd5786f84a46164 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sat, 25 Jan 2025 21:39:43 +0000 Subject: [PATCH 07/16] Working CI --- .github/workflows/platform_tests.yml | 2 +- .github/workflows/static_analysis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/platform_tests.yml b/.github/workflows/platform_tests.yml index 07102071..153f18f3 100644 --- a/.github/workflows/platform_tests.yml +++ b/.github/workflows/platform_tests.yml @@ -21,7 +21,7 @@ jobs: go-version: ${{ matrix.go-version }} - name: Get dependencies - run: sudo apt-get update && sudo apt-get install gcc libgl1-mesa-dev libegl1-mesa-dev libgles2-mesa-dev libx11-dev xorg-dev bc + run: sudo apt-get update && sudo apt-get install gcc libgl1-mesa-dev libegl1-mesa-dev libgles2-mesa-dev libx11-dev xorg-dev bc libpam-dev if: ${{ runner.os == 'Linux' }} - name: Tests diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index ba75b1c9..9e6e1816 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -16,7 +16,7 @@ jobs: - name: Get dependencies run: | - sudo apt-get update && sudo apt-get install gcc libgl1-mesa-dev libegl1-mesa-dev libgles2-mesa-dev libx11-dev xorg-dev + sudo apt-get update && sudo apt-get install gcc libgl1-mesa-dev libegl1-mesa-dev libgles2-mesa-dev libx11-dev xorg-dev libpam-dev 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 From 2290787cdf31728cb2ebbf67a733ed1ef10ed0d4 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sat, 25 Jan 2025 22:13:14 +0000 Subject: [PATCH 08/16] Reduce cyclo --- internal/x11/wm/desk.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/internal/x11/wm/desk.go b/internal/x11/wm/desk.go index b9aae914..dfbf78e6 100644 --- a/internal/x11/wm/desk.go +++ b/internal/x11/wm/desk.go @@ -424,9 +424,7 @@ func (x *x11WM) runLoop() { case xproto.ClientMessageEvent: x.handleClientMessage(ev) case xproto.ConfigureNotifyEvent: - if ev.Window == x.x.RootWin() { - x.configureRoots() - } + x.notifyConfigure(ev) case xproto.ConfigureRequestEvent: x.configureWindow(ev.Window, ev) case xproto.CreateNotifyEvent: @@ -523,6 +521,12 @@ func (x *x11WM) configureRoots() { go x.updateBackgrounds() } +func (x *x11WM) notifyConfigure(ev xproto.ConfigureNotifyEvent) { + if ev.Window == x.x.RootWin() { + x.configureRoots() + } +} + func (x *x11WM) configureWindow(win xproto.Window, ev xproto.ConfigureRequestEvent) { c := x.clientForWin(win) xcoord := ev.X From 13e3be5ef08db25bdaf4b446a9e2d6eb9cc36b2b Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sat, 25 Jan 2025 22:16:07 +0000 Subject: [PATCH 09/16] Fix test failure with overlay --- internal/ui/desk_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ui/desk_test.go b/internal/ui/desk_test.go index dc372e84..9f87a694 100644 --- a/internal/ui/desk_test.go +++ b/internal/ui/desk_test.go @@ -66,7 +66,7 @@ func TestBackgroundChange(t *testing.T) { l.settings = wmTest.NewSettings() l.setupRoot() - bg := l.root.Content().(*fyne.Container).Objects[0].(*background) + bg := l.root.Content().(*fyne.Container).Objects[0].(*fyne.Container).Objects[0].(*background) workingDir, err := os.Getwd() if err != nil { From b2d6c595b88505d11dd918de96aeae7d14cb18cc Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sat, 25 Jan 2025 22:19:22 +0000 Subject: [PATCH 10/16] Fix header for macOS preview build --- internal/x11/wm/screensaver.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/x11/wm/screensaver.go b/internal/x11/wm/screensaver.go index a150ba1d..7883bd1d 100644 --- a/internal/x11/wm/screensaver.go +++ b/internal/x11/wm/screensaver.go @@ -1,3 +1,6 @@ +//go:build linux || openbsd || freebsd || netbsd +// +build linux openbsd freebsd netbsd + package wm import ( From 403a6b33a7069bb745fe527084d21b6977c91ecf Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sun, 26 Jan 2025 19:06:18 +0000 Subject: [PATCH 11/16] Fix lint errors --- desk.go | 4 ++-- internal/ui/desk.go | 2 +- internal/ui/embed_wm.go | 2 +- internal/ui/menu.go | 2 +- internal/ui/screensaver.go | 6 +++--- internal/x11/wm/screensaver.go | 2 +- test/desktop.go | 6 ++++-- test/settings.go | 5 ++++- 8 files changed, 17 insertions(+), 12 deletions(-) diff --git a/desk.go b/desk.go index 64bf63d5..c04b8193 100644 --- a/desk.go +++ b/desk.go @@ -26,8 +26,8 @@ type Desktop interface { Desktop() int SetDesktop(int) - DelayScreensaver() - TriggerScreensaver() + DelayScreenSaver() + TriggerScreenSaver() } var instance Desktop diff --git a/internal/ui/desk.go b/internal/ui/desk.go index 49960324..40e50bfb 100644 --- a/internal/ui/desk.go +++ b/internal/ui/desk.go @@ -360,7 +360,7 @@ func (l *desktop) registerShortcuts() { l.calculator) l.AddShortcut(fynedesk.NewShortcut("Lock screen", fyne.KeyL, fynedesk.UserModifier), func() { - l.TriggerScreensaver() + l.TriggerScreenSaver() }) } diff --git a/internal/ui/embed_wm.go b/internal/ui/embed_wm.go index 1f38acc5..73d49688 100644 --- a/internal/ui/embed_wm.go +++ b/internal/ui/embed_wm.go @@ -110,7 +110,7 @@ func (e *embededWM) ShowScreensaver(s *saver.ScreenSaver) { func (e *embededWM) setWindow(win fyne.Window) fyne.CanvasObject { e.root = win - return newSaverMonitor(fynedesk.Instance().DelayScreensaver) + return newSaverMonitor(fynedesk.Instance().DelayScreenSaver) } type saverMonitor struct { diff --git a/internal/ui/menu.go b/internal/ui/menu.go index 5b17b75e..3894efdd 100644 --- a/internal/ui/menu.go +++ b/internal/ui/menu.go @@ -113,7 +113,7 @@ func (w *widgetPanel) showAccountMenu(_ fyne.CanvasObject) { w2.Close() go func() { time.Sleep(time.Millisecond * 300) - w.desk.TriggerScreensaver() + w.desk.TriggerScreenSaver() }() }}) if !isEmbed { diff --git a/internal/ui/screensaver.go b/internal/ui/screensaver.go index fc640612..9b2a62b5 100644 --- a/internal/ui/screensaver.go +++ b/internal/ui/screensaver.go @@ -21,7 +21,7 @@ func (l *desktop) startXscreensaver() { } } -func (l *desktop) TriggerScreensaver() { +func (l *desktop) TriggerScreenSaver() { s := saver.NewScreenSaver(nil) s.ClockFormat = l.settings.ClockFormatting() if l.settings.ScreenSaverClock() { @@ -36,7 +36,7 @@ func (l *desktop) TriggerScreensaver() { var lastActivity time.Time -func (l *desktop) DelayScreensaver() { +func (l *desktop) DelayScreenSaver() { lastActivity = time.Now() } @@ -50,7 +50,7 @@ func (l *desktop) watchScreenActivity() { if !idle { idle = true - l.TriggerScreensaver() + l.TriggerScreenSaver() } } else { idle = false diff --git a/internal/x11/wm/screensaver.go b/internal/x11/wm/screensaver.go index 7883bd1d..09e60cfe 100644 --- a/internal/x11/wm/screensaver.go +++ b/internal/x11/wm/screensaver.go @@ -37,7 +37,7 @@ func (x *x11WM) watchScreensaver() { } if info.MsSinceUserInput <= 5500 { - fynedesk.Instance().DelayScreensaver() + fynedesk.Instance().DelayScreenSaver() } } } diff --git a/test/desktop.go b/test/desktop.go index 9990286d..5b8f6c5f 100644 --- a/test/desktop.go +++ b/test/desktop.go @@ -121,6 +121,8 @@ func (td *Desktop) WindowManager() fynedesk.WindowManager { return td.wm } -func (td *Desktop) DelayScreensaver() {} +// DelayScreenSaver is called each time the user interacts with the system. +func (td *Desktop) DelayScreenSaver() {} -func (td *Desktop) TriggerScreensaver() {} +// TriggerScreenSaver can be called to immediately show the screensaver. +func (td *Desktop) TriggerScreenSaver() {} diff --git a/test/settings.go b/test/settings.go index 9cb5b294..a8f36497 100644 --- a/test/settings.go +++ b/test/settings.go @@ -158,14 +158,17 @@ func (s *Settings) ClockFormatting() string { return s.clockFormatting } +// ScreenSaverClock returns if the text on the screensaver should be a clock. func (s *Settings) ScreenSaverClock() bool { return true } +// ScreenSaverLabel returns the string to use in the screensaver (if not a clock). func (s *Settings) ScreenSaverLabel() string { - return "(clock)" + return "FyshOS" } +// ScreenSaverType returns whether this user should use FyshOS or XScreensaver savers. func (s *Settings) ScreenSaverType() string { return "FyshOS" } From 6bae5fff9e53b0fa3661538d1f1e6b1bf2339186 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sat, 8 Feb 2025 22:07:14 +0000 Subject: [PATCH 12/16] Using Fyne develop without patches --- go.mod | 2 +- go.sum | 4 ++-- internal/x11/win/frame.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index d4690880..7f005ae8 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module fyshos.com/fynedesk go 1.19 require ( - fyne.io/fyne/v2 v2.5.5-0.20250208132135-967702162d53 + fyne.io/fyne/v2 v2.5.5-0.20250208220124-36dce94b9595 github.com/BurntSushi/xgb v0.0.0-20201008132610-5f9e7b3c49cd github.com/BurntSushi/xgbutil v0.0.0-20160919175755-f7c97cef3b4e github.com/FyshOS/appie v0.0.0-20250103211310-00f097d8e19d diff --git a/go.sum b/go.sum index 1dc99b27..69ad9d3b 100644 --- a/go.sum +++ b/go.sum @@ -37,8 +37,8 @@ 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.5.5-0.20250208132135-967702162d53 h1:qXq2uL+bCtlg9uNnlXGdj+9eamAjMhuL4fQVDJrHVqo= -fyne.io/fyne/v2 v2.5.5-0.20250208132135-967702162d53/go.mod h1:6/uEYg4FEhspAcWgsokutm9wFMHDNSYuEHCKTYWSho8= +fyne.io/fyne/v2 v2.5.5-0.20250208220124-36dce94b9595 h1:oWbNIUNmmRx3DjnGQ5lKzKGvmEemtxcSrcAZKvSY/IE= +fyne.io/fyne/v2 v2.5.5-0.20250208220124-36dce94b9595/go.mod h1:6/uEYg4FEhspAcWgsokutm9wFMHDNSYuEHCKTYWSho8= fyne.io/systray v1.11.0 h1:D9HISlxSkx+jHSniMBR6fCFOUjk1x/OOOJLa9lJYAKg= fyne.io/systray v1.11.0/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs= github.com/ActiveState/termtest/conpty v0.5.0 h1:JLUe6YDs4Jw4xNPCU+8VwTpniYOGeKzQg4SM2YHQNA8= diff --git a/internal/x11/win/frame.go b/internal/x11/win/frame.go index 415742fd..d0eada7c 100644 --- a/internal/x11/win/frame.go +++ b/internal/x11/win/frame.go @@ -607,7 +607,7 @@ func (f *frame) mouseMotion(x, y int16) { cursor := x11.DefaultCursor if obj != nil { if cur, ok := obj.(desktop.Cursorable); ok { - if cur.Cursor() == wm.CloseCursor { + if cur.Cursor() == desktop.PointerCursor { cursor = x11.CloseCursor } } From 979b078ae3bd269d2dd68b1b8806eb81ea4d9b5e Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Tue, 11 Feb 2025 21:09:37 +0000 Subject: [PATCH 13/16] Don't invoke screensaver automatically if inhinbited Videos etc playing will ask screensaver not to show. --- internal/ui/screensaver.go | 65 +++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/internal/ui/screensaver.go b/internal/ui/screensaver.go index 9b2a62b5..84b113a5 100644 --- a/internal/ui/screensaver.go +++ b/internal/ui/screensaver.go @@ -1,14 +1,24 @@ +// Note that you need to have github.com/knightpp/dbus-codegen-go installed +// +//go:generate dbus-codegen-go -prefix org.freedesktop -package screensaver -output generated/screensaver.go dbus/ScreenSaver.xml package ui import ( + "math/rand" "os/exec" "time" + screensaver "fyshos.com/fynedesk/internal/ui/generated" "github.com/FyshOS/saver" + "github.com/godbus/dbus/v5" + "github.com/godbus/dbus/v5/introspect" + "github.com/godbus/dbus/v5/prop" "fyne.io/fyne/v2" ) +var inhibitCount = 0 + func (l *desktop) startXscreensaver() { _, err := exec.LookPath("xscreensaver") if err != nil { @@ -41,11 +51,12 @@ func (l *desktop) DelayScreenSaver() { } func (l *desktop) watchScreenActivity() { + watchDBus() idle := false to := time.NewTicker(5 * time.Second) for range to.C { - if lastActivity.Add(time.Minute * 5).Before(time.Now()) { + if inhibitCount == 0 && lastActivity.Add(time.Minute*5).Before(time.Now()) { if !idle { idle = true @@ -57,3 +68,55 @@ func (l *desktop) watchScreenActivity() { } } } + +func watchDBus() { + conn, err := dbus.ConnectSessionBus() + if err != nil { + fyne.LogError("failed to connect to DBus to watch for screensaver inhibits", err) + return + } + + name := "org.freedesktop.ScreenSaver" + r, err := conn.RequestName(name, dbus.NameFlagDoNotQueue) + if err != nil || r != dbus.RequestNameReplyPrimaryOwner { + fyne.LogError("could not watch DBus screensaver, another is registered", err) + return + } + + s := &screenSaverWatcher{} + path := "/org/freedesktop/ScreenSaver" + err = conn.ExportAll(s, dbus.ObjectPath(path), "org.freedesktop.ScreenSaver") + if err != nil { + fyne.LogError("failed to export inhibits", err) + return + } + + node := introspect.Node{ + Name: path, + Interfaces: []introspect.Interface{ + introspect.IntrospectData, + prop.IntrospectData, + screensaver.IntrospectDataScreenSaver, + }, + } + err = conn.Export(introspect.NewIntrospectable(&node), dbus.ObjectPath(path), + "org.freedesktop.DBus.Introspectable") + if err != nil { + fyne.LogError("could not export our node data", err) + } +} + +type screenSaverWatcher struct { +} + +func (s *screenSaverWatcher) Inhibit(_ dbus.Sender, _, _ string) (uint, *dbus.Error) { + id := rand.Uint32() + inhibitCount++ + + return uint(id), nil +} + +func (s *screenSaverWatcher) UnInhibit(_ dbus.Sender, _ uint32) *dbus.Error { + inhibitCount-- + return nil +} From 4f215e81bf21565fbb86847ef0e7b43b2f6f6589 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Tue, 11 Feb 2025 21:15:54 +0000 Subject: [PATCH 14/16] Added missing generated file --- internal/ui/dbus/ScreenSaver.xml | 13 ++++ internal/ui/generated/screensaver.go | 92 ++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 internal/ui/dbus/ScreenSaver.xml create mode 100644 internal/ui/generated/screensaver.go diff --git a/internal/ui/dbus/ScreenSaver.xml b/internal/ui/dbus/ScreenSaver.xml new file mode 100644 index 00000000..9966828b --- /dev/null +++ b/internal/ui/dbus/ScreenSaver.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/internal/ui/generated/screensaver.go b/internal/ui/generated/screensaver.go new file mode 100644 index 00000000..e9305f71 --- /dev/null +++ b/internal/ui/generated/screensaver.go @@ -0,0 +1,92 @@ +// Code generated by dbus-codegen-go DO NOT EDIT. +package screensaver + +import ( + "context" + "github.com/godbus/dbus/v5" + "github.com/godbus/dbus/v5/introspect" +) + +var ( + // Introspection for org.freedesktop.ScreenSaver + IntrospectDataScreenSaver = introspect.Interface{ + Name: "org.freedesktop.ScreenSaver", + Methods: []introspect.Method{{Name: "Inhibit", Args: []introspect.Arg{ + {Name: "application_name", Type: "s", Direction: "in"}, + {Name: "reason_for_inhibit", Type: "s", Direction: "in"}, + {Name: "cookie", Type: "u", Direction: "out"}, + }}, + {Name: "UnInhibit", Args: []introspect.Arg{ + {Name: "cookie", Type: "u", Direction: "in"}, + }}, + }, + Signals: []introspect.Signal{}, + Properties: []introspect.Property{}, + Annotations: []introspect.Annotation{}, + } +) + +// Interface name constants. +const ( + InterfaceScreenSaver = "org.freedesktop.ScreenSaver" +) + +// ScreenSaverer is org.freedesktop.ScreenSaver interface. +type ScreenSaverer interface { + // Inhibit is org.freedesktop.ScreenSaver.Inhibit method. + Inhibit(applicationName string, reasonForInhibit string) (cookie uint32, err *dbus.Error) + // UnInhibit is org.freedesktop.ScreenSaver.UnInhibit method. + UnInhibit(cookie uint32) (err *dbus.Error) +} + +// ExportScreenSaver exports the given object that implements org.freedesktop.ScreenSaver on the bus. +func ExportScreenSaver(conn *dbus.Conn, path dbus.ObjectPath, v ScreenSaverer) error { + return conn.ExportSubtreeMethodTable(map[string]interface{}{ + "Inhibit": v.Inhibit, + "UnInhibit": v.UnInhibit, + }, path, InterfaceScreenSaver) +} + +// UnexportScreenSaver unexports org.freedesktop.ScreenSaver interface on the named path. +func UnexportScreenSaver(conn *dbus.Conn, path dbus.ObjectPath) error { + return conn.Export(nil, path, InterfaceScreenSaver) +} + +// UnimplementedScreenSaver can be embedded to have forward compatible server implementations. +type UnimplementedScreenSaver struct{} + +func (*UnimplementedScreenSaver) iface() string { + return InterfaceScreenSaver +} + +func (*UnimplementedScreenSaver) Inhibit(applicationName string, reasonForInhibit string) (cookie uint32, err *dbus.Error) { + err = &dbus.ErrMsgUnknownMethod + return +} + +func (*UnimplementedScreenSaver) UnInhibit(cookie uint32) (err *dbus.Error) { + err = &dbus.ErrMsgUnknownMethod + return +} + +// NewScreenSaver creates and allocates org.freedesktop.ScreenSaver. +func NewScreenSaver(object dbus.BusObject) *ScreenSaver { + return &ScreenSaver{object} +} + +// ScreenSaver implements org.freedesktop.ScreenSaver D-Bus interface. +type ScreenSaver struct { + object dbus.BusObject +} + +// Inhibit calls org.freedesktop.ScreenSaver.Inhibit method. +func (o *ScreenSaver) Inhibit(ctx context.Context, applicationName string, reasonForInhibit string) (cookie uint32, err error) { + err = o.object.CallWithContext(ctx, InterfaceScreenSaver+".Inhibit", 0, applicationName, reasonForInhibit).Store(&cookie) + return +} + +// UnInhibit calls org.freedesktop.ScreenSaver.UnInhibit method. +func (o *ScreenSaver) UnInhibit(ctx context.Context, cookie uint32) (err error) { + err = o.object.CallWithContext(ctx, InterfaceScreenSaver+".UnInhibit", 0, cookie).Store() + return +} From e577e1a7b79e7df7b2460361e7896060c36211e5 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Tue, 11 Feb 2025 21:20:19 +0000 Subject: [PATCH 15/16] Fix output format of generated file --- internal/ui/generated/screensaver.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/ui/generated/screensaver.go b/internal/ui/generated/screensaver.go index e9305f71..d4f96fef 100644 --- a/internal/ui/generated/screensaver.go +++ b/internal/ui/generated/screensaver.go @@ -3,6 +3,7 @@ package screensaver import ( "context" + "github.com/godbus/dbus/v5" "github.com/godbus/dbus/v5/introspect" ) From 65978aee92a5a1edad34328ffe4c1b25977e0667 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Tue, 11 Feb 2025 21:23:42 +0000 Subject: [PATCH 16/16] Don't confuse comment with package doc --- internal/ui/screensaver.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/internal/ui/screensaver.go b/internal/ui/screensaver.go index 84b113a5..2a20e168 100644 --- a/internal/ui/screensaver.go +++ b/internal/ui/screensaver.go @@ -1,6 +1,6 @@ // Note that you need to have github.com/knightpp/dbus-codegen-go installed -// //go:generate dbus-codegen-go -prefix org.freedesktop -package screensaver -output generated/screensaver.go dbus/ScreenSaver.xml + package ui import ( @@ -41,7 +41,9 @@ func (l *desktop) TriggerScreenSaver() { } s.Lock = true - go l.wm.ShowScreensaver(s) + fyne.Do(func() { + l.wm.ShowScreensaver(s) + }) } var lastActivity time.Time @@ -109,14 +111,16 @@ func watchDBus() { type screenSaverWatcher struct { } -func (s *screenSaverWatcher) Inhibit(_ dbus.Sender, _, _ string) (uint, *dbus.Error) { +func (s *screenSaverWatcher) Inhibit(_ dbus.Sender, who, why string) (uint, *dbus.Error) { id := rand.Uint32() inhibitCount++ + // TODO also check these are still alive every so often return uint(id), nil } -func (s *screenSaverWatcher) UnInhibit(_ dbus.Sender, _ uint32) *dbus.Error { +func (s *screenSaverWatcher) UnInhibit(_ dbus.Sender, cookie uint32) *dbus.Error { + // TODO compare to the cookies logged inhibitCount-- return nil }