From df5eebb84a7ed08fa0878c64a67c0d1ac76e954a Mon Sep 17 00:00:00 2001 From: mircearoata Date: Tue, 6 Feb 2024 20:13:56 +0100 Subject: [PATCH] Recenter window if it is offscreen --- backend/app/window.go | 124 ++++++++++++++++++++++++--------------- backend/utils/display.go | 19 ++++++ go.mod | 4 ++ go.sum | 9 +++ 4 files changed, 108 insertions(+), 48 deletions(-) create mode 100644 backend/utils/display.go diff --git a/backend/app/window.go b/backend/app/window.go index d40e23a5..02e8a79b 100644 --- a/backend/app/window.go +++ b/backend/app/window.go @@ -1,6 +1,7 @@ package app import ( + "image" "log/slog" "time" @@ -20,59 +21,86 @@ func (a *app) WatchWindow() { case <-a.stopSizeWatcher: return case <-windowStateTicker.C: - if wailsRuntime.WindowIsMinimised(common.AppContext) { - // When the window is minimized, the window position values are garbage - continue - } - w, h := wailsRuntime.WindowGetSize(common.AppContext) - x, y := wailsRuntime.WindowGetPosition(common.AppContext) - changed := false - if a.IsExpanded { - if w != settings.Settings.ExpandedSize.Width { - settings.Settings.ExpandedSize.Width = w - changed = true - } - } else { - if w != settings.Settings.UnexpandedSize.Width { - settings.Settings.UnexpandedSize.Width = w - changed = true - } - } - if h != settings.Settings.ExpandedSize.Height { - settings.Settings.ExpandedSize.Height = h - changed = true - } - if h != settings.Settings.UnexpandedSize.Height { - settings.Settings.UnexpandedSize.Height = h - changed = true - } - if settings.Settings.WindowPosition == nil { - settings.Settings.WindowPosition = &utils.Position{ - X: x, - Y: y, - } - changed = true - } else { - if x != settings.Settings.WindowPosition.X { - settings.Settings.WindowPosition.X = x - changed = true - } - if y != settings.Settings.WindowPosition.Y { - settings.Settings.WindowPosition.Y = y - changed = true - } - } - if changed { - err := settings.SaveSettings() - if err != nil { - slog.Error("failed to save settings", slog.Any("error", err)) - } - } + a.ensureWindowVisible() + a.saveWindowState() } } }() } +func (a *app) ensureWindowVisible() { + if wailsRuntime.WindowIsMinimised(common.AppContext) { + // When the window is minimized, the window position values are garbage + return + } + x, y := wailsRuntime.WindowGetPosition(common.AppContext) + w, h := wailsRuntime.WindowGetSize(common.AppContext) + + window := image.Rect(x, y, x+w, y+h) + + displays := utils.GetDisplayBounds() + + for _, display := range displays { + if display.Overlaps(window) { + return + } + } + + // If the window is not visible, move it to the center of the primary display + wailsRuntime.WindowCenter(common.AppContext) +} + +func (a *app) saveWindowState() { + if wailsRuntime.WindowIsMinimised(common.AppContext) { + // When the window is minimized, the window position values are garbage + return + } + w, h := wailsRuntime.WindowGetSize(common.AppContext) + x, y := wailsRuntime.WindowGetPosition(common.AppContext) + changed := false + if a.IsExpanded { + if w != settings.Settings.ExpandedSize.Width { + settings.Settings.ExpandedSize.Width = w + changed = true + } + } else { + if w != settings.Settings.UnexpandedSize.Width { + settings.Settings.UnexpandedSize.Width = w + changed = true + } + } + if h != settings.Settings.ExpandedSize.Height { + settings.Settings.ExpandedSize.Height = h + changed = true + } + if h != settings.Settings.UnexpandedSize.Height { + settings.Settings.UnexpandedSize.Height = h + changed = true + } + if settings.Settings.WindowPosition == nil { + settings.Settings.WindowPosition = &utils.Position{ + X: x, + Y: y, + } + changed = true + } else { + if x != settings.Settings.WindowPosition.X { + settings.Settings.WindowPosition.X = x + changed = true + } + if y != settings.Settings.WindowPosition.Y { + settings.Settings.WindowPosition.Y = y + changed = true + } + } + if changed { + err := settings.SaveSettings() + if err != nil { + slog.Error("failed to save settings", slog.Any("error", err)) + } + } +} + func (a *app) StopWindowWatcher() { if a.stopSizeWatcher != nil { close(a.stopSizeWatcher) diff --git a/backend/utils/display.go b/backend/utils/display.go new file mode 100644 index 00000000..fccde596 --- /dev/null +++ b/backend/utils/display.go @@ -0,0 +1,19 @@ +package utils + +import ( + "image" + + "github.com/kbinani/screenshot" +) + +func GetDisplayBounds() []image.Rectangle { + n := screenshot.NumActiveDisplays() + + bounds := make([]image.Rectangle, 0, n) + + for i := 0; i < n; i++ { + bounds = append(bounds, screenshot.GetDisplayBounds(i)) + } + + return bounds +} diff --git a/go.mod b/go.mod index e09f76fa..d97103b7 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/Masterminds/semver/v3 v3.2.1 github.com/andygrunwald/vdf v1.1.0 github.com/dustin/go-humanize v1.0.1 + github.com/kbinani/screenshot v0.0.0-20230812210009-b87d31814237 github.com/lmittmann/tint v1.0.3 github.com/minio/selfupdate v0.6.0 github.com/mitchellh/go-ps v1.0.0 @@ -33,6 +34,7 @@ require ( github.com/avast/retry-go v3.0.0+incompatible // indirect github.com/bep/debounce v1.2.1 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gen2brain/shm v0.0.0-20230802011745-f2460f5984f7 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/google/uuid v1.4.0 // indirect @@ -43,6 +45,7 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect + github.com/jezek/xgb v1.1.0 // indirect github.com/jlaffaye/ftp v0.2.0 // indirect github.com/kr/fs v0.1.0 // indirect github.com/labstack/echo/v4 v4.11.3 // indirect @@ -51,6 +54,7 @@ require ( github.com/leaanthony/gosod v1.0.3 // indirect github.com/leaanthony/slicer v1.6.0 // indirect github.com/leaanthony/u v1.1.0 // indirect + github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect diff --git a/go.sum b/go.sum index 88d0bdf6..abb0fbf3 100644 --- a/go.sum +++ b/go.sum @@ -39,6 +39,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= 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/gen2brain/shm v0.0.0-20230802011745-f2460f5984f7 h1:VLEKvjGJYAMCXw0/32r9io61tEXnMWDRxMk+peyRVFc= +github.com/gen2brain/shm v0.0.0-20230802011745-f2460f5984f7/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= @@ -62,8 +64,12 @@ github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= +github.com/jezek/xgb v1.1.0 h1:wnpxJzP1+rkbGclEkmwpVFQWpuE2PUGNUzP8SbfFobk= +github.com/jezek/xgb v1.1.0/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk= github.com/jlaffaye/ftp v0.2.0 h1:lXNvW7cBu7R/68bknOX3MrRIIqZ61zELs1P2RAiA3lg= github.com/jlaffaye/ftp v0.2.0/go.mod h1:is2Ds5qkhceAPy2xD6RLI6hmp/qysSoymZ+Z2uTnspI= +github.com/kbinani/screenshot v0.0.0-20230812210009-b87d31814237 h1:YOp8St+CM/AQ9Vp4XYm4272E77MptJDHkwypQHIRl9Q= +github.com/kbinani/screenshot v0.0.0-20230812210009-b87d31814237/go.mod h1:e7qQlOY68wOz4b82D7n+DdaptZAi+SHW0+yKiWZzEYE= github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= @@ -91,6 +97,8 @@ github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8 github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= github.com/lmittmann/tint v1.0.3 h1:W5PHeA2D8bBJVvabNfQD/XW9HPLZK1XoPZH0cq8NouQ= github.com/lmittmann/tint v1.0.3/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE= +github.com/lxn/win v0.0.0-20210218163916-a377121e959e h1:H+t6A/QJMbhCSEH5rAuRxh+CtW96g0Or0Fxa9IKr4uc= +github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= @@ -224,6 +232,7 @@ golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=