diff --git a/CHANGES.txt b/CHANGES.txt index ab9fe4a..2ca2ba0 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,6 @@ 0.93, 2026/XX/XX -- ALL: Replaced bare `except:` clauses with `except Exception:`, preventing accidental suppression of system-exit signals (KeyboardInterrupt, SystemExit) during error handling. ALL: Removed dependency on `typing_extensions` + ALL: Allow `getPrimary` to return `None` if the underlying `Monitor()` call throws a `ValueError` (no primary monitor) 0.8, 2023/10/11 -- ALL: Added saveSetup() and restoreSetup(). Fixed / Improved watchdog (especially in Linux). Fixed / improved setPosition() method LINUX: Added ewmhlib as separate module. Fixed watchdog (freezing randomly invoking screen_resources and get_output_info), fixed workarea crash (some apps/environments do not set it), improved to work almost fine in Manjaro/KDE, avoid crashing in Wayland for "fake" :1 display (though module won't likely work) WIN32: Fixed dev.StateFlags returning weird values for multi-monitor. Fixed GetAwarenessFromDpiAwarenessContext not supported on Windows Server diff --git a/src/pymonctl/_main.py b/src/pymonctl/_main.py index a4fdaa4..89bf271 100644 --- a/src/pymonctl/_main.py +++ b/src/pymonctl/_main.py @@ -100,14 +100,20 @@ def getMonitorsCount() -> int: """ return _getMonitorsCount() - -def getPrimary() -> Monitor: +def getPrimary() -> Monitor | None: """ - Get primary monitor instance. This is equivalent to invoking ''Monitor()'', with empty input params. + Get primary monitor instance. + + This is equivalent to invoking `Monitor()`, with empty input params. + With a fallback to None in case of `ValueError`. + Which usually means lack of primary (or any) monitor. :return: Monitor instance or None """ - return _getPrimary() + try: + return Monitor() + except ValueError: + return None def findMonitorsAtPoint(x: int, y: int) -> list[Monitor]: @@ -202,6 +208,15 @@ def arrangeMonitors(arrangement: dict[str, dict[str, str | int | Position | Poin _arrangeMonitors(arrangement) +def getMousePos() -> Point: + """ + Get the current (x, y) coordinates of the mouse pointer on screen, in pixels + + :return: Point struct + """ + return _getMousePos() + + def saveSetup() -> list[tuple[Monitor, ScreenValue]]: """ Save current monitors setup information to be restored afterward. @@ -1003,16 +1018,16 @@ def _getRelativePosition(monitor, relativeTo) -> tuple[int, int]: if sys.platform == "darwin": - from ._pymonctl_macos import (_getAllMonitors, _getAllMonitorsDict, _getMonitorsCount, _getPrimary, - _findMonitor, _arrangeMonitors, _getMousePos as getMousePos, MacOSMonitor as Monitor + from ._pymonctl_macos import (_getAllMonitors, _getAllMonitorsDict, _getMonitorsCount, + _findMonitor, _arrangeMonitors, _getMousePos, MacOSMonitor as Monitor ) elif sys.platform == "win32": - from ._pymonctl_win import (_getAllMonitors, _getAllMonitorsDict, _getMonitorsCount, _getPrimary, - _findMonitor, _arrangeMonitors, _getMousePos as getMousePos, Win32Monitor as Monitor + from ._pymonctl_win import (_getAllMonitors, _getAllMonitorsDict, _getMonitorsCount, + _findMonitor, _arrangeMonitors, _getMousePos, Win32Monitor as Monitor ) elif sys.platform == "linux": from ._pymonctl_linux import (_getAllMonitors, _getAllMonitorsDict, _getAllMonitorsDictThread, _getMonitorsData, - _getMonitorsCount, _getPrimary, _findMonitor, _arrangeMonitors, _getMousePos as getMousePos, + _getMonitorsCount, _findMonitor, _arrangeMonitors, _getMousePos, LinuxMonitor as Monitor ) else: diff --git a/src/pymonctl/_pymonctl_linux.py b/src/pymonctl/_pymonctl_linux.py index 129ce2a..eda40d4 100644 --- a/src/pymonctl/_pymonctl_linux.py +++ b/src/pymonctl/_pymonctl_linux.py @@ -114,10 +114,6 @@ def _findMonitor(x: int, y: int) -> list[LinuxMonitor]: return monitors -def _getPrimary() -> LinuxMonitor: - return LinuxMonitor() - - def _arrangeMonitors(arrangement: dict[str, dict[str, str | int | Position | Point | Size | None]]): monitors = _XgetMonitorsDict() @@ -224,6 +220,7 @@ def __init__(self, handle: int | None = None) -> None: getPrimary() or findMonitor(x, y). It can raise ValueError exception in case provided handle is not valid + or there's no primary monitor with no provided handle. """ monitorData = _XgetMonitorData(handle) if monitorData: diff --git a/src/pymonctl/_pymonctl_macos.py b/src/pymonctl/_pymonctl_macos.py index d0c1ef8..7027fa7 100644 --- a/src/pymonctl/_pymonctl_macos.py +++ b/src/pymonctl/_pymonctl_macos.py @@ -76,12 +76,7 @@ def _findMonitor(x: int, y: int) -> list[MacOSMonitor]: return [MacOSMonitor(displayId) for displayId in ids] -def _getPrimary() -> MacOSMonitor: - return MacOSMonitor() - - def _arrangeMonitors(arrangement: dict[str, dict[str, str | int | Position | Point | Size | None]]): - monitors = _NSgetAllMonitorsDict() primaryPresent = False setAsPrimary = "" diff --git a/src/pymonctl/_pymonctl_win.py b/src/pymonctl/_pymonctl_win.py index 4f1a873..1b0352b 100644 --- a/src/pymonctl/_pymonctl_win.py +++ b/src/pymonctl/_pymonctl_win.py @@ -109,10 +109,6 @@ def _findMonitor(x: int, y: int) -> list[Win32Monitor]: return [] -def _getPrimary() -> Win32Monitor: - return Win32Monitor() - - def _arrangeMonitors(arrangement: dict[str, dict[str, str | int | Position | Point | Size | None]]): # https://stackoverflow.com/questions/35814309/winapi-changedisplaysettingsex-does-not-work # https://stackoverflow.com/questions/195267/use-windows-api-from-c-sharp-to-set-primary-monitor diff --git a/tests/test_pymonctl.py b/tests/test_pymonctl.py index 327794f..51f0078 100644 --- a/tests/test_pymonctl.py +++ b/tests/test_pymonctl.py @@ -6,7 +6,6 @@ import pymonctl as pmc - _TIMELAP = 5 @@ -25,10 +24,8 @@ def changedCB(names: list[str], info: dict[str, pmc.ScreenValue]) -> None: print("MONITORS COUNT:", pmc.getMonitorsCount()) -try: - print("PRIMARY MONITOR:", pmc.getPrimary().name) -except ValueError: - print("PRIMARY MONITOR: None") +primary = pmc.getPrimary() +print("PRIMARY MONITOR:", primary and primary.name) print() monDict = pmc.getAllMonitorsDict() for mon in monDict: