Resize display resolution using python with cross platform support
Below is a solution that works on Windows (depends on pywin32). There are placeholders where you can put in your existing linux code, I'm not sure what to do about OS X though.
from __future__ import print_functionimport sysclass ScreenRes(object): @classmethod def set(cls, width=None, height=None, depth=32): ''' Set the primary display to the specified mode ''' if width and height: print('Setting resolution to {}x{}'.format(width, height, depth)) else: print('Setting resolution to defaults') if sys.platform == 'win32': cls._win32_set(width, height, depth) elif sys.platform.startswith('linux'): cls._linux_set(width, height, depth) elif sys.platform.startswith('darwin'): cls._osx_set(width, height, depth) @classmethod def get(cls): if sys.platform == 'win32': return cls._win32_get() elif sys.platform.startswith('linux'): return cls._linux_get() elif sys.platform.startswith('darwin'): return cls._osx_get() @classmethod def get_modes(cls): if sys.platform == 'win32': return cls._win32_get_modes() elif sys.platform.startswith('linux'): return cls._linux_get_modes() elif sys.platform.startswith('darwin'): return cls._osx_get_modes() @staticmethod def _win32_get_modes(): ''' Get the primary windows display width and height ''' import win32api from pywintypes import DEVMODEType, error modes = [] i = 0 try: while True: mode = win32api.EnumDisplaySettings(None, i) modes.append(( int(mode.PelsWidth), int(mode.PelsHeight), int(mode.BitsPerPel), )) i += 1 except error: pass return modes @staticmethod def _win32_get(): ''' Get the primary windows display width and height ''' import ctypes user32 = ctypes.windll.user32 screensize = ( user32.GetSystemMetrics(0), user32.GetSystemMetrics(1), ) return screensize @staticmethod def _win32_set(width=None, height=None, depth=32): ''' Set the primary windows display to the specified mode ''' # Gave up on ctypes, the struct is really complicated #user32.ChangeDisplaySettingsW(None, 0) import win32api from pywintypes import DEVMODEType if width and height: if not depth: depth = 32 mode = win32api.EnumDisplaySettings() mode.PelsWidth = width mode.PelsHeight = height mode.BitsPerPel = depth win32api.ChangeDisplaySettings(mode, 0) else: win32api.ChangeDisplaySettings(None, 0) @staticmethod def _win32_set_default(): ''' Reset the primary windows display to the default mode ''' # Interesting since it doesn't depend on pywin32 import ctypes user32 = ctypes.windll.user32 # set screen size user32.ChangeDisplaySettingsW(None, 0) @staticmethod def _linux_set(width=None, height=None, depth=32): raise NotImplementedError() @staticmethod def _linux_get(): raise NotImplementedError() @staticmethod def _linux_get_modes(): raise NotImplementedError() @staticmethod def _osx_set(width=None, height=None, depth=32): raise NotImplementedError() @staticmethod def _osx_get(): raise NotImplementedError() @staticmethod def _osx_get_modes(): raise NotImplementedError()if __name__ == '__main__': print('Primary screen resolution: {}x{}'.format( *ScreenRes.get() )) print(ScreenRes.get_modes()) #ScreenRes.set(1920, 1080) #ScreenRes.set() # Set defaults
Many of the answers are already scattered around StackOverflow and can be summarized as follows.
To get the resolution on Windows in a purely pythonic fashion (reference: https://stackoverflow.com/a/3129524/2942522):
import ctypesuser32 = ctypes.windll.user32screensize = user32.GetSystemMetrics(0), user32.GetSystemMetrics(1)
The MacOS solution also uses Python, but uses a package outside the standard library (reference: https://stackoverflow.com/a/3129567/2942522):
import AppKit[(screen.frame().size.width, screen.frame().size.height) for screen in AppKit.NSScreen.screens()]
Apparently the list comprehension will iterate over the screens in a multiple monitor setup.
I think Alex Martelli's response to a related issue (https://stackoverflow.com/a/2662892/2942522) is also notable. He uses:
pygame.display.list_modes()[(1920, 1080), (1768, 992), (1680, 1050), (1600, 1200), (1600, 1024), (1600, 900), (1440, 900), (1400, 1050), (1360, 768), (1280, 1024), (1280, 960), (1280, 800), (1280, 768), (1280, 720), (1152, 864), (1024, 768), (800, 600), (720, 576), (720, 480), (640, 480)]
to get a list of largest to smallest resolutions available (although pygame
would become a dependency if you went this route). Conversely, I suspect it would work just fine in a cross-platform setting. Furthermore, he mentions pygame.display.set_mode
for setting the resolution (docs: http://www.pygame.org/docs/ref/display.html#pygame.display.set_mode). Here's a snippet of the docs for set_mode
:
"The resolution argument is a pair of numbers representing the width and height. The flags argument is a collection of additional options. The depth argument represents the number of bits to use for color."
Maybe that will get you started. At the very least you could perhaps check the source code for set_mode
to see if there's some possible inspiration there if you cannot use it directly.
Other potentially useful ideas:
- You can do a crude platform check with
sys.platform
(docs: http://docs.python.org/2/library/sys.html#sys.platform). This returns'darwin'
on MacOS. - The bit architecture should be accessible with the Python
platform
module. If I runplatform.architecture()
on my machine it returns a tuple:('64bit', '')
(docs: http://docs.python.org/2/library/platform.html#platform.architecture)
To get and set the resolution under Windows (both 32 and 64 bits) you can use the ctypes and the user32 dll (ctypes.windll.user32). Don't care about the '32' in the name of the dll - it's a 64 bits dll on 64 bits Windows. This library you can use also to discover the allowed resolutions.
Alternatively you can use some command line tool like nircmd.exe :
nircmd.exe 1024 768 32
The last number is the colour depth.
Hope this helps.