Skip to main content

Cross-Platform toolkit to get info on and control monitors connected

Project description

PyMonCtl

Type Checking PyPI version

Cross-Platform module which provides a set of features to get info on and control monitors.

Additional tools/extensions/APIs used:

  • Linux:
    • Xlib's randr extension
    • xrandr command-line tool
    • xset command-line tool
  • Windows:
    • VCP MCCS API interface
  • macOS:
    • pmset command-line tool

My most sincere thanks and appreciation to the University of Utah Student Computing Labs for their awesome work on the display_manager_lib module, for sharing it so generously, and most especially for allowing to be integrated into PyMonCtl

General Features

Functions to get monitor instances, get info and arrange monitors plugged to the system.

General functions:
getAllMonitors
getAllMonitorsDict
getMonitorsCount
getPrimary
findMonitorAtPoint
findMonitorAtPointInfo
findMonitorWithName
findMonitorWithNameInfo
arrangeMonitors
getMousePos

Monitor Class

Class to access all methods and functions to get info and control a given monitor plugged to the system.

This class is not meant to be directly instantiated. Instead, use convenience functions like getAllMonitors(), getPrimary() or findMonitorsAtPoint(x, y). Use PyWinCtl module in case you need to find the monitor a given window is in, by using getDisplay() method which returns the name of the monitor that can directly be used to invoke findMonitorWithName(name) function.

To instantiate it, you need to pass the monitor handle (OS-dependent). It can raise ValueError exception in case the provided handle is not valid.

Methods Windows Linux macOS
size X X X
workarea X X X
position X X X
setPosition X X X
box X X X
rect X X X
frequency X X X
colordepth X X X
dpi X X X
scale X X X
setScale X X
orientation X X X
setOrientation X X X (1)
brightness X (2) X X (1)
setBrightness X (2) X X (1)
contrast X (2) X (3) X (3)
setContrast X (2) X (3) X (3)
mode X X X
setMode X X X
defaultMode X X X
setDefaultMode X X X
allModes X X X
setPrimary X X X
isPrimary X X X
turnOn X X
turnOff X (4) X
isOn X (2) X X
suspend X (4) X (4) X (4)
isSuspended X (2) X X
attach X X
detach X X
isAttached X X X

(1) Through display_manager_lib from University of Utah - Marriott Library - Apple Infrastructure (thank you, guys!).

(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) Working on Windows with VCP MCCS support, otherwise, it will suspend ALL monitors. To address a specific monitor, try using turnOff() / turnOn() / detach() / attach() methods.

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

Important OS-dependent behaviors and limitations:

  • On Windows, primary monitor is mandatory, and it is always placed at (0, 0) coordinates. Besides, the monitors can not overlap. To set a monitor as Primary, it is necessary to reposition primary monitor first, so the rest of monitors will sequentially be repositioned to LEFT.
  • On Linux, primary monitor can be anywhere, and even there can be no primary monitor. Monitors can overlap, so take this into account when setting a new monitor position. Also bear in mind that xrandr won't accept negative values, so the whole setup will be referenced to (0, 0) coordinates.
  • On macOS, primary monitor is mandatory, and it is always placed at (0, 0) coordinates. The monitors can overlap, so take this into account when setting a new monitor position. To set a monitor as Primary, it is necessary to reposition primary monitor first, so the rest of monitors will sequentially be repositioned to LEFT.

It is highly recommended to use arrangeMonitors() function for complex setups or just in case there are two or more monitors.

Keep track of Monitor(s) changes

You can activate a watchdog, running in a separate Thread, which will allow you to keep monitors information updated, without negatively impacting your main process, and define hooks and its callbacks to be
notified when monitors are plugged / unplugged or their properties change.

Watchdog methods:
isWatchdogEnabled
updateWatchdogInterval

The watchdog will automatically start while the update information is enabled and / or there are any listeners registered, and will automatically stop otherwise or if the script finishes.

You can check if the watchdog is working (isWatchdogEnabled()) and also change its update interval (updateWatchdogInterval()) in case you need a custom period (default is 0.5 seconds). Adjust this value to your needs, but take into account that higher values will take longer to detect and notify changes; whilst lower values will consume more CPU and may produce additional notifications for intermediate (non-final) status.

Keep Monitors info updated

Info update methods:
enableUpdateInfo
disableUpdateInfo
isUpdateInfoEnabled

Enable this only if you need to keep track of monitor-related events like changing its resolution, position, scale, or if monitors can be dynamically plugged or unplugged in a multi-monitor setup. If you need monitors info updated at a given moment, but not continuously updated, just invoke getAllMonitors() at your convenience.

If enabled, it will activate a separate thread which will periodically update the list of monitors and their properties (see getAllMonitors() and getAllMonitorsDict() function).

Get notified on Monitors changes

It is possible to register listeners to be invoked in case the number of connected monitors or their properties change.

Listeners methods:
plugListenerRegister
changeListenerRegister
plugListenerUnregister
changeListenerUnregister
isPlugListenerRegistered
isChangeListenerRegistered

The information passed to the listeners is as follows:

  • Names of the monitors which have changed (as a list of strings)
  • All monitors info, as returned by getAllMonitorsDict(). To access monitors properties, use monitor name/s as dictionary key

Example:

import pymonctl as pmc
import time

def countChanged(names, screensInfo):
    print("MONITOR PLUGGED/UNPLUGGED:", names)
    for name in names:
        print("MONITORS INFO:", screensInfo[name])

def propsChanged(names, screensInfo):
    print("MONITOR CHANGED:", names)
    for name in names:
        print("MONITORS INFO:", screensInfo[name])

pmc.plugListenerRegister(countChanged)
pmc.changeListenerRegister(propsChanged)

print("Plug/Unplug monitors, or change monitor properties while running")
print("Press Ctl-C to Quit")
while True:
    try:
        time.sleep(1)
    except KeyboardInterrupt:
        break

pmc.plugListenerUnregister(countChanged)
pmc.changeListenerUnregister(propsChanged)

INSTALL

To install this module on your system, you can use pip:

pip install pymonctl

or

python3 -m pip install pymonctl

Alternatively, you can download the wheel file (.whl) available in the Download page and the dist folder, and run this (don't forget to replace 'x.x.xx' with proper version number):

pip install PyMonCtl-x.x.xx-py3-none-any.whl

You may want to add --force-reinstall option to be sure you are installing the right dependencies version.

Then, you can use it on your own projects just importing it:

import pymonctl

SUPPORT

In case you have a problem, comments or suggestions, do not hesitate to open issues on the project homepage

USING THIS CODE

If you want to use this code or contribute, you can either:

Be sure you install all dependencies described on requirements.txt by using pip

python3 -m pip install -r requirements.txt

TEST

To test this module on your own system, cd to tests folder and run:

python3 test_pymonctl.py

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

PyMonCtl-0.7-py3-none-any.whl (86.2 kB view details)

Uploaded Python 3

File details

Details for the file PyMonCtl-0.7-py3-none-any.whl.

File metadata

  • Download URL: PyMonCtl-0.7-py3-none-any.whl
  • Upload date:
  • Size: 86.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.10.9

File hashes

Hashes for PyMonCtl-0.7-py3-none-any.whl
Algorithm Hash digest
SHA256 20c1f7f4cf46ff3349fa60d4e63c4ac300a2b907c0d984a1dd64d452b85ea781
MD5 d0d795ab424354e992666a5c05d906c7
BLAKE2b-256 a7e1e42776f68f200ce358e8de0e9be6edb189ae867286a71db7470b12931b9f

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page