macOS schermresolutie wijzigen via Python/CoreGraphics

Definitie

Op macOS kan de schermresolutie programmatisch worden gewijzigd via de CoreGraphics-bibliotheek, aangesproken vanuit Python met ctypes. Dit werkt zonder extra tools of installaties, ook als Homebrew-pakketten zoals displayplacer niet beschikbaar zijn.

Context

Nuttig wanneer displayplacer niet geinstalleerd kan worden (bijv. Command Line Tools ontbreken), of wanneer je de resolutie wil scripten. Op Retina-displays is de relatie tussen fysieke pixels en UI-grootte omgekeerd: hogere fysieke resolutie = kleinere UI-elementen.

Kernpunten

Retina-logica: De “looks like”-resolutie in macOS System Settings is ruwweg de helft van de fysieke pixels (bij 2x HiDPI). Wil je grotere tekst, kies dan een lagere fysieke resolutie.

Beschikbare modi ophalen:

import ctypes, ctypes.util
 
cg = ctypes.CDLL(ctypes.util.find_library('CoreGraphics'))
cf = ctypes.CDLL(ctypes.util.find_library('CoreFoundation'))
 
cg.CGMainDisplayID.restype = ctypes.c_uint32
display_id = cg.CGMainDisplayID()
 
cg.CGDisplayCopyAllDisplayModes.restype = ctypes.c_void_p
cg.CGDisplayCopyAllDisplayModes.argtypes = [ctypes.c_uint32, ctypes.c_void_p]
modes = cg.CGDisplayCopyAllDisplayModes(display_id, None)
 
cf.CFArrayGetCount.restype = ctypes.c_long
cf.CFArrayGetCount.argtypes = [ctypes.c_void_p]
cf.CFArrayGetValueAtIndex.restype = ctypes.c_void_p
cf.CFArrayGetValueAtIndex.argtypes = [ctypes.c_void_p, ctypes.c_long]
cg.CGDisplayModeGetWidth.restype = ctypes.c_size_t
cg.CGDisplayModeGetWidth.argtypes = [ctypes.c_void_p]
cg.CGDisplayModeGetHeight.restype = ctypes.c_size_t
cg.CGDisplayModeGetHeight.argtypes = [ctypes.c_void_p]
 
for i in range(cf.CFArrayGetCount(modes)):
    mode = cf.CFArrayGetValueAtIndex(modes, i)
    print(cg.CGDisplayModeGetWidth(mode), 'x', cg.CGDisplayModeGetHeight(mode))

Resolutie instellen:

cg.CGDisplaySetDisplayMode.restype = ctypes.c_int32
cg.CGDisplaySetDisplayMode.argtypes = [ctypes.c_uint32, ctypes.c_void_p, ctypes.c_void_p]
 
TARGET_W, TARGET_H = 2560, 1600  # pas aan
 
for i in range(cf.CFArrayGetCount(modes)):
    mode = cf.CFArrayGetValueAtIndex(modes, i)
    if cg.CGDisplayModeGetWidth(mode) == TARGET_W and cg.CGDisplayModeGetHeight(mode) == TARGET_H:
        result = cg.CGDisplaySetDisplayMode(display_id, mode, None)
        print(f"Result: {result} (0 = success)")
        break

Retourneerwaarde 0 = succes. Wijziging is direct zichtbaar, geen herstart nodig.

Stappentabel MacBook Pro 14” Retina (fysiek looks like):

Fysieke pixelsLooks likeUI-grootte
3024x1964~1512x982default (kleine tekst)
2704x1756~1352x878iets groter
2560x1600~1280x800comfortabel
2294x1490~1147x745groot
1920x1200~960x600zeer groot

Noot: De native modus heeft flags=0x02000003, alle andere modi flags=0x00000003.

Verbanden

Bronnen

Geen externe bronnen. Afgeleid via empirisch testen met system_profiler SPDisplaysDataType en CoreGraphics API-documentatie (Apple).

Sessie-herkomst