Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get display count and resolution for each display in Python without xrandr

Tags:

python

xlib

I'm running Ubuntu and I want to get the number of attached displays, their current resolution and, if possible, their position in relation to each other. Because I don't like parsing Console output of xrandr - at least not if I don't have to - I would like to do that with Python-XLib or a similar Pythonic approach.

This is the xrandr output for my display config:

$ xrandr
Screen 0: minimum 320 x 200, current 2960 x 1050, maximum 8192 x 8192
DVI-0 connected 1680x1050+0+0 (normal left inverted right x axis y axis) 473mm x 296mm
   1680x1050      60.0*+
   1400x1050      60.0  
   1280x1024      75.0     60.0  
   1440x900       59.9  
   1280x960       75.0     60.0  
   1152x864       75.0  
   1280x720       75.0  
   1024x768       75.1     70.1     60.0  
   832x624        74.6  
   800x600        72.2     75.0     60.3     56.2  
   640x480        72.8     75.0     66.7     60.0  
   720x400        70.1  
VGA-0 connected 1280x1024+1680+26 (normal left inverted right x axis y axis) 376mm x 301mm
   1280x1024      60.0 +   75.0* 
   1024x768       75.1     70.1     60.0  
   832x624        74.6  
   800x600        72.2     75.0     60.3     56.2  
   640x480        72.8     75.0     66.7     60.0  
   720x400        70.1  

I want to get these values with Python, in a way like this:

displays = get_displays()
print displays[0].width # out: 1680
print displays[1].width # out: 1280
print displays[0].x_position # out: 0
print displays[1].x_position # out: 1680

When trying to get informations via Python-XLib (or other libs like pyGTK and pygame), it seems that all displays are always handled as one single display. For example this is what I got with XLib so far:

import Xlib
import Xlib.display

display = Xlib.display.Display(':0')

print display.screen_count()        # output: 1
root = display.screen().root
print root.get_geometry().width     # output: 2960 -> no way to get width of single display?
print root.get_geometry().height    # output: 1050

I know how to get display informations calling xrandr within Python:

import subprocess
output = subprocess.Popen('xrandr | grep "\*" | cut -d" " -f4',shell=True, stdout=subprocess.PIPE).communicate()[0]

displays = output.strip().split('\n')
for display in displays:
    values = display.split('x')
    width = values[0]
    height = values[1]
    print "Width:" + width + ",height:" + height

But as I said I would prefer a cleaner approach without having to parse Console output. Is there really no way to get (detailed) Display informations with Python without having to parse xrandr output?

like image 369
Wolkenarchitekt Avatar asked Jan 02 '12 22:01

Wolkenarchitekt


2 Answers

xrandr is just a client to access the "RandR" X11 extension from the command line. You can access the functionality directly from Python-Xlib. Here's an example (from Python-Xlib's own code!).

Just in case the URL changes again, here's a minimal piece of code that gets us the display modes. We need to create window (it doesn't matter the size, etc):

from __future__ import print_function
from Xlib import X, display
from Xlib.ext import randr

d = display.Display()
s = d.screen()
window = s.root.create_window(0, 0, 1, 1, 1, s.root_depth)

Then we can query the screen resources using it. Eg, following OP's example:

res = randr.get_screen_resources(window)
for mode in res.modes:
    w, h = mode.width, mode.height
    print("Width: {}, height: {}".format(w, h))

In my computer I get:

$ python minimal.py 
Xlib.protocol.request.QueryExtension
Width: 1600, height: 900
Width: 1440, height: 900
Width: 1360, height: 768
Width: 1360, height: 768
Width: 1152, height: 864
Width: 1024, height: 768
Width: 800, height: 600
Width: 800, height: 600
Width: 640, height: 480
like image 150
Ricardo Cárdenes Avatar answered Nov 18 '22 13:11

Ricardo Cárdenes


Latest snippet. It extracts all modes with current resolution from all connected monitors.

from Xlib import display
from Xlib.ext import randr

def find_mode(id, modes):
   for mode in modes:
       if id == mode.id:
           return "{}x{}".format(mode.width, mode.height)

def get_display_info():
    d = display.Display(':0')
    screen_count = d.screen_count()
    default_screen = d.get_default_screen()
    result = []
    screen = 0
    info = d.screen(screen)
    window = info.root

    res = randr.get_screen_resources(window)
    for output in res.outputs:
        params = d.xrandr_get_output_info(output, res.config_timestamp)
        if not params.crtc:
           continue
        crtc = d.xrandr_get_crtc_info(params.crtc, res.config_timestamp)
        modes = set()
        for mode in params.modes:
            modes.add(find_mode(mode, res.modes))
        result.append({
            'name': params.name,
            'resolution': "{}x{}".format(crtc.width, crtc.height),
            'available_resolutions': list(modes)
        })

    return result

print(get_display_info())
like image 38
Max Ivanov Avatar answered Nov 18 '22 13:11

Max Ivanov