multimon

package module
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 19, 2026 License: MIT Imports: 5 Imported by: 0

README

multimon

A Go package for handling window positioning and sizing across multiple monitors. Provides utilities for fitting windows to monitors while respecting work areas (taskbars/docks) and handling various edge cases.

Go Reference Tests

Overview

Window positioning and scaling is a common challenge in desktop GUI applications, particularly when handling multiple monitors. Applications need to properly restore window positions between sessions while gracefully handling changes in monitor configurations. This includes cases where displays are added, removed, or rearranged. The package helps ensure windows remain accessible and properly positioned, avoiding issues like windows appearing outside viewable areas or spanning multiple displays inappropriately.

Features

  • Monitor-aware window positioning and sizing
  • Support for work areas (excluding taskbars/docks)
  • Intelligent window fitting based on:
    • Overlap area with monitors
    • Edge distance when no overlap exists
    • Minimum size requirements
  • Initial window placement with:
    • Margin support with minimum size guarantees
    • Automatic centering in work area
  • Cross-platform support (Windows, Linux, macOS)

Installation

go get github.com/adnsv/multimon

This package has no external Go dependencies - it only uses the standard library and CGO bindings to system libraries.

Terminology

Different operating systems handle screen coordinates and display scaling in their own unique ways. Since there isn't standard terminology across platforms, here are the terms we use in this package:

  • Physical Pixels: The smallest addressable unit on the display.

  • Screen Units: Units that are used by the display manager to position windows on the screen. All window coordinates and monitor bounds in this package use screen units.

  • Logical Units: Units that provide resolution-independent way of describing window size and position. Used only when explicitly converting to/from screen units.

On Windows and Linux, screen units and physical pixels are the same. Window positioning, monitor boundaries and mouse cursor movements are done in physical pixel coordinates. Monitors may have display scale factors that provide a mapping between screen units and logical units.

MacOS is different. In MacOS terminology, our screen units correspond to screen points. On regular resolution displays, a screen unit is the same as physical pixel. On Retina displays, a screen unit is 2x2 physical pixels.

Understanding "Effective" DPI terminology:

  • The effective DPI set by display managers is a logical construct to ensure consistent UI scaling and does not directly correspond to the monitor's physical DPI
  • On Windows and linux:
    • Monitors with 100% scaling factor have 96 effective DPI resolution.
    • Monitors with 200% scaling factor have 192 effective DPI resolution.
  • On macOS:
    • It is assumed that non-retina displays have 72 effective DPI resolution.
    • Retina displays have 144 effective DPI resolution.

Platform Support

  • Windows: Native support via Win32 API (pure Go)
  • macOS: Support via Cocoa/AppKit (requires cgo)
  • Linux: Support via GTK3/GDK (requires cgo, gtk3-dev package)

Each platform implementation provides:

  • Monitor enumeration
  • Physical and logical monitor bounds
  • Work area detection (accounting for taskbars/docks)
Dependencies

For non-Windows platforms, this package requires CGO and the appropriate development packages:

  • Linux: gtk3-dev (or libgtk-3-dev on Debian/Ubuntu)
  • macOS: Xcode Command Line Tools (provides Foundation, Cocoa, and AppKit frameworks)

Units Package

The units subpackage provides flexible dimension types for specifying window sizes using different measurement units:

  • Pixels: Absolute pixel values (e.g., 1024, 768)
  • Em units: Relative to system font em-height (e.g., 60em, 40em)
  • Percentages: Relative to work area dimensions (e.g., 80%, 70%)
Usage
import "github.com/adnsv/multimon/units"

// Parse dimension strings
width := units.ParseDimension("60em")   // 60 em units
height := units.ParseDimension("80%")   // 80% of work area
minW := units.ParseDimension("400")     // 400 pixels

// Or create dimensions programmatically
width := units.Ems(60)
height := units.Pct(80)
minW := units.Pixels(400)

// Resolve to pixels using a context
ctx := units.ResolveContext{
    EmHeight: 16,  // System em-height in pixels
    WorkArea: units.WorkArea{Width: 1920, Height: 1080},
}
pixelWidth := width.ResolveWidth(ctx)   // 60 * 16 = 960
pixelHeight := height.ResolveHeight(ctx) // 80% of 1080 = 864
Dimension String Format
Format Example Description
<number> 1024 Absolute pixels
<number>px 1024px Absolute pixels (explicit)
<number>em 60em Multiple of system em-height
<number>% 80% Percentage of work area

Em units are particularly useful for creating resolution-independent window sizes that scale appropriately with the user's font settings.

Core API

Monitor Enumeration
// Get all connected monitors
monitors := multimon.GetMonitors()
Finding Monitors
// Find monitor containing a screen point
monitor := multimon.FindMonitorFromScreenPoint(monitors, x, y, multimon.DefaultMonitorNearest)

// Find monitor with largest overlap with a rectangle
monitor := multimon.FindMonitorFromScreenRect(monitors, rect, multimon.DefaultMonitorNearest)

// Find primary monitor (contains 0,0 or first available)
monitor := multimon.FindPrimaryMonitor(monitors)

// Get work area for a window rectangle (convenience function)
workArea := multimon.GetWorkAreaForRect(monitors, windowRect)
Default Monitor Modes

When no exact match is found, the defaultTo parameter controls fallback behavior:

Mode Description
DefaultMonitorNull Returns nil if no monitor matches
DefaultMonitorPrimary Returns the primary monitor
DefaultMonitorNearest Returns the monitor with smallest edge distance

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrInvalidDimensions = errors.New("invalid dimensions: negative width or height")

ErrInvalidDimensions is returned when a window or monitor has negative dimensions

View Source
var ErrNoMonitors = errors.New("no monitors available")

ErrNoMonitors is returned when no monitors are available for fitting

Functions

func CalcPlacementSize added in v0.2.1

func CalcPlacementSize(m *Monitor, desiredWidth, desiredHeight, minWidth, minHeight, margin int) (width, height int)

CalcPlacementSize calculates the window size in screen units, attempting to satisfy the desired size while fitting within monitor bounds: 1. Converts desired size to screen units using monitor's scale 2. Attempts to fit within work area minus margins 3. If needed, allows using margin area to satisfy minimum size

Parameters: - desiredWidth, desiredHeight: preferred window size in logical units - minWidth, minHeight: minimum required window size in logical units - margin: minimum distance from work area edges in logical units

Returns width and height in screen units.

Types

type DefaultMonitorMode added in v0.2.1

type DefaultMonitorMode int

DefaultMonitorMode specifies how to select a monitor when no exact match is found

const (
	// DefaultMonitorNull returns nil if no monitor matches the criteria
	DefaultMonitorNull DefaultMonitorMode = iota
	// DefaultMonitorPrimary returns the monitor containing (0,0) in screen coordinates,
	// or the first available monitor if no monitor contains (0,0)
	DefaultMonitorPrimary
	// DefaultMonitorNearest returns the monitor with smallest edge distance to the target
	DefaultMonitorNearest
)

type FitMode

type FitMode int

FitMode specifies how to fit a window to a monitor

const (
	// FitModeBounds fits to monitor's total bounds
	FitModeBounds FitMode = iota
	// FitModeWorkArea fits to monitor's work area (excluding taskbar, dock, etc.)
	FitModeWorkArea
)

type Monitor

type Monitor = types.Monitor

Monitor represents a display monitor and its properties

func FindMonitorFromScreenPoint added in v0.2.1

func FindMonitorFromScreenPoint(monitors []Monitor, x, y int, defaultTo DefaultMonitorMode) *Monitor

FindMonitorFromScreenPoint finds the monitor that contains the given screen point. If no monitor contains the point: - DefaultMonitorNearest: returns the nearest monitor - DefaultMonitorPrimary: returns the primary monitor - DefaultMonitorNull: returns nil

func FindMonitorFromScreenRect added in v0.2.1

func FindMonitorFromScreenRect(monitors []Monitor, rect Rect, defaultTo DefaultMonitorMode) *Monitor

FindMonitorFromScreenRect finds a monitor with the largest overlap with the given rect in screen coordinates. If no monitor has overlap: - DefaultMonitorNearest: returns the monitor with smallest edge distance - DefaultMonitorPrimary: returns the primary monitor - DefaultMonitorNull: returns nil

func FindPrimaryMonitor added in v0.2.1

func FindPrimaryMonitor(monitors []Monitor) *Monitor

FindPrimaryMonitor returns the monitor containing (0,0) in screen coordinates, or the first available monitor if no monitor contains (0,0). Returns nil if no monitors are available.

func GetMonitors

func GetMonitors() []Monitor

GetMonitors returns monitor information

type Point added in v0.2.1

type Point struct {
	X, Y int
}

Point represents a point in 2D space

func LogicalToScreenPoint added in v0.2.1

func LogicalToScreenPoint(m Monitor, x, y int) Point

LogicalToScreenPoint converts a logical point to screen coordinates for a given monitor

func ScreenToLogicalPoint added in v0.2.1

func ScreenToLogicalPoint(m Monitor, x, y int) Point

ScreenToLogicalPoint converts a screen point to logical coordinates for a given monitor

type Rect

type Rect = types.Rect

Rect represents a rectangle with coordinates in screen space

func FitToMonitor

func FitToMonitor(m *Monitor, mode FitMode, window Rect, windowScale float64) (Rect, float64, error)

FitToMonitor fits a window to a specific monitor. Input window coordinates are in screen units. windowScale specifies what scale factor the window was designed for: - If 0.0: keep window as is, no rescaling needed - If > 0.0: rescale window from windowScale to monitor's scale Returns error if window or monitor has negative dimensions. Returns the fitted rect and the monitor's scale factor. If monitor is nil, returns windowScale if non-zero, otherwise 1.0.

func FitToNearestMonitor

func FitToNearestMonitor(monitors []Monitor, mode FitMode, window Rect, windowScale float64, minWidth, minHeight int) (Rect, float64, error)

FitToNearestMonitor finds the most appropriate monitor and fits the window to it. Input window coordinates are in screen units. windowScale specifies what scale factor the window was designed for: - If 0.0: keep window as is, no rescaling needed - If > 0.0: rescale window from windowScale to monitor's scale minWidth and minHeight specify the minimum dimensions the window should have (in logical units). Returns error if window has negative dimensions, if no valid monitors are available, or if no monitor can fit the minimum size requirements. If no monitors are available, returns windowScale if non-zero, otherwise 1.0.

func GetWorkAreaForRect added in v0.6.0

func GetWorkAreaForRect(monitors []Monitor, rect Rect) Rect

GetWorkAreaForRect returns the work area of the monitor containing the given rect. Returns an empty Rect if no monitors are available.

func InitialPlacement added in v0.2.0

func InitialPlacement(desiredWidth, desiredHeight, minWidth, minHeight, margin int) (Rect, float64)

InitialPlacement calculates the initial window placement centered on a primary monitor. Window size is determined by logic implemented in CalcPlacementSize.

Parameters: - desiredWidth, desiredHeight: preferred window size in logical units - minWidth, minHeight: minimum required window size in logical units - margin: minimum distance from work area edges in logical units

Returns a Rect with the calculated window position and size in screen units, and the scale factor of the selected monitor (1.0 if no monitor is available).

func LogicalToScreenRect added in v0.2.1

func LogicalToScreenRect(m Monitor, logical Rect) Rect

LogicalToScreenRect converts logical coordinates to screen units for a given monitor

func ScreenToLogicalRect added in v0.2.1

func ScreenToLogicalRect(m Monitor, screen Rect) Rect

ScreenToLogicalRect converts screen coordinates to logical units for a given monitor

Directories

Path Synopsis
Package units provides dimension types for specifying window sizes in pixels, em-units (relative to system font), or percentages (relative to work area).
Package units provides dimension types for specifying window sizes in pixels, em-units (relative to system font), or percentages (relative to work area).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL