Windows
Learn about window management.
Wails provides a unified screen API that works across all platforms. Get screen information, detect multiple monitors, query screen properties (size, position, DPI), identify the primary display, and handle DPI scaling with consistent code.
// Get all screensscreens := app.Screen.GetAll()
for _, screen := range screens { fmt.Printf("Screen: %s (%dx%d)\n", screen.Name, screen.Width, screen.Height)}
// Get primary screenprimary := app.Screens.GetPrimary()fmt.Printf("Primary: %s\n", primary.Name)That’s it! Cross-platform screen information.
screens := app.Screen.GetAll()
for _, screen := range screens { fmt.Printf("ID: %s\n", screen.ID) fmt.Printf("Name: %s\n", screen.Name) fmt.Printf("Size: %dx%d\n", screen.Width, screen.Height) fmt.Printf("Position: %d,%d\n", screen.X, screen.Y) fmt.Printf("Scale: %.2f\n", screen.ScaleFactor) fmt.Printf("Primary: %v\n", screen.IsPrimary) fmt.Println("---")}primary := app.Screens.GetPrimary()
fmt.Printf("Primary screen: %s\n", primary.Name)fmt.Printf("Resolution: %dx%d\n", primary.Width, primary.Height)fmt.Printf("Scale factor: %.2f\n", primary.ScaleFactor)Get the screen containing a window:
screen := app.Screens.GetCurrent(window)
fmt.Printf("Window is on: %s\n", screen.Name)screen := app.Screens.GetByID("screen-id")if screen != nil { fmt.Printf("Found screen: %s\n", screen.Name)}type Screen struct { ID string // Unique identifier Name string // Display name X int // X position Y int // Y position Width int // Width in pixels Height int // Height in pixels ScaleFactor float32 // DPI scale (1.0, 1.5, 2.0, etc.) IsPrimary bool // Is this the primary screen?}screen := app.Screens.GetPrimary()
// Logical pixels (what you use)logicalWidth := screen.WidthlogicalHeight := screen.Height
// Physical pixels (actual display)physicalWidth := int(float32(screen.Width) * screen.ScaleFactor)physicalHeight := int(float32(screen.Height) * screen.ScaleFactor)
fmt.Printf("Logical: %dx%d\n", logicalWidth, logicalHeight)fmt.Printf("Physical: %dx%d\n", physicalWidth, physicalHeight)fmt.Printf("Scale: %.2f\n", screen.ScaleFactor)Common scale factors:
1.0 - Standard DPI (96 DPI)1.25 - 125% scaling (120 DPI)1.5 - 150% scaling (144 DPI)2.0 - 200% scaling (192 DPI) - Retina3.0 - 300% scaling (288 DPI) - 4K/5Kfunc centreOnScreen(window *application.WebviewWindow, screen *Screen) { windowWidth, windowHeight := window.Size()
x := screen.X + (screen.Width-windowWidth)/2 y := screen.Y + (screen.Height-windowHeight)/2
window.SetPosition(x, y)}func moveToScreen(window *application.WebviewWindow, screenIndex int) { screens := app.Screen.GetAll()
if screenIndex < 0 || screenIndex >= len(screens) { return }
screen := screens[screenIndex]
// Centre on target screen centreOnScreen(window, screen)}// Top-left cornerfunc positionTopLeft(window *application.WebviewWindow, screen *Screen) { window.SetPosition(screen.X+10, screen.Y+10)}
// Top-right cornerfunc positionTopRight(window *application.WebviewWindow, screen *Screen) { windowWidth, _ := window.Size() window.SetPosition(screen.X+screen.Width-windowWidth-10, screen.Y+10)}
// Bottom-right cornerfunc positionBottomRight(window *application.WebviewWindow, screen *Screen) { windowWidth, windowHeight := window.Size() window.SetPosition( screen.X+screen.Width-windowWidth-10, screen.Y+screen.Height-windowHeight-10, )}func hasMultipleMonitors() bool { return len(app.Screen.GetAll()) > 1}
func getMonitorCount() int { return len(app.Screen.GetAll())}func listMonitors() { screens := app.Screen.GetAll()
fmt.Printf("Found %d monitor(s):\n", len(screens))
for i, screen := range screens { primary := "" if screen.IsPrimary { primary = " (Primary)" }
fmt.Printf("%d. %s%s\n", i+1, screen.Name, primary) fmt.Printf(" Resolution: %dx%d\n", screen.Width, screen.Height) fmt.Printf(" Position: %d,%d\n", screen.X, screen.Y) fmt.Printf(" Scale: %.2fx\n", screen.ScaleFactor) }}func chooseMonitor() (*Screen, error) { screens := app.Screen.GetAll()
if len(screens) == 1 { return screens[0], nil }
// Show dialog to choose var options []string for i, screen := range screens { primary := "" if screen.IsPrimary { primary = " (Primary)" } options = append(options, fmt.Sprintf("%d. %s%s - %dx%d", i+1, screen.Name, primary, screen.Width, screen.Height)) }
// Use dialog to select // (Implementation depends on your dialog system)
return screens[0], nil}type MultiMonitorManager struct { app *application.Application windows map[int]*application.WebviewWindow}
func NewMultiMonitorManager(app *application.Application) *MultiMonitorManager { return &MultiMonitorManager{ app: app, windows: make(map[int]*application.WebviewWindow), }}
func (m *MultiMonitorManager) CreateWindowOnScreen(screenIndex int) error { screens := m.app.Screen.GetAll()
if screenIndex < 0 || screenIndex >= len(screens) { return errors.New("invalid screen index") }
screen := screens[screenIndex]
// Create window window := m.app.Window.NewWithOptions(application.WebviewWindowOptions{ Title: fmt.Sprintf("Window on %s", screen.Name), Width: 800, Height: 600, })
// Centre on screen x := screen.X + (screen.Width-800)/2 y := screen.Y + (screen.Height-600)/2 window.SetPosition(x, y)
window.Show()
m.windows[screenIndex] = window return nil}
func (m *MultiMonitorManager) CreateWindowOnEachScreen() { screens := m.app.Screen.GetAll()
for i := range screens { m.CreateWindowOnScreen(i) }}type ScreenMonitor struct { app *application.Application lastScreens []*Screen changeHandler func([]*Screen)}
func NewScreenMonitor(app *application.Application) *ScreenMonitor { return &ScreenMonitor{ app: app, lastScreens: app.Screen.GetAll(), }}
func (sm *ScreenMonitor) OnScreenChange(handler func([]*Screen)) { sm.changeHandler = handler}
func (sm *ScreenMonitor) Start() { ticker := time.NewTicker(2 * time.Second)
go func() { for range ticker.C { sm.checkScreens() } }()}
func (sm *ScreenMonitor) checkScreens() { current := sm.app.Screen.GetAll()
if len(current) != len(sm.lastScreens) { sm.lastScreens = current if sm.changeHandler != nil { sm.changeHandler(current) } }}func createDPIAwareWindow(screen *Screen) *application.WebviewWindow { // Base size at 1.0 scale baseWidth := 800 baseHeight := 600
// Adjust for DPI width := int(float32(baseWidth) * screen.ScaleFactor) height := int(float32(baseHeight) * screen.ScaleFactor)
window := app.Window.NewWithOptions(application.WebviewWindowOptions{ Title: "DPI-Aware Window", Width: width, Height: height, })
// Centre on screen x := screen.X + (screen.Width-width)/2 y := screen.Y + (screen.Height-height)/2 window.SetPosition(x, y)
return window}func visualiseScreenLayout() string { screens := app.Screen.GetAll()
var layout strings.Builder layout.WriteString("Screen Layout:\n\n")
for i, screen := range screens { primary := "" if screen.IsPrimary { primary = " [PRIMARY]" }
layout.WriteString(fmt.Sprintf("Screen %d: %s%s\n", i+1, screen.Name, primary)) layout.WriteString(fmt.Sprintf(" Position: (%d, %d)\n", screen.X, screen.Y)) layout.WriteString(fmt.Sprintf(" Size: %dx%d\n", screen.Width, screen.Height)) layout.WriteString(fmt.Sprintf(" Scale: %.2fx\n", screen.ScaleFactor)) layout.WriteString(fmt.Sprintf(" Physical: %dx%d\n", int(float32(screen.Width)*screen.ScaleFactor), int(float32(screen.Height)*screen.ScaleFactor))) layout.WriteString("\n") }
return layout.String()}Windows
Learn about window management.
Window Options
Configure window appearance.
Multiple Windows
Multi-window patterns.
Bindings
Call Go functions from JavaScript.
Questions? Ask in Discord or check the screen examples.