diff --git a/backend/utils/display.go b/backend/utils/display.go index fccde596..fcf3e794 100644 --- a/backend/utils/display.go +++ b/backend/utils/display.go @@ -2,6 +2,7 @@ package utils import ( "image" + "runtime" "github.com/kbinani/screenshot" ) @@ -15,5 +16,34 @@ func GetDisplayBounds() []image.Rectangle { bounds = append(bounds, screenshot.GetDisplayBounds(i)) } + if runtime.GOOS == "linux" { + // gdk_monitor_get_geometry considers 0,0 to be the corner of the bounding box of all the monitors, + // not the 0,0 of the main monitor + boundingBox := bounds[0] + for _, b := range bounds { + boundingBox = boundingBox.Union(b) + } + for i := range bounds { + bounds[i] = bounds[i].Sub(boundingBox.Min) + } + } + return bounds } + +func GetDisplayBoundsAt(x, y int) image.Rectangle { + point := image.Pt(x, y) + + displays := GetDisplayBounds() + + curDisplay := displays[0] // use main display as fallback + + for _, d := range displays { + if point.In(d) { + curDisplay = d + break + } + } + + return curDisplay +} diff --git a/backend/wailsextras/window.go b/backend/wailsextras/window.go new file mode 100644 index 00000000..8bf2dec4 --- /dev/null +++ b/backend/wailsextras/window.go @@ -0,0 +1,30 @@ +package wailsextras + +import ( + "context" + "runtime" + + wailsRuntime "github.com/wailsapp/wails/v2/pkg/runtime" + + "github.com/satisfactorymodding/SatisfactoryModManager/backend/utils" +) + +// WindowSetPosition wraps Wails's WindowSetPosition, +// but ensures that WindowSetPosition(WindowGetPosition()) +// will result in the window remaining stationary +// regardless of OS's behaviour with multiple displays +func WindowSetPosition(ctx context.Context, x, y int) { + if runtime.GOOS == "windows" || runtime.GOOS == "linux" { + // WindowSetPosition expects relative to the current monitor, + // but WindowGetPosition returns absolute + curX, curY := wailsRuntime.WindowGetPosition(ctx) + display := utils.GetDisplayBoundsAt(curX, curY) + x -= display.Min.X + y -= display.Min.Y + } + + // It appears that on darwin Wails gets and sets the position + // with values relative to the current monitor + + wailsRuntime.WindowSetPosition(ctx, x, y) +} diff --git a/main.go b/main.go index 8f9e4652..94c357fb 100644 --- a/main.go +++ b/main.go @@ -14,7 +14,6 @@ import ( "github.com/wailsapp/wails/v2" "github.com/wailsapp/wails/v2/pkg/options" "github.com/wailsapp/wails/v2/pkg/options/assetserver" - wailsRuntime "github.com/wailsapp/wails/v2/pkg/runtime" "github.com/satisfactorymodding/SatisfactoryModManager/backend" "github.com/satisfactorymodding/SatisfactoryModManager/backend/app" @@ -25,6 +24,7 @@ import ( "github.com/satisfactorymodding/SatisfactoryModManager/backend/logging" "github.com/satisfactorymodding/SatisfactoryModManager/backend/settings" "github.com/satisfactorymodding/SatisfactoryModManager/backend/utils" + "github.com/satisfactorymodding/SatisfactoryModManager/backend/wailsextras" "github.com/satisfactorymodding/SatisfactoryModManager/backend/websocket" ) @@ -96,7 +96,9 @@ func main() { appCommon.AppContext = ctx // Wails doesn't support setting the window position on init, so we do it here - loadWindowLocation(ctx) + if settings.Settings.WindowPosition != nil { + wailsextras.WindowSetPosition(ctx, settings.Settings.WindowPosition.X, settings.Settings.WindowPosition.Y) + } app.App.WatchWindow() //nolint:contextcheck go websocket.ListenAndServeWebsocket() @@ -137,23 +139,6 @@ func main() { } } -func loadWindowLocation(ctx context.Context) { - if settings.Settings.WindowPosition != nil { - // Setting the window location is relative to the current monitor, - // but we save it as absolute position. - - wailsRuntime.WindowSetPosition(ctx, 0, 0) - - // Get the location the window was actually placed at - monitorLeft, monitorTop := wailsRuntime.WindowGetPosition(ctx) - - x := settings.Settings.WindowPosition.X - monitorLeft - y := settings.Settings.WindowPosition.Y - monitorTop - - wailsRuntime.WindowSetPosition(ctx, x, y) - } -} - func init() { // Pass build-time variables to viper if len(version) > 0 && version[0] == 'v' {