From 21446dc7c9ce5b320bc60827602e98714a782d09 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sun, 14 Jan 2024 08:31:35 +0000 Subject: [PATCH 1/5] 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 2/5] 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 3/5] 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 4/5] 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 5/5] 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 }