Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import re
import time
from urllib.request import urlretrieve

project = 'PyMonCtl'
year = time.strftime("%Y")
Expand Down Expand Up @@ -42,8 +43,6 @@

# -- Copy the modules documentation ------------------------------------------
# https://stackoverflow.com/questions/66495200/is-it-possible-to-include-external-rst-files-in-my-documentation
from urllib.request import urlretrieve

urlretrieve(
"https://raw.githubusercontent.com/kalmat/pymonctl/master/README.md",
"index.md"
Expand Down
10 changes: 0 additions & 10 deletions ruff.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,6 @@ ignore = [
# TODO: Consider later
"UP031", # printf-string-formatting
"RUF059", # unused-unpacked-variable

# TODO: Not autofixable, address in a separate PR !
"E402",
"E722",
"F401",
"PERF401",
"PYI063",
"RUF003",
"RUF012",
"RUF022",
]
# F401 would remove imports not marked as explicit re-exports, which may break API boundaries
extend-unsafe-fixes = ["F401"]
Expand Down
17 changes: 9 additions & 8 deletions src/pymonctl/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
#!/usr/bin/python
from importlib.metadata import version as _importlib_version

from ._main import (getAllMonitors, getAllMonitorsDict, getMonitorsCount, getPrimary,
findMonitorsAtPoint, findMonitorsAtPointInfo, findMonitorWithName, findMonitorWithNameInfo,
saveSetup, restoreSetup, arrangeMonitors, getMousePos, Monitor,
enableUpdateInfo, disableUpdateInfo, isUpdateInfoEnabled, isWatchdogEnabled, updateWatchdogInterval,
plugListenerRegister, plugListenerUnregister, isPlugListenerRegistered,
changeListenerRegister, changeListenerUnregister, isChangeListenerRegistered,
DisplayMode, ScreenValue, Size, Point, Box, Rect, Position, Orientation
)

__all__ = [
"getAllMonitors", "getAllMonitorsDict", "getMonitorsCount", "getPrimary",
"findMonitorsAtPoint", "findMonitorsAtPointInfo", "findMonitorWithName", "findMonitorWithNameInfo",
Expand All @@ -19,11 +28,3 @@ def version(numberOnly: bool = True) -> str:
return ("" if numberOnly else "PyMonCtl-")+__version__


from ._main import (getAllMonitors, getAllMonitorsDict, getMonitorsCount, getPrimary,
findMonitorsAtPoint, findMonitorsAtPointInfo, findMonitorWithName, findMonitorWithNameInfo,
saveSetup, restoreSetup, arrangeMonitors, getMousePos, Monitor,
enableUpdateInfo, disableUpdateInfo, isUpdateInfoEnabled, isWatchdogEnabled, updateWatchdogInterval,
plugListenerRegister, plugListenerUnregister, isPlugListenerRegistered,
changeListenerRegister, changeListenerUnregister, isChangeListenerRegistered,
DisplayMode, ScreenValue, Size, Point, Box, Rect, Position, Orientation
)
15 changes: 7 additions & 8 deletions src/pymonctl/_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,11 +212,7 @@ def saveSetup() -> list[tuple[Monitor, ScreenValue]]:

:return: list of tuples containing all necessary info to restore saved setup as required by restoreSetup()
"""
result: list[tuple[Monitor, ScreenValue]] = []
monDict: dict[str, ScreenValue] = getAllMonitorsDict()
for monName in monDict.keys():
result.append((Monitor(monDict[monName]["id"]), monDict[monName]))
return result
return [(Monitor(screenValue["id"]), screenValue) for screenValue in getAllMonitorsDict().values()]


def restoreSetup(setup: list[tuple[Monitor, ScreenValue]]):
Expand Down Expand Up @@ -1002,18 +998,21 @@ def _getRelativePosition(monitor, relativeTo) -> tuple[int, int]:
return x, y



if sys.platform == "darwin":
from ._pymonctl_macos import (_getAllMonitors, _getAllMonitorsDict, _getMonitorsCount, _getPrimary,
_findMonitor, _arrangeMonitors, _getMousePos as getMousePos, MacOSMonitor as Monitor
_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
_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, _getPrimary, _findMonitor, _arrangeMonitors, _getMousePos,
LinuxMonitor as Monitor
)
else:
raise NotImplementedError('PyMonCtl currently does not support this platform. If you think you can help, please contribute! https://github.com/Kalmat/PyMonCtl')

getMousePos = _getMousePos
19 changes: 10 additions & 9 deletions src/pymonctl/_pymonctl_linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

import sys

assert sys.platform == "linux"
if sys.platform != "linux":
raise OSError(f"Cannot import {__name__} on {sys.platform}")

import math
import os
Expand Down Expand Up @@ -107,11 +108,11 @@ def _getMonitorsCount() -> int:


def _findMonitor(x: int, y: int) -> list[LinuxMonitor]:
monitors = []
for monitor in _XgetMonitors():
if _pointInBox(x, y, monitor.x, monitor.y, monitor.width_in_pixels, monitor.height_in_pixels):
monitors.append(LinuxMonitor(monitor.crtcs[0]))
return monitors
return [
LinuxMonitor(monitor.crtcs[0])
for monitor in _XgetMonitors()
if _pointInBox(x, y, monitor.x, monitor.y, monitor.width_in_pixels, monitor.height_in_pixels)
]


def _getPrimary() -> LinuxMonitor:
Expand Down Expand Up @@ -377,9 +378,9 @@ def dpi(self) -> tuple[float, float] | None:
monitors = _XgetMonitors(self.name)
if monitors:
monitor = monitors[0]
_x, _y, w, h = monitor.x, monitor.y, monitor.width_in_pixels, monitor.height_in_pixels
if monitor.width_in_millimeters != 0 and monitor.height_in_millimeters != 0:
dpiX, dpiY = round((w * 25.4) / monitor.width_in_millimeters), round((h * 25.4) / monitor.height_in_millimeters)
dpiX = round((monitor.width_in_pixels * 25.4) / monitor.width_in_millimeters),
dpiY = round((monitor.height_in_pixels * 25.4) / monitor.height_in_millimeters)
else:
dpiX, dpiY = 0.0, 0.0
return dpiX, dpiY
Expand Down Expand Up @@ -1001,7 +1002,7 @@ def _XgetMonitorData(handle: int | None = None) -> tuple[Xlib.display.Display, S
for monitorData in _XgetAllMonitors():
display, screen, root, monitor, monName = monitorData
output = monitor.crtcs[0]
if (handle and handle == output) or (not handle and monitor.primary == 1):
if (handle == output if handle else monitor.primary == 1):
return display, screen, root, monitor, output, monName
return None

Expand Down
11 changes: 5 additions & 6 deletions src/pymonctl/_pymonctl_macos.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
import ctypes

import sys
assert sys.platform == "darwin"

if sys.platform != "darwin":
raise OSError(f"Cannot import {__name__} on {sys.platform}")

import subprocess
import threading
Expand All @@ -22,11 +24,8 @@


def _getAllMonitors() -> list[MacOSMonitor]:
monitors = []
v, ids, cnt = CG.CGGetOnlineDisplayList(10, None, None) # --> How to get display name from this?
for displayId in ids:
monitors.append(MacOSMonitor(displayId))
return monitors
return [MacOSMonitor(displayId) for displayId in ids]


def _getAllMonitorsDict() -> dict[str, ScreenValue]:
Expand Down Expand Up @@ -617,7 +616,7 @@ def isOn(self) -> bool | None:
return bool(CG.CGDisplayIsActive(self.handle) == 1)

def suspend(self):
# Also injecting: ControlShiftMedia_Eject
# Also injecting: Control-Shift-Media_Eject
cmd = "pmset displaysleepnow"
try:
_ = subprocess.run(cmd, text=True, shell=True, capture_output=True, timeout=1)
Expand Down
7 changes: 4 additions & 3 deletions src/pymonctl/_pymonctl_win.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
from __future__ import annotations

import sys
assert sys.platform == "win32"

if sys.platform != "win32":
raise OSError(f"Cannot import {__name__} on {sys.platform}")

import gc
import platform
Expand Down Expand Up @@ -849,8 +851,7 @@ class _PHYSICAL_MONITOR(ctypes.Structure):
physical_array = (_PHYSICAL_MONITOR * count.value)()
ret = ctypes.windll.dxva2.GetPhysicalMonitorsFromHMONITOR(hMon, count.value, physical_array)
if ret:
for physical in physical_array:
handles.append(physical.handle)
handles.extend([physical.handle for physical in physical_array])
return handles


Expand Down
Loading
Loading