6

Is there a cross platform way to get the monitor's refresh rate in python (2.6)? I'm using Pygame and PyOpenGL, if that helps.

I don't need to change the refresh rate, I just need to know what it is.

Brad Zeis
  • 10,085
  • 5
  • 26
  • 20
  • What are you going to use the refresh rate for, if I might ask? If you are writing a game loop or something, you generally don't need to use the refresh rate. – Mike Daniels Aug 03 '09 at 23:49
  • When my app is running in full screen, v-sync is enabled which caps the fps at the refresh rate. V-sync isn't enabled in windowed mode, and the fps is many times faster. I want it to run at the same speed in windowed and fullscreen, so I want to set the maximum fps as the refresh rate of the monitor. – Brad Zeis Aug 04 '09 at 01:22
  • You should not tie your game logic and your render rate together as much as you have. Look here for some alternative game loop constructions: http://dewitters.koonsolo.com/gameloop.html – Mike Daniels Aug 04 '09 at 04:29

4 Answers4

10

I am not sure about the platform you use, but on window you can use ctypes or win32api to get details about devices e.g. using win32api

import win32api

def printInfo(device):
    print((device.DeviceName, device.DeviceString))
    settings = win32api.EnumDisplaySettings(device.DeviceName, -1)
    for varName in ['Color', 'BitsPerPel', 'DisplayFrequency']:
        print("%s: %s"%(varName, getattr(settings, varName)))

device = win32api.EnumDisplayDevices()
printInfo(device)

output on my system:

\\.\DISPLAY1 Mobile Intel(R) 945GM Express Chipset Family
Color: 0
BitsPerPel: 8
DisplayFrequency: 60
Smiley Barry
  • 150
  • 1
  • 8
Anurag Uniyal
  • 85,954
  • 40
  • 175
  • 219
0

On macOS, you can use pyobjc to query the refresh rate of all the attached displays. You'll need the Cocoa (i.e. "AppKit") framework for this:

$ python3 -m venv screen-res
$ . ./screen-res/bin/activate
$ pip install pyobjc-framework-Cocoa

then, in Python:

from AppKit import NSScreen

for each in NSScreen.screens():
    print(f"{each.localizedName()}: {each.maximumFramesPerSecond()}Hz")

On my system, this produces:

LG HDR WQHD+: 120Hz
Built-in Retina Display: 120Hz

(Which is correct, my displays are indeed both set to a 120Hz refresh rate.)

On Linux, you can use python-xlib:

from Xlib import display
from Xlib.ext import randr
d = display.Display()
default_screen = d.get_default_screen()
info = d.screen(default_screen)

resources = randr.get_screen_resources(info.root)
active_modes = set()
for crtc in resources.crtcs:
    crtc_info = randr.get_crtc_info(info.root, crtc, resources.config_timestamp)
    if crtc_info.mode:
        active_modes.add(crtc_info.mode)

for mode in resources.modes:
    if mode.id in active_modes:
        print(mode.dot_clock / (mode.h_total * mode.v_total))

Associating the appropriate screen index number with the place you want your PyOpenGL window to open up on is left as an exercise for the reader :).

(I won't duplicate Anurag's answer for Windows here, especially since I can't test it, but that's how you would do it on that platform.)

Eevee
  • 47,412
  • 11
  • 95
  • 127
Glyph
  • 31,152
  • 11
  • 87
  • 129
0

You can use DEVMODEW, but this only works on Windows Machines.

Install 'wmi' using pip with "pip install wmi"

import ctypes
import wmi
from time import sleep

class DEVMODEW(ctypes.Structure): # Defines the DEVMODEW Structure
_fields_ = [
    ("dmDeviceName", ctypes.c_wchar * 32),
    ("dmSpecVersion", ctypes.c_uint16),
    ("dmDriverVersion", ctypes.c_uint16),
    ("dmSize", ctypes.c_uint32),
    ("dmDriverExtra", ctypes.c_uint16),
    ("dmFields", ctypes.c_uint32),
    ("dmPosition", ctypes.c_int32 * 2),
    ("dmDisplayOrientation", ctypes.c_uint32),
    ("dmDisplayFixedOutput", ctypes.c_uint32),
    ("dmColor", ctypes.c_short),
    ("dmDuplex", ctypes.c_short),
    ("dmYResolution", ctypes.c_short),
    ("dmTTOption", ctypes.c_short),
    ("dmCollate", ctypes.c_short),
    ("dmFormName", ctypes.c_wchar * 32),
    ("dmLogPixels", ctypes.c_uint16),
    ("dmBitsPerPel", ctypes.c_uint32),
    ("dmPelsWidth", ctypes.c_uint32),
    ("dmPelsHeight", ctypes.c_uint32),
    ("dmDisplayFlags", ctypes.c_uint32),
    ("dmDisplayFrequency", ctypes.c_uint32),
    ("dmICMMethod", ctypes.c_uint32),
    ("dmICMIntent", ctypes.c_uint32),
    ("dmMediaType", ctypes.c_uint32),
    ("dmDitherType", ctypes.c_uint32),
    ("dmReserved1", ctypes.c_uint32),
    ("dmReserved2", ctypes.c_uint32),
    ("dmPanningWidth", ctypes.c_uint32),
    ("dmPanningHeight", ctypes.c_uint32)
]

def get_monitor_refresh_rate():
    c = wmi.WMI()
    for monitor in c.Win32_VideoController():
        return monitor.MaxRefreshRate
    return None

refresh_rate = get_monitor_refresh_rate()
if refresh_rate is not None:
    print(f"Monitor refresh rate: {refresh_rate} Hz")
else:
    print("Cannot Detremine the Monitor Refresh Rate.")
sleep(10)
Cracko298
  • 11
  • 2
-4

You can use the pygame clock

fps = 60
clock = pygame.time.Clock()

At the end of the code: clock.tick(fps)