197 lines
7.1 KiB
Python
Executable File
197 lines
7.1 KiB
Python
Executable File
#!/usr/bin/python
|
|
#
|
|
# examples/xrandr.py -- demonstrate the RandR extension
|
|
#
|
|
# Copyright (C) 2009 David H. Bronke <whitelynx@gmail.com>
|
|
#
|
|
# This library is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU Lesser General Public License
|
|
# as published by the Free Software Foundation; either version 2.1
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This library is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
# See the GNU Lesser General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Lesser General Public
|
|
# License along with this library; if not, write to the
|
|
# Free Software Foundation, Inc.,
|
|
# 59 Temple Place,
|
|
# Suite 330,
|
|
# Boston, MA 02111-1307 USA
|
|
|
|
|
|
# Python 2/3 compatibility.
|
|
from __future__ import print_function
|
|
|
|
import sys
|
|
import os
|
|
import pprint
|
|
|
|
# Change path so we find Xlib
|
|
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
|
|
|
|
from Xlib import X, display, Xutil
|
|
from Xlib.ext import randr
|
|
|
|
# Application window (only one)
|
|
class Window(object):
|
|
def __init__(self, display):
|
|
self.d = display
|
|
|
|
# Check for extension
|
|
if not self.d.has_extension('RANDR'):
|
|
sys.stderr.write('{}: server does not have the RANDR extension\n'.format(sys.argv[0]))
|
|
ext = self.d.query_extension('RANDR')
|
|
print(ext)
|
|
sys.stderr.write("\n".join(self.d.list_extensions()))
|
|
if ext is None:
|
|
sys.exit(1)
|
|
|
|
# print(version)
|
|
r = self.d.xrandr_query_version()
|
|
print('RANDR version %d.%d' % (r.major_version, r.minor_version))
|
|
|
|
|
|
# Grab the current screen
|
|
self.screen = self.d.screen()
|
|
|
|
self.window = self.screen.root.create_window(
|
|
50, 50, 300, 200, 2,
|
|
self.screen.root_depth,
|
|
X.InputOutput,
|
|
X.CopyFromParent,
|
|
|
|
# special attribute values
|
|
background_pixel = self.screen.white_pixel,
|
|
event_mask = (X.ExposureMask |
|
|
X.StructureNotifyMask |
|
|
X.ButtonPressMask |
|
|
X.ButtonReleaseMask |
|
|
X.Button1MotionMask),
|
|
colormap = X.CopyFromParent,
|
|
)
|
|
|
|
self.gc = self.window.create_gc(
|
|
foreground = self.screen.black_pixel,
|
|
background = self.screen.white_pixel,
|
|
)
|
|
|
|
# Set some WM info
|
|
|
|
self.WM_DELETE_WINDOW = self.d.intern_atom('WM_DELETE_WINDOW')
|
|
self.WM_PROTOCOLS = self.d.intern_atom('WM_PROTOCOLS')
|
|
|
|
self.window.set_wm_name('Xlib example: xrandr.py')
|
|
self.window.set_wm_icon_name('xrandr.py')
|
|
self.window.set_wm_class('xrandr', 'XlibExample')
|
|
|
|
self.window.set_wm_protocols([self.WM_DELETE_WINDOW])
|
|
self.window.set_wm_hints(flags = Xutil.StateHint,
|
|
initial_state = Xutil.NormalState)
|
|
|
|
self.window.set_wm_normal_hints(flags = (Xutil.PPosition | Xutil.PSize
|
|
| Xutil.PMinSize),
|
|
min_width = 20,
|
|
min_height = 20)
|
|
|
|
# Map the window, making it visible
|
|
self.window.map()
|
|
|
|
# Enable all RandR events.
|
|
self.window.xrandr_select_input(
|
|
randr.RRScreenChangeNotifyMask
|
|
| randr.RRCrtcChangeNotifyMask
|
|
| randr.RROutputChangeNotifyMask
|
|
| randr.RROutputPropertyNotifyMask
|
|
)
|
|
|
|
self.pp = pprint.PrettyPrinter(indent=4)
|
|
|
|
print("Screen info:")
|
|
self.pp.pprint(self.window.xrandr_get_screen_info()._data)
|
|
|
|
print("Screen size range:")
|
|
self.pp.pprint(self.window.xrandr_get_screen_size_range()._data)
|
|
|
|
print("Primary output:")
|
|
self.pp.pprint(self.window.xrandr_get_output_primary()._data)
|
|
|
|
resources = self.window.xrandr_get_screen_resources()._data
|
|
|
|
print("Modes:")
|
|
for mode_id, mode in self.parseModes(resources['mode_names'], resources['modes']).items():
|
|
print(" %d: %s" % (mode_id, mode['name']))
|
|
|
|
for output in resources['outputs']:
|
|
print("Output %d info:" % (output, ))
|
|
self.pp.pprint(self.d.xrandr_get_output_info(output, resources['config_timestamp'])._data)
|
|
|
|
for crtc in resources['crtcs']:
|
|
print("CRTC %d info:" % (crtc, ))
|
|
self.pp.pprint(self.d.xrandr_get_crtc_info(crtc, resources['config_timestamp'])._data)
|
|
|
|
print("Raw screen resources:")
|
|
self.pp.pprint(resources)
|
|
|
|
def parseModes(self, mode_names, modes):
|
|
lastIdx = 0
|
|
modedatas = dict()
|
|
for mode in modes:
|
|
modedata = dict(mode._data)
|
|
modedata['name'] = mode_names[lastIdx:lastIdx + modedata['name_length']]
|
|
modedatas[modedata['id']] = modedata
|
|
lastIdx += modedata['name_length']
|
|
return modedatas
|
|
|
|
# Main loop, handling events
|
|
def loop(self):
|
|
current = None
|
|
while 1:
|
|
e = self.d.next_event()
|
|
|
|
# Window has been destroyed, quit
|
|
if e.type == X.DestroyNotify:
|
|
sys.exit(0)
|
|
|
|
# Screen information has changed
|
|
elif e.__class__.__name__ == randr.ScreenChangeNotify.__name__:
|
|
print('Screen change')
|
|
print(self.pp.pprint(e._data))
|
|
|
|
# check if we're getting one of the RandR event types with subcodes
|
|
elif e.type == self.d.extension_event.CrtcChangeNotify[0]:
|
|
# yes, check the subcodes
|
|
|
|
# CRTC information has changed
|
|
if (e.type, e.sub_code) == self.d.extension_event.CrtcChangeNotify:
|
|
print('CRTC change')
|
|
#e = randr.CrtcChangeNotify(display=display.display, binarydata = e._binary)
|
|
print(self.pp.pprint(e._data))
|
|
|
|
# Output information has changed
|
|
elif (e.type, e.sub_code) == self.d.extension_event.OutputChangeNotify:
|
|
print('Output change')
|
|
#e = randr.OutputChangeNotify(display=display.display, binarydata = e._binary)
|
|
print(self.pp.pprint(e._data))
|
|
|
|
# Output property information has changed
|
|
elif (e.type, e.sub_code) == self.d.extension_event.OutputPropertyNotify:
|
|
print('Output property change')
|
|
#e = randr.OutputPropertyNotify(display=display.display, binarydata = e._binary)
|
|
print(self.pp.pprint(e._data))
|
|
else:
|
|
print("Unrecognised subcode", e.sub_code)
|
|
|
|
# Somebody wants to tell us something
|
|
elif e.type == X.ClientMessage:
|
|
if e.client_type == self.WM_PROTOCOLS:
|
|
fmt, data = e.data
|
|
if fmt == 32 and data[0] == self.WM_DELETE_WINDOW:
|
|
sys.exit(0)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
Window(display.Display()).loop()
|