Spaces:
Runtime error
Runtime error
# Xlib.display -- high level display object | |
# | |
# Copyright (C) 2000 Peter Liljenberg <petli@ctrl-c.liu.se> | |
# | |
# 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 modules | |
import types | |
# Python 2/3 compatibility. | |
from six import create_unbound_method | |
# Xlib modules | |
from . import error | |
from . import ext | |
from . import X | |
# Xlib.protocol modules | |
from .protocol import display as protocol_display | |
from .protocol import request, event, rq | |
# Xlib.xobjects modules | |
from .xobject import resource | |
from .xobject import drawable | |
from .xobject import fontable | |
from .xobject import colormap | |
from .xobject import cursor | |
_resource_baseclasses = { | |
'resource': resource.Resource, | |
'drawable': drawable.Drawable, | |
'window': drawable.Window, | |
'pixmap': drawable.Pixmap, | |
'fontable': fontable.Fontable, | |
'font': fontable.Font, | |
'gc': fontable.GC, | |
'colormap': colormap.Colormap, | |
'cursor': cursor.Cursor, | |
} | |
_resource_hierarchy = { | |
'resource': ('drawable', 'window', 'pixmap', | |
'fontable', 'font', 'gc', | |
'colormap', 'cursor'), | |
'drawable': ('window', 'pixmap'), | |
'fontable': ('font', 'gc') | |
} | |
class _BaseDisplay(protocol_display.Display): | |
# Implement a cache of atom names, used by Window objects when | |
# dealing with some ICCCM properties not defined in Xlib.Xatom | |
def __init__(self, *args, **keys): | |
self.resource_classes = _resource_baseclasses.copy() | |
protocol_display.Display.__init__(self, *args, **keys) | |
self._atom_cache = {} | |
def get_atom(self, atomname, only_if_exists=False): | |
if atomname in self._atom_cache: | |
return self._atom_cache[atomname] | |
r = request.InternAtom(display = self, name = atomname, only_if_exists = only_if_exists) | |
# don't cache NONE responses in case someone creates this later | |
if r.atom != X.NONE: | |
self._atom_cache[atomname] = r.atom | |
return r.atom | |
class Display(object): | |
def __init__(self, display = None): | |
self.display = _BaseDisplay(display) | |
# Create the keymap cache | |
self._keymap_codes = [()] * 256 | |
self._keymap_syms = {} | |
self._update_keymap(self.display.info.min_keycode, | |
(self.display.info.max_keycode | |
- self.display.info.min_keycode + 1)) | |
# Translations for keysyms to strings. | |
self.keysym_translations = {} | |
# Find all supported extensions | |
self.extensions = [] | |
self.class_extension_dicts = {} | |
self.display_extension_methods = {} | |
# a dict that maps the event name to the code | |
# or, when it's an event with a subcode, to a tuple of (event,subcode) | |
# note this wraps the dict so you address it as | |
# extension_event.EXTENSION_EVENT_NAME rather than | |
# extension_event["EXTENSION_EVENT_NAME"] | |
self.extension_event = rq.DictWrapper({}) | |
exts = self.list_extensions() | |
# Go through all extension modules | |
for extname, modname in ext.__extensions__: | |
if extname in exts: | |
# Import the module and fetch it | |
__import__('Xlib.ext.' + modname) | |
mod = getattr(ext, modname) | |
info = self.query_extension(extname) | |
self.display.set_extension_major(extname, info.major_opcode) | |
# Call initialiasation function | |
mod.init(self, info) | |
self.extensions.append(extname) | |
# Finalize extensions by creating new classes | |
for class_name, dictionary in self.class_extension_dicts.items(): | |
origcls = self.display.resource_classes[class_name] | |
self.display.resource_classes[class_name] = type(origcls.__name__, | |
(origcls,), | |
dictionary) | |
# Problem: we have already created some objects without the | |
# extensions: the screen roots and default colormaps. | |
# Fix that by reinstantiating them. | |
for screen in self.display.info.roots: | |
screen.root = self.display.resource_classes['window'](self.display, screen.root.id) | |
screen.default_colormap = self.display.resource_classes['colormap'](self.display, screen.default_colormap.id) | |
def get_display_name(self): | |
"""Returns the name used to connect to the server, either | |
provided when creating the Display object, or fetched from the | |
environmental variable $DISPLAY.""" | |
return self.display.get_display_name() | |
def fileno(self): | |
"""Returns the file descriptor number of the underlying socket. | |
This method is provided to allow Display objects to be passed | |
select.select().""" | |
return self.display.fileno() | |
def close(self): | |
"""Close the display, freeing the resources that it holds.""" | |
self.display.close() | |
def set_error_handler(self, handler): | |
"""Set the default error handler which will be called for all | |
unhandled errors. handler should take two arguments as a normal | |
request error handler, but the second argument (the request) will | |
be None. See section Error Handling.""" | |
self.display.set_error_handler(handler) | |
def flush(self): | |
"""Flush the request queue, building and sending the queued | |
requests. This can be necessary in applications that never wait | |
for events, and in threaded applications.""" | |
self.display.flush() | |
def sync(self): | |
"""Flush the queue and wait until the server has processed all | |
the queued requests. Use this e.g. when it is important that | |
errors caused by a certain request is trapped.""" | |
# Do a light-weight replyrequest to sync. There must | |
# be a better way to do it... | |
self.get_pointer_control() | |
def next_event(self): | |
"""Return the next event. If there are no events queued, it will | |
block until the next event is fetched from the server.""" | |
return self.display.next_event() | |
def pending_events(self): | |
"""Return the number of events queued, i.e. the number of times | |
that Display.next_event() can be called without blocking.""" | |
return self.display.pending_events() | |
def has_extension(self, extension): | |
"""Check if both the server and the client library support the X | |
extension named extension.""" | |
return extension in self.extensions | |
def create_resource_object(self, type, id): | |
"""Create a resource object of type for the integer id. type | |
should be one of the following strings: | |
resource | |
drawable | |
window | |
pixmap | |
fontable | |
font | |
gc | |
colormap | |
cursor | |
This function can be used when a resource ID has been fetched | |
e.g. from an resource or a command line argument. Resource | |
objects should never be created by instantiating the appropriate | |
class directly, since any X extensions dynamically added by the | |
library will not be available. | |
""" | |
return self.display.resource_classes[type](self.display, id) | |
# We need this to handle display extension methods | |
def __getattr__(self, attr): | |
try: | |
function = self.display_extension_methods[attr] | |
return types.MethodType(function, self) | |
except KeyError: | |
raise AttributeError(attr) | |
### | |
### display information retrieval | |
### | |
def screen(self, sno = None): | |
if sno is None: | |
return self.display.info.roots[self.display.default_screen] | |
else: | |
return self.display.info.roots[sno] | |
def screen_count(self): | |
"""Return the total number of screens on the display.""" | |
return len(self.display.info.roots) | |
def get_default_screen(self): | |
"""Return the number of the default screen, extracted from the | |
display name.""" | |
return self.display.get_default_screen() | |
### | |
### Extension module interface | |
### | |
def extension_add_method(self, object, name, function): | |
"""extension_add_method(object, name, function) | |
Add an X extension module method. OBJECT is the type of | |
object to add the function to, a string from this list: | |
display | |
resource | |
drawable | |
window | |
pixmap | |
fontable | |
font | |
gc | |
colormap | |
cursor | |
NAME is the name of the method, a string. FUNCTION is a | |
normal function whose first argument is a 'self'. | |
""" | |
if object == 'display': | |
if hasattr(self, name): | |
raise AssertionError('attempting to replace display method: %s' % name) | |
self.display_extension_methods[name] = function | |
else: | |
class_list = (object, ) + _resource_hierarchy.get(object, ()) | |
for class_name in class_list: | |
cls = _resource_baseclasses[class_name] | |
if hasattr(cls, name): | |
raise AssertionError('attempting to replace %s method: %s' % (class_name, name)) | |
method = create_unbound_method(function, cls) | |
# Maybe should check extension overrides too | |
try: | |
self.class_extension_dicts[class_name][name] = method | |
except KeyError: | |
self.class_extension_dicts[class_name] = { name: method } | |
def extension_add_event(self, code, evt, name = None): | |
"""extension_add_event(code, evt, [name]) | |
Add an extension event. CODE is the numeric code, and EVT is | |
the event class. EVT will be cloned, and the attribute _code | |
of the new event class will be set to CODE. | |
If NAME is omitted, it will be set to the name of EVT. This | |
name is used to insert an entry in the DictWrapper | |
extension_event. | |
""" | |
newevt = type(evt.__name__, evt.__bases__, | |
evt.__dict__.copy()) | |
newevt._code = code | |
self.display.add_extension_event(code, newevt) | |
if name is None: | |
name = evt.__name__ | |
setattr(self.extension_event, name, code) | |
def extension_add_subevent(self, code, subcode, evt, name = None): | |
"""extension_add_subevent(code, evt, [name]) | |
Add an extension subevent. CODE is the numeric code, subcode | |
is the sub-ID of this event that shares the code ID with other | |
sub-events and EVT is the event class. EVT will be cloned, and | |
the attribute _code of the new event class will be set to CODE. | |
If NAME is omitted, it will be set to the name of EVT. This | |
name is used to insert an entry in the DictWrapper | |
extension_event. | |
""" | |
newevt = type(evt.__name__, evt.__bases__, | |
evt.__dict__.copy()) | |
newevt._code = code | |
self.display.add_extension_event(code, newevt, subcode) | |
if name is None: | |
name = evt.__name__ | |
# store subcodes as a tuple of (event code, subcode) in the | |
# extension dict maintained in the display object | |
setattr(self.extension_event, name, (code,subcode)) | |
def extension_add_error(self, code, err): | |
"""extension_add_error(code, err) | |
Add an extension error. CODE is the numeric code, and ERR is | |
the error class. | |
""" | |
self.display.add_extension_error(code, err) | |
### | |
### keymap cache implementation | |
### | |
# The keycode->keysym map is stored in a list with 256 elements. | |
# Each element represents a keycode, and the tuple elements are | |
# the keysyms bound to the key. | |
# The keysym->keycode map is stored in a mapping, where the keys | |
# are keysyms. The values are a sorted list of tuples with two | |
# elements each: (index, keycode) | |
# keycode is the code for a key to which this keysym is bound, and | |
# index is the keysyms index in the map for that keycode. | |
def keycode_to_keysym(self, keycode, index): | |
"""Convert a keycode to a keysym, looking in entry index. | |
Normally index 0 is unshifted, 1 is shifted, 2 is alt grid, and 3 | |
is shift+alt grid. If that key entry is not bound, X.NoSymbol is | |
returned.""" | |
try: | |
return self._keymap_codes[keycode][index] | |
except IndexError: | |
return X.NoSymbol | |
def keysym_to_keycode(self, keysym): | |
"""Look up the primary keycode that is bound to keysym. If | |
several keycodes are found, the one with the lowest index and | |
lowest code is returned. If keysym is not bound to any key, 0 is | |
returned.""" | |
try: | |
return self._keymap_syms[keysym][0][1] | |
except (KeyError, IndexError): | |
return 0 | |
def keysym_to_keycodes(self, keysym): | |
"""Look up all the keycodes that is bound to keysym. A list of | |
tuples (keycode, index) is returned, sorted primarily on the | |
lowest index and secondarily on the lowest keycode.""" | |
try: | |
# Copy the map list, reversing the arguments | |
return map(lambda x: (x[1], x[0]), self._keymap_syms[keysym]) | |
except KeyError: | |
return [] | |
def refresh_keyboard_mapping(self, evt): | |
"""This method should be called once when a MappingNotify event | |
is received, to update the keymap cache. evt should be the event | |
object.""" | |
if isinstance(evt, event.MappingNotify): | |
if evt.request == X.MappingKeyboard: | |
self._update_keymap(evt.first_keycode, evt.count) | |
else: | |
raise TypeError('expected a MappingNotify event') | |
def _update_keymap(self, first_keycode, count): | |
"""Internal function, called to refresh the keymap cache. | |
""" | |
# Delete all sym->code maps for the changed codes | |
lastcode = first_keycode + count | |
for keysym, codes in self._keymap_syms.items(): | |
i = 0 | |
while i < len(codes): | |
code = codes[i][1] | |
if code >= first_keycode and code < lastcode: | |
del codes[i] | |
else: | |
i = i + 1 | |
# Get the new keyboard mapping | |
keysyms = self.get_keyboard_mapping(first_keycode, count) | |
# Replace code->sym map with the new map | |
self._keymap_codes[first_keycode:lastcode] = keysyms | |
# Update sym->code map | |
code = first_keycode | |
for syms in keysyms: | |
index = 0 | |
for sym in syms: | |
if sym != X.NoSymbol: | |
if sym in self._keymap_syms: | |
symcodes = self._keymap_syms[sym] | |
symcodes.append((index, code)) | |
symcodes.sort() | |
else: | |
self._keymap_syms[sym] = [(index, code)] | |
index = index + 1 | |
code = code + 1 | |
### | |
### client-internal keysym to string translations | |
### | |
def lookup_string(self, keysym): | |
"""Return a string corresponding to KEYSYM, or None if no | |
reasonable translation is found. | |
""" | |
s = self.keysym_translations.get(keysym) | |
if s is not None: | |
return s | |
import Xlib.XK | |
return Xlib.XK.keysym_to_string(keysym) | |
def rebind_string(self, keysym, newstring): | |
"""Change the translation of KEYSYM to NEWSTRING. | |
If NEWSTRING is None, remove old translation if any. | |
""" | |
if newstring is None: | |
try: | |
del self.keysym_translations[keysym] | |
except KeyError: | |
pass | |
else: | |
self.keysym_translations[keysym] = newstring | |
### | |
### X requests | |
### | |
def intern_atom(self, name, only_if_exists = False): | |
"""Intern the string name, returning its atom number. If | |
only_if_exists is true and the atom does not already exist, it | |
will not be created and X.NONE is returned.""" | |
r = request.InternAtom(display = self.display, | |
name = name, | |
only_if_exists = only_if_exists) | |
return r.atom | |
def get_atom(self, atom, only_if_exists = False): | |
"""Alias for intern_atom, using internal cache""" | |
return self.display.get_atom(atom, only_if_exists) | |
def get_atom_name(self, atom): | |
"""Look up the name of atom, returning it as a string. Will raise | |
BadAtom if atom does not exist.""" | |
r = request.GetAtomName(display = self.display, | |
atom = atom) | |
return r.name | |
def get_selection_owner(self, selection): | |
"""Return the window that owns selection (an atom), or X.NONE if | |
there is no owner for the selection. Can raise BadAtom.""" | |
r = request.GetSelectionOwner(display = self.display, | |
selection = selection) | |
return r.owner | |
def send_event(self, destination, event, event_mask = 0, propagate = False, | |
onerror = None): | |
"""Send a synthetic event to the window destination which can be | |
a window object, or X.PointerWindow or X.InputFocus. event is the | |
event object to send, instantiated from one of the classes in | |
protocol.events. See XSendEvent(3X11) for details. | |
There is also a Window.send_event() method.""" | |
request.SendEvent(display = self.display, | |
onerror = onerror, | |
propagate = propagate, | |
destination = destination, | |
event_mask = event_mask, | |
event = event) | |
def ungrab_pointer(self, time, onerror = None): | |
"""Release a grabbed pointer and any queued events. See | |
XUngrabPointer(3X11).""" | |
request.UngrabPointer(display = self.display, | |
onerror = onerror, | |
time = time) | |
def change_active_pointer_grab(self, event_mask, cursor, time, onerror = None): | |
"""Change the dynamic parameters of a pointer grab. See | |
XChangeActivePointerGrab(3X11).""" | |
request.ChangeActivePointerGrab(display = self.display, | |
onerror = onerror, | |
cursor = cursor, | |
time = time, | |
event_mask = event_mask) | |
def ungrab_keyboard(self, time, onerror = None): | |
"""Ungrab a grabbed keyboard and any queued events. See | |
XUngrabKeyboard(3X11).""" | |
request.UngrabKeyboard(display = self.display, | |
onerror = onerror, | |
time = time) | |
def allow_events(self, mode, time, onerror = None): | |
"""Release some queued events. mode should be one of | |
X.AsyncPointer, X.SyncPointer, X.AsyncKeyboard, X.SyncKeyboard, | |
X.ReplayPointer, X.ReplayKeyboard, X.AsyncBoth, or X.SyncBoth. | |
time should be a timestamp or X.CurrentTime.""" | |
request.AllowEvents(display = self.display, | |
onerror = onerror, | |
mode = mode, | |
time = time) | |
def grab_server(self, onerror = None): | |
"""Disable processing of requests on all other client connections | |
until the server is ungrabbed. Server grabbing should be avoided | |
as much as possible.""" | |
request.GrabServer(display = self.display, | |
onerror = onerror) | |
def ungrab_server(self, onerror = None): | |
"""Release the server if it was previously grabbed by this client.""" | |
request.UngrabServer(display = self.display, | |
onerror = onerror) | |
def warp_pointer(self, x, y, src_window = X.NONE, src_x = 0, src_y = 0, | |
src_width = 0, src_height = 0, onerror = None): | |
"""Move the pointer relative its current position by the offsets | |
(x, y). However, if src_window is a window the pointer is only | |
moved if the specified rectangle in src_window contains it. If | |
src_width is 0 it will be replaced with the width of src_window - | |
src_x. src_height is treated in a similar way. | |
To move the pointer to absolute coordinates, use Window.warp_pointer().""" | |
request.WarpPointer(display = self.display, | |
onerror = onerror, | |
src_window = src_window, | |
dst_window = X.NONE, | |
src_x = src_x, | |
src_y = src_y, | |
src_width = src_width, | |
src_height = src_height, | |
dst_x = x, | |
dst_y = y) | |
def set_input_focus(self, focus, revert_to, time, onerror = None): | |
"""Set input focus to focus, which should be a window, | |
X.PointerRoot or X.NONE. revert_to specifies where the focus | |
reverts to if the focused window becomes not visible, and should | |
be X.RevertToParent, RevertToPointerRoot, or RevertToNone. See | |
XSetInputFocus(3X11) for details. | |
There is also a Window.set_input_focus().""" | |
request.SetInputFocus(display = self.display, | |
onerror = onerror, | |
revert_to = revert_to, | |
focus = focus, | |
time = time) | |
def get_input_focus(self): | |
"""Return an object with the following attributes: | |
focus | |
The window which currently holds the input | |
focus, X.NONE or X.PointerRoot. | |
revert_to | |
Where the focus will revert, one of X.RevertToParent, | |
RevertToPointerRoot, or RevertToNone. """ | |
return request.GetInputFocus(display = self.display) | |
def query_keymap(self): | |
"""Return a bit vector for the logical state of the keyboard, | |
where each bit set to 1 indicates that the corresponding key is | |
currently pressed down. The vector is represented as a list of 32 | |
integers. List item N contains the bits for keys 8N to 8N + 7 | |
with the least significant bit in the byte representing key 8N.""" | |
r = request.QueryKeymap(display = self.display) | |
return r.map | |
def open_font(self, name): | |
"""Open the font identifed by the pattern name and return its | |
font object. If name does not match any font, None is returned.""" | |
fid = self.display.allocate_resource_id() | |
ec = error.CatchError(error.BadName) | |
request.OpenFont(display = self.display, | |
onerror = ec, | |
fid = fid, | |
name = name) | |
self.sync() | |
if ec.get_error(): | |
self.display.free_resource_id(fid) | |
return None | |
else: | |
cls = self.display.get_resource_class('font', fontable.Font) | |
return cls(self.display, fid, owner = 1) | |
def list_fonts(self, pattern, max_names): | |
"""Return a list of font names matching pattern. No more than | |
max_names will be returned.""" | |
r = request.ListFonts(display = self.display, | |
max_names = max_names, | |
pattern = pattern) | |
return r.fonts | |
def list_fonts_with_info(self, pattern, max_names): | |
"""Return a list of fonts matching pattern. No more than | |
max_names will be returned. Each list item represents one font | |
and has the following properties: | |
name | |
The name of the font. | |
min_bounds | |
max_bounds | |
min_char_or_byte2 | |
max_char_or_byte2 | |
default_char | |
draw_direction | |
min_byte1 | |
max_byte1 | |
all_chars_exist | |
font_ascent | |
font_descent | |
replies_hint | |
See the description of XFontStruct in XGetFontProperty(3X11) | |
for details on these values. | |
properties | |
A list of properties. Each entry has two attributes: | |
name | |
The atom identifying this property. | |
value | |
A 32-bit unsigned value. | |
""" | |
return request.ListFontsWithInfo(display = self.display, | |
max_names = max_names, | |
pattern = pattern) | |
def set_font_path(self, path, onerror = None): | |
"""Set the font path to path, which should be a list of strings. | |
If path is empty, the default font path of the server will be | |
restored.""" | |
request.SetFontPath(display = self.display, | |
onerror = onerror, | |
path = path) | |
def get_font_path(self): | |
"""Return the current font path as a list of strings.""" | |
r = request.GetFontPath(display = self.display) | |
return r.paths | |
def query_extension(self, name): | |
"""Ask the server if it supports the extension name. If it is | |
supported an object with the following attributes is returned: | |
major_opcode | |
The major opcode that the requests of this extension uses. | |
first_event | |
The base event code if the extension have additional events, or 0. | |
first_error | |
The base error code if the extension have additional errors, or 0. | |
If the extension is not supported, None is returned.""" | |
r = request.QueryExtension(display = self.display, | |
name = name) | |
if r.present: | |
return r | |
else: | |
return None | |
def list_extensions(self): | |
"""Return a list of all the extensions provided by the server.""" | |
r = request.ListExtensions(display = self.display) | |
return r.names | |
def change_keyboard_mapping(self, first_keycode, keysyms, onerror = None): | |
"""Modify the keyboard mapping, starting with first_keycode. | |
keysyms is a list of tuples of keysyms. keysyms[n][i] will be | |
assigned to keycode first_keycode+n at index i.""" | |
request.ChangeKeyboardMapping(display = self.display, | |
onerror = onerror, | |
first_keycode = first_keycode, | |
keysyms = keysyms) | |
def get_keyboard_mapping(self, first_keycode, count): | |
"""Return the current keyboard mapping as a list of tuples, | |
starting at first_keycount and no more than count.""" | |
r = request.GetKeyboardMapping(display = self.display, | |
first_keycode = first_keycode, | |
count = count) | |
return r.keysyms | |
def change_keyboard_control(self, onerror = None, **keys): | |
"""Change the parameters provided as keyword arguments: | |
key_click_percent | |
The volume of key clicks between 0 (off) and 100 (load). | |
-1 will restore default setting. | |
bell_percent | |
The base volume of the bell, coded as above. | |
bell_pitch | |
The pitch of the bell in Hz, -1 restores the default. | |
bell_duration | |
The duration of the bell in milliseconds, -1 restores | |
the default. | |
led | |
led_mode | |
led_mode should be X.LedModeOff or X.LedModeOn. If led is | |
provided, it should be a 32-bit mask listing the LEDs that | |
should change. If led is not provided, all LEDs are changed. | |
key | |
auto_repeat_mode | |
auto_repeat_mode should be one of X.AutoRepeatModeOff, | |
X.AutoRepeatModeOn, or X.AutoRepeatModeDefault. If key is | |
provided, that key will be modified, otherwise the global | |
state for the entire keyboard will be modified.""" | |
request.ChangeKeyboardControl(display = self.display, | |
onerror = onerror, | |
attrs = keys) | |
def get_keyboard_control(self): | |
"""Return an object with the following attributes: | |
global_auto_repeat | |
X.AutoRepeatModeOn or X.AutoRepeatModeOff. | |
auto_repeats | |
A list of 32 integers. List item N contains the bits for keys | |
8N to 8N + 7 with the least significant bit in the byte | |
representing key 8N. If a bit is on, autorepeat is enabled | |
for the corresponding key. | |
led_mask | |
A 32-bit mask indicating which LEDs are on. | |
key_click_percent | |
The volume of key click, from 0 to 100. | |
bell_percent | |
bell_pitch | |
bell_duration | |
The volume, pitch and duration of the bell. """ | |
return request.GetKeyboardControl(display = self.display) | |
def bell(self, percent = 0, onerror = None): | |
"""Ring the bell at the volume percent which is relative the base | |
volume. See XBell(3X11).""" | |
request.Bell(display = self.display, | |
onerror = onerror, | |
percent = percent) | |
def change_pointer_control(self, accel = None, threshold = None, onerror = None): | |
"""To change the pointer acceleration, set accel to a tuple (num, | |
denum). The pointer will then move num/denum times the normal | |
speed if it moves beyond the threshold number of pixels at once. | |
To change the threshold, set it to the number of pixels. -1 | |
restores the default.""" | |
if accel is None: | |
do_accel = 0 | |
accel_num = 0 | |
accel_denum = 0 | |
else: | |
do_accel = 1 | |
accel_num, accel_denum = accel | |
if threshold is None: | |
do_threshold = 0 | |
else: | |
do_threshold = 1 | |
request.ChangePointerControl(display = self.display, | |
onerror = onerror, | |
do_accel = do_accel, | |
do_thresh = do_threshold, | |
accel_num = accel_num, | |
accel_denum = accel_denum, | |
threshold = threshold) | |
def get_pointer_control(self): | |
"""Return an object with the following attributes: | |
accel_num | |
accel_denom | |
The acceleration as numerator/denumerator. | |
threshold | |
The number of pixels the pointer must move before the | |
acceleration kicks in.""" | |
return request.GetPointerControl(display = self.display) | |
def set_screen_saver(self, timeout, interval, prefer_blank, allow_exposures, onerror = None): | |
"""See XSetScreenSaver(3X11).""" | |
request.SetScreenSaver(display = self.display, | |
onerror = onerror, | |
timeout = timeout, | |
interval = interval, | |
prefer_blank = prefer_blank, | |
allow_exposures = allow_exposures) | |
def get_screen_saver(self): | |
"""Return an object with the attributes timeout, interval, | |
prefer_blanking, allow_exposures. See XGetScreenSaver(3X11) for | |
details.""" | |
return request.GetScreenSaver(display = self.display) | |
def change_hosts(self, mode, host_family, host, onerror = None): | |
"""mode is either X.HostInsert or X.HostDelete. host_family is | |
one of X.FamilyInternet, X.FamilyDECnet, X.FamilyChaos, | |
X.FamilyServerInterpreted or X.FamilyInternetV6. | |
host is a list of bytes. For the Internet family, it should be the | |
four bytes of an IPv4 address.""" | |
request.ChangeHosts(display = self.display, | |
onerror = onerror, | |
mode = mode, | |
host_family = host_family, | |
host = host) | |
def list_hosts(self): | |
"""Return an object with the following attributes: | |
mode | |
X.EnableAccess if the access control list is used, X.DisableAccess otherwise. | |
hosts | |
The hosts on the access list. Each entry has the following attributes: | |
family | |
X.FamilyInternet, X.FamilyDECnet, X.FamilyChaos, X.FamilyServerInterpreted or X.FamilyInternetV6. | |
name | |
A list of byte values, the coding depends on family. For the Internet family, it is the 4 bytes of an IPv4 address. | |
""" | |
return request.ListHosts(display = self.display) | |
def set_access_control(self, mode, onerror = None): | |
"""Enable use of access control lists at connection setup if mode | |
is X.EnableAccess, disable if it is X.DisableAccess.""" | |
request.SetAccessControl(display = self.display, | |
onerror = onerror, | |
mode = mode) | |
def set_close_down_mode(self, mode, onerror = None): | |
"""Control what will happen with the client's resources at | |
connection close. The default is X.DestroyAll, the other values | |
are X.RetainPermanent and X.RetainTemporary.""" | |
request.SetCloseDownMode(display = self.display, | |
onerror = onerror, | |
mode = mode) | |
def force_screen_saver(self, mode, onerror = None): | |
"""If mode is X.ScreenSaverActive the screen saver is activated. | |
If it is X.ScreenSaverReset, the screen saver is deactivated as | |
if device input had been received.""" | |
request.ForceScreenSaver(display = self.display, | |
onerror = onerror, | |
mode = mode) | |
def set_pointer_mapping(self, map): | |
"""Set the mapping of the pointer buttons. map is a list of | |
logical button numbers. map must be of the same length as the | |
list returned by Display.get_pointer_mapping(). | |
map[n] sets the | |
logical number for the physical button n+1. Logical number 0 | |
disables the button. Two physical buttons cannot be mapped to the | |
same logical number. | |
If one of the buttons to be altered are | |
logically in the down state, X.MappingBusy is returned and the | |
mapping is not changed. Otherwise the mapping is changed and | |
X.MappingSuccess is returned.""" | |
r = request.SetPointerMapping(display = self.display, | |
map = map) | |
return r.status | |
def get_pointer_mapping(self): | |
"""Return a list of the pointer button mappings. Entry N in the | |
list sets the logical button number for the physical button N+1.""" | |
r = request.GetPointerMapping(display = self.display) | |
return r.map | |
def set_modifier_mapping(self, keycodes): | |
"""Set the keycodes for the eight modifiers X.Shift, X.Lock, | |
X.Control, X.Mod1, X.Mod2, X.Mod3, X.Mod4 and X.Mod5. keycodes | |
should be a eight-element list where each entry is a list of the | |
keycodes that should be bound to that modifier. | |
If any changed | |
key is logically in the down state, X.MappingBusy is returned and | |
the mapping is not changed. If the mapping violates some server | |
restriction, X.MappingFailed is returned. Otherwise the mapping | |
is changed and X.MappingSuccess is returned.""" | |
r = request.SetModifierMapping(display = self.display, | |
keycodes = keycodes) | |
return r.status | |
def get_modifier_mapping(self): | |
"""Return a list of eight lists, one for each modifier. The list | |
can be indexed using X.ShiftMapIndex, X.Mod1MapIndex, and so on. | |
The sublists list the keycodes bound to that modifier.""" | |
r = request.GetModifierMapping(display = self.display) | |
return r.keycodes | |
def no_operation(self, onerror = None): | |
"""Do nothing but send a request to the server.""" | |
request.NoOperation(display = self.display, | |
onerror = onerror) | |