PyWinCtl

raw JSON →
0.4.1 verified Fri May 01 auth: no python

PyWinCtl is a cross-platform Python library (Windows, macOS, Linux with X11/Wayland) for getting information about and controlling on-screen windows. Version 0.4.1 supports Python 3.9+ and provides window enumeration, activation, resizing, moving, and property retrieval. Release cadence is irregular, with major features added every few months.

pip install pywinctl
error AttributeError: module 'pywinctl' has no attribute 'PyWinCtl'
cause Attempting to import 'PyWinCtl' as a class when it is the module name.
fix
Use 'import pywinctl' and then call functions like pywinctl.getAllWindows().
error TypeError: 'NoneType' object is not iterable
cause getAllWindows() returns None on unsupported platforms or if the backend fails.
fix
Check if the result is None before iterating: windows = pywinctl.getAllWindows() or []
error OSError: [WinError 5] Access is denied
cause On Windows, trying to manipulate a window owned by another process (e.g., UIPI) without proper privileges.
fix
Run the script with elevated permissions (admin) or target windows that allow external control.
error ModuleNotFoundError: No module named 'pywinctl._pywinctl_osx'
cause Trying to import internal submodules directly; they are platform-specific and not intended for direct use.
fix
Use the public API: 'import pywinctl' and let the library handle the backend selection.
gotcha On Linux with Wayland, getActiveWindow() may return None unless 'unsafe mode' is enabled. Enable by setting environment variable PYWNCTL_WAYLAND_UNSAFE=1 before import.
fix os.environ['PYWNCTL_WAYLAND_UNSAFE'] = '1' before importing pywinctl.
deprecated The method getDisplay() is deprecated in v0.4 and replaced by getMonitor().
fix Use getMonitor() instead of getDisplay().
breaking MacOS: MacOSNSWindow was removed in v0.4. All window operations now use AppleScript. Code that directly references MacOSNSWindow will break.
fix Use the standard pywinctl API; class MacOSNSWindow no longer exists.
gotcha Window.moveTo() and resizeTo() expect integer coordinates. Passing floats may cause silent failure or unexpected behavior.
fix Always convert to int: win.moveTo(int(x), int(y)).

Basic usage: enumerate windows, get active window, move/resize.

import pywinctl

# Get all windows
windows = pywinctl.getAllWindows()
for win in windows:
    print(f'{win.title}: {win.bbox}')

# Get active window
active = pywinctl.getActiveWindow()
if active:
    print('Active window title:', active.title)

# Move and resize window
win = windows[0]
win.moveTo(100, 100)
win.resizeTo(800, 600)

# Check if window is visible
print('Visible:', win.isVisible)