Skip to content

Commit

Permalink
ALL: Added saveSetup() and restoreSetup(). Fixed / Improved watchdog …
Browse files Browse the repository at this point in the history
…(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
MACOS: Replaced display-manager-lib by other alternatives which seem to work in several macOS versions (brightness only) Added setScale() method (using a workaround). Added wakeup feature to turnOn() method
  • Loading branch information
Kalmat committed Apr 16, 2024
1 parent b36d8c6 commit 3246eb4
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 48 deletions.
8 changes: 0 additions & 8 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,6 @@
/build/
dist/
/src/PyMonCtl.egg-info/
/tests/multi_monitor_coords.py
/make_wheel.bat
/pip_make.bat
/pip_upload.bat
*.cpython-310.pyc
/tests/source-shake.lua
/tests/test.py
/tests/test2.py
/tests/test3.py
/tests/test_cec.py
/tests/_display_manager_lib.py
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,17 @@ the provided handle is not valid.
| isAttached | X | X | X |


(1) Working only in versions older than Catalina
(1) Working only in versions older than Catalina (thanks to University of Utah - Marriott Library - Apple Infrastructure)

(2) If monitor has no VCP MCCS support, these methods won't likely work.

(3) It doesn't exactly return / change contrast, but gamma values.

(4) Windows: Working with VCP MCCS support only.
Linux: It will suspend ALL monitors. To address just one monitor, try using turnOff() / turnOn() / detach() / attach() methods.
macOS: It will suspend ALL monitors. Use turnOn() to wake them up again
(4) Different behaviour according to OS:
- Windows: Working with VCP MCCS support only.
- Linux: It will suspend ALL monitors. To address just one monitor, try using turnOff() / turnOn() / detach() / attach() methods.
- macOS: It will suspend ALL monitors. Use turnOn() to wake them up again


#### WARNING: Most of these properties may return ''None'' in case the value can not be obtained

Expand Down
1 change: 0 additions & 1 deletion src/pymonctl/_pymonctl_linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from __future__ import annotations

import sys
import time

assert sys.platform == "linux"

Expand Down
62 changes: 27 additions & 35 deletions src/pymonctl/_pymonctl_macos.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,14 +202,9 @@ def __init__(self, handle: Optional[int] = None):
break
if self.screen is not None:
self.name = _getName(self.handle, self.screen)
v = platform.mac_ver()[0].split(".")
self._ver = float(v[0] + "." + v[1])
# In Catalina display_manager_lib fails to load IOKit
# In Ventura setBrightness() method fails (it was OK in Big Sur)
# --> Display() class takes around 5 seconds to instantiate!!!
self._ds: Optional[Union[ctypes.CDLL, int]] = None
self._cd: Optional[Union[ctypes.CDLL, int]] = None
self._iokit: Optional[Union[ctypes.CDLL, int]] = None
self._ds: Union[ctypes.CDLL, int] = 0
self._cd: Union[ctypes.CDLL, int] = 0
self._iokit: Union[ctypes.CDLL, int] = 0
self._ioservice: Optional[int] = None
else:
raise ValueError
Expand Down Expand Up @@ -394,9 +389,9 @@ def colordepth(self) -> Optional[int]:
def brightness(self) -> Optional[int]:
res = None
ret = 1
if self._ds is None and self._ds != -1:
if self._ds == 0:
self._ds = _loadDisplayServices()
if self._ds is not None and self._ds != -1:
if self._ds not in (0, -1):
value = ctypes.c_float()
try:
ret = self._ds.DisplayServicesGetBrightness(self.handle, ctypes.byref(value))
Expand All @@ -405,9 +400,9 @@ def brightness(self) -> Optional[int]:
if ret == 0:
res = value.value
if ret != 0:
if self._cd is None and self._cd != -1:
if self._cd == 0:
self._cd = _loadCoreDisplay()
if self._cd is not None and self._cd != -1:
if self._cd not in (0, -1):
value = ctypes.c_double()
try:
ret = self._cd.CoreDisplay_Display_GetUserBrightness(self.handle, ctypes.byref(value))
Expand All @@ -416,9 +411,9 @@ def brightness(self) -> Optional[int]:
if ret == 0:
res = value.value
if ret != 0:
if self._iokit is None and self._iokit != -1:
if self._iokit == 0:
self._iokit, self._ioservice = _loadIOKit(self.handle)
if self._iokit is not None and self._iokit != -1 and self._ioservice is not None:
if self._iokit not in (0, -1) and self._ioservice is not None:
value = ctypes.c_float()
try:
ret = self._iokit.IODisplayGetFloatParameter(self._ioservice, 0, CF.CFSTR("brightness"), ctypes.byref(value))
Expand All @@ -434,28 +429,28 @@ def setBrightness(self, brightness: Optional[int]):
# https://stackoverflow.com/questions/46885603/is-there-a-programmatic-way-to-check-if-brightness-is-at-max-or-min-value-on-osx
if brightness is not None and 0 < brightness < 100:
ret = 1
if self._ds is None and self._ds != -1:
if self._ds == 0:
self._ds = _loadDisplayServices()
if self._ds is not None and self._ds != -1:
if self._ds not in (0, -1):
value = ctypes.c_float(brightness / 100)
try:
if self._ds.DisplayServicesCanChangeBrightness(self.handle):
ret = self._ds.DisplayServicesSetBrightness(self.handle, value)
except:
ret = 1
if ret != 0:
if self._cd is None and self._cd != -1:
if self._cd == 0:
self._cd = _loadCoreDisplay()
if self._cd is not None and self._cd != -1:
if self._cd not in (0, -1):
value = ctypes.c_double(brightness / 100)
try:
ret = self._cd.CoreDisplay_Display_SetUserBrightness(self.handle, value)
except:
ret = 1
if ret != 0:
if self._iokit is None and self._iokit != -1:
if self._iokit == 0:
self._iokit, self._ioservice = _loadIOKit(self.handle)
if self._iokit is not None and self._iokit != -1 and self._ioservice is not None:
if self._iokit not in (0, -1) and self._ioservice is not None:
value = ctypes.c_float(brightness / 100)
try:
ret = self._iokit.IODisplaySetFloatParameter(self._ioservice, 0, CF.CFSTR("brightness"), value)
Expand Down Expand Up @@ -514,21 +509,18 @@ def setMode(self, mode: Optional[DisplayMode]):
# https://stackoverflow.com/questions/10596489/programmatically-change-resolution-os-x
# https://searchcode.com/file/2207916/pyobjc-framework-Quartz/PyObjCTest/test_cgdirectdisplay.py/
if mode is not None:
bestMode, ret = CG.CGDisplayBestModeForParametersAndRefreshRate(self.handle, self.colordepth,
mode.width, mode.height, mode.frequency,
None)
if bestMode:
bw = bestMode[Quartz.kCGDisplayWidth]
bh = bestMode[Quartz.kCGDisplayHeight]
br = bestMode[Quartz.kCGDisplayRefreshRate]
allModes = _CGgetAllModes(self.handle)
for m in allModes:
w = Quartz.CGDisplayModeGetWidth(m)
h = Quartz.CGDisplayModeGetHeight(m)
r = Quartz.CGDisplayModeGetRefreshRate(m)
if w == bw and h == bh and r == br:
CG.CGDisplaySetDisplayMode(self.handle, m, None)
break
# bestMode, ret = CG.CGDisplayBestModeForParametersAndRefreshRate(self.handle, self.colordepth,
# mode.width, mode.height, mode.frequency,
# None)
mw, mh, mr = mode.width, mode.height, mode.frequency
allModes = _CGgetAllModes(self.handle)
for m in allModes:
w = Quartz.CGDisplayModeGetWidth(mode)
h = Quartz.CGDisplayModeGetHeight(mode)
r = Quartz.CGDisplayModeGetRefreshRate(mode)
if w == mw and h == mh and r == mr:
CG.CGDisplaySetDisplayMode(self.handle, m, None)
break

@property
def defaultMode(self) -> Optional[DisplayMode]:
Expand Down
2 changes: 2 additions & 0 deletions tests/test_pymonctl.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ def changedCB(names: List[str], info: dict[str, pmc.ScreenValue]):
targetWidth = 1360
elif monWidth == 1680:
targetWidth = 1280
elif monWidth == 1470:
targetWidth = 1710
for mode in monitor.allModes:
if targetWidth == mode.width:
targetMode = mode
Expand Down

0 comments on commit 3246eb4

Please sign in to comment.