Import Upstream version 0.33

This commit is contained in:
luoyaoming 2024-04-30 18:12:55 +08:00
parent 466392cd2e
commit ee09aa30a6
72 changed files with 7758 additions and 776 deletions

5
.gitignore vendored
View File

@ -59,6 +59,9 @@ docs/_build/
target/
# IntelliJ
.idea/
# Visual Studio Code
.vscode/
/.mypy_cache/

View File

@ -2,10 +2,12 @@ language: python
python:
- "2.7"
- "3.3"
- "3.4"
- "3.5"
- "3.6"
- "3.7"
- "3.8"
- "3.9"
# command to install dependencies
install:

View File

@ -1,5 +1,140 @@
NEWS for Python X Library
Version 0.33
============
Bug Fixes
---------
- Removed unused imports (thanks @Avasam).
- Avoid to use fcntl module on some environments (thanks @i2y).
- Change a test behavior for `unix_connect.get_socket` (thanks @i2y).
- Fix accidental data change (thanks @Avasam).
- Prefer `bool` over `Literal[0, 1, None]` (thanks @Avasam).
- Change parentheses to brackets in LICENSE (thanks @mtelka).
---
Version 0.32
============
Bug Fixes
---------
- Use archived link for X documentation resource (thanks @yaxollum).
- Fix for auth entry having no display number (thanks @Majiir).
- Fix return type inconsistency with the `pack_value` for class `Object` (thanks @allfro).
- Rename `add_extension_error` method to `extension_add_error` (thanks @mattalexx).
Extensions
--------------------
- screensaver: fix screensaver protocol mismatch (thanks @yut23).
- XRandr: add version 1.5 support for RRSetMonitor RRGetMonitors and RRDeleteMonitors (thanks @allfro and @jklong).
---
Version 0.31
============
Extensions
--------------------
- XInput: add event methods (thanks @dd4e).
---
Version 0.30
============
Extensions
--------------------
- XResource: first implementation (thanks @alebastr).
- XRandr: add missing parameters to delete_output_mode function (thanks @jimmy-loyola).
---
Version 0.29
============
Extensions
--------------------
- Drawable & XInput: Avoid using array.array.tostring() which wiil be removed in Python 3.9 (thanks @t-wissmann).
---
Version 0.28
============
Extensions
--------------------
- DPMS: Display Power Management Signaling (by @thiagokokada)
---
Version 0.27
============
Bug Fixes
---------
- fix TypeError in socket.error exception handling for Python 3.x (by @t-wissmann)
Extensions
--------------------
- NV-CONTROL: set offset for all perf levels (by @Sporif)
---
Version 0.26
============
Bug Fixes
---------
- support legacy X servers like RealVNC's one (by @Gerardwx)
Extensions
--------------------
- enrich XFixes extension with XFixesSelectionNotify events (by @acrisci)
- add example xfixes-selection-notify.py (by @acrisci)
- fix two issues in NV-CONTROL extension (by @leinardi)
- add method get_clock_info into NV-CONTROL extension (by @leinardi)
- add default client version into Composite extension (by @jakogut)
- add Damage extension with the example (by @mgarg1 and @jakogut)
---
Version 0.25
============
Bug Fixes
---------
- fix increasing memory usage on display instantiation
NV-CONTROL extension
--------------------
- add first implementation by Roberto Leinardi (@leinardi)
---
Version 0.24
============
Bug Fixes
---------
- fix protocol handling: correctly support explicit Unix
connections and fix support fox macOS
- improve Python 3 support: fix events sub-code handling
and possible crashes when unpacking text data
- add support for error handlers to the Composite extension
Misc
----
- fix `xfixes` example
- fix a bunch of typos in the code / documentation
---
Version 0.23
============

View File

@ -6,9 +6,9 @@
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
(This is the first released version of the Lesser GPL. It also counts
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.)
the version number 2.1.]
Preamble

150
PKG-INFO
View File

@ -1,150 +0,0 @@
Metadata-Version: 1.1
Name: python-xlib
Version: 0.23
Summary: Python X Library
Home-page: https://github.com/python-xlib/python-xlib
Author: Peter Liljenberg
Author-email: petli@ctrl-c.liu.se
License: LGPLv2+
Download-URL: https://github.com/python-xlib/python-xlib/releases
Description-Content-Type: UNKNOWN
Description: The Python X Library
====================
|Build Status| |codecov.io| |Code Health|
`Homepage`_ | `Releases`_ | `Changelog`_
Copyright
~~~~~~~~~
The main part of the code is
::
Copyright (C) 2000-2002 Peter Liljenberg
Some contributed code is copyrighted by `the contributors <Contributors_>`_,
in these cases that is indicated in the source files in question.
The Python X Library is released under LGPL v2.1 or later (since 2016),
see the file LICENSE for details. 0.15rc1 and before were released under
GPL v2.
Requirements
~~~~~~~~~~~~
The Python X Library requires Python 2.7 or newer. It has been tested to
various extents with Python 2.7 and 3.3 through 3.6.
Installation
~~~~~~~~~~~~
The Python Xlib uses the standard setuptools package, to install run
this command:
::
python setup.py install
See the command help for details: ``python setup.py install -h``.
Alternatively, you can run programs from the distribution directory, or
change the module path in programs.
There's a simple example program, implemented twice using both the
high-level interface and the low-level protocol.
Introduction
~~~~~~~~~~~~
The Python X Library is intended to be a fully functional X client
library for Python programs. It is written entirely in Python, in
contrast to earlier X libraries for Python (the ancient X extension and
the newer plxlib) which were interfaces to the C Xlib.
This is possible to do since X client programs communicate with the X
server via the X protocol. The communication takes place over TCP/IP,
Unix sockets, DECnet or any other streaming network protocol. The C Xlib
is merely an interface to this protocol, providing functions suitable
for a C environment.
There are three advantages of implementing a pure Python library:
- Integration: The library can make use of the wonderful object system
in Python, providing an easy-to-use class hierarchy.
- Portability: The library will be usable on (almost) any computer
which have Python installed. A C interface could be problematic to
port to non-Unix systems, such as MS Windows or OpenVMS.
- Maintainability: It is much easier to develop and debug native Python
modules than modules written in C.
Documentation
~~~~~~~~~~~~~
The reference manual is not finished by far, but is probably still useful. It
can be `browsed online <http://python-xlib.sourceforge.net/doc/html/index.html>`__.
There are also some `example programs <Examples_>`_ and, of course,
`the standard X11 documentation <http://tronche.com/gui/x/xlib/>`__ applies.
Project status
~~~~~~~~~~~~~~
The low-level protocol is complete, implementing client-side X11R6. The
high-level object oriented interface is also fully functional. It is
possible to write client applications with the library. Currently, the
only real application using Python Xlib is the window manager PLWM,
starting with version 2.0.
There is a resource database implementation, ICCCM support and a
framework for adding X extension code. Several extensions have been
implemented; (RECORD, SHAPE, Xinerama, Composite, RANDR, and XTEST)
patches for additions are very welcome.
There are most likely still bugs, but the library is at least stable
enough to run PLWM. A continuously bigger part of the library is covered
by regression tests, improving stability.
The documentation is still quite rudimentary, but should be of some help
for people programming with the Xlib. X beginners should first find some
general texts on X. A very good starting point is
http://www.rahul.net/kenton/xsites.html
See the file TODO for a detailed list of what is missing, approximately
ordered by importance.
.. _Homepage: https://github.com/python-xlib/python-xlib
.. _Releases: https://github.com/python-xlib/python-xlib/releases
.. _Changelog: https://github.com/python-xlib/python-xlib/tree/master/CHANGELOG.md
.. _Contributors: https://github.com/python-xlib/python-xlib/graphs/contributors
.. _Examples: https://github.com/python-xlib/python-xlib/tree/master/examples
.. |Build Status| image:: https://travis-ci.org/python-xlib/python-xlib.svg?branch=master
:target: https://travis-ci.org/python-xlib/python-xlib
.. |codecov.io| image:: https://codecov.io/github/python-xlib/python-xlib/coverage.svg?branch=master
:target: https://codecov.io/github/python-xlib/python-xlib?branch=master
.. |Code Health| image:: https://landscape.io/github/python-xlib/python-xlib/master/landscape.svg?style=flat
:target: https://landscape.io/github/python-xlib/python-xlib/master
Keywords: windows,x,x11,xlib
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: X11 Applications
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: User Interfaces

View File

@ -27,6 +27,9 @@ Requirements
The Python X Library requires Python 2.7 or newer. It has been tested to
various extents with Python 2.7 and 3.3 through 3.6.
The Python X Library will only work on systems that have an X server installed,
such as most Linux distros, but will not work on Windows or MacOS.
Installation
~~~~~~~~~~~~
@ -70,15 +73,15 @@ There are three advantages of implementing a pure Python library:
- Maintainability: It is much easier to develop and debug native Python
modules than modules written in C.
Documentation
~~~~~~~~~~~~~
The reference manual is not finished by far, but is probably still useful. It
can be `browsed online <http://python-xlib.sourceforge.net/doc/html/index.html>`__.
can be `browsed online <https://python-xlib.github.io/>`__.
There are also some `example programs <Examples_>`_ and, of course,
`the standard X11 documentation <http://tronche.com/gui/x/xlib/>`__ applies.
`the standard X11 documentation <https://tronche.com/gui/x/xlib/>`__ applies.
Project status
@ -92,7 +95,8 @@ starting with version 2.0.
There is a resource database implementation, ICCCM support and a
framework for adding X extension code. Several extensions have been
implemented; (RECORD, SHAPE, Xinerama, Composite, RANDR, and XTEST)
implemented (RECORD, SHAPE, Xinerama, Composite, RANDR, DAMAGE,
Generic Event, SECURITY, XFIXES, XInput, XTEST, NV-CONTROL, DPMS and XRes);
patches for additions are very welcome.
There are most likely still bugs, but the library is at least stable

View File

@ -197,6 +197,8 @@ PlaceOnBottom = 1
FamilyInternet = 0
FamilyDECnet = 1
FamilyChaos = 2
FamilyServerInterpreted = 5
FamilyInternetV6 = 6
PropertyNewValue = 0
PropertyDelete = 1
ColormapUninstalled = 0

View File

@ -19,7 +19,7 @@
# Suite 330,
# Boston, MA 02111-1307 USA
__version__ = (0, 23)
__version__ = (0, 33)
__version_extra__ = ''

View File

@ -62,16 +62,16 @@ _resource_hierarchy = {
}
class _BaseDisplay(protocol_display.Display):
resource_classes = _resource_baseclasses.copy()
# 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=0):
def get_atom(self, atomname, only_if_exists=False):
if atomname in self._atom_cache:
return self._atom_cache[atomname]
@ -340,8 +340,8 @@ class Display(object):
# extension dict maintained in the display object
setattr(self.extension_event, name, (code,subcode))
def add_extension_error(self, code, err):
"""add_extension_error(code, err)
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.
@ -473,7 +473,7 @@ class Display(object):
### X requests
###
def intern_atom(self, name, only_if_exists = 0):
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."""
@ -482,7 +482,7 @@ class Display(object):
only_if_exists = only_if_exists)
return r.atom
def get_atom(self, atom, only_if_exists = 0):
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)
@ -501,7 +501,7 @@ class Display(object):
selection = selection)
return r.owner
def send_event(self, destination, event, event_mask = 0, propagate = 0,
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
@ -517,7 +517,7 @@ class Display(object):
event = event)
def ungrab_pointer(self, time, onerror = None):
"""elease a grabbed pointer and any queued events. See
"""Release a grabbed pointer and any queued events. See
XUngrabPointer(3X11)."""
request.UngrabPointer(display = self.display,
onerror = onerror,
@ -661,7 +661,7 @@ class Display(object):
font_ascent
font_descent
replies_hint
See the descripton of XFontStruct in XGetFontProperty(3X11)
See the description of XFontStruct in XGetFontProperty(3X11)
for details on these values.
properties
A list of properties. Each entry has two attributes:
@ -849,7 +849,8 @@ class Display(object):
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 or X.FamilyChaos.
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."""
@ -868,7 +869,7 @@ hosts
The hosts on the access list. Each entry has the following attributes:
family
X.FamilyInternet, X.FamilyDECnet, or X.FamilyChaos.
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.

View File

@ -70,7 +70,7 @@ class XError(rq.GetAttrData, Exception):
)
def __init__(self, display, data):
self._data, data = self._fields.parse_binary(data, display, rawdict = 1)
self._data, _ = self._fields.parse_binary(data, display, rawdict = True)
def __str__(self):
s = []

View File

@ -36,6 +36,11 @@ __extensions__ = [
('XFIXES', 'xfixes'),
('SECURITY', 'security'),
('XInputExtension', 'xinput'),
('NV-CONTROL', 'nvcontrol'),
('DAMAGE', 'damage'),
('DPMS', 'dpms'),
('X-Resource', 'res'),
('MIT-SCREEN-SAVER', 'screensaver'),
]
__all__ = map(lambda x: x[1], __extensions__)

View File

@ -33,7 +33,6 @@ also need RENDER or glX or some similar method of creating fancy
graphics.
"""
from Xlib import X
from Xlib.protocol import rq
from Xlib.xobject import drawable
@ -65,6 +64,8 @@ def query_version(self):
return QueryVersion(
display = self.display,
opcode = self.display.get_extension_major(extname),
major_version=0,
minor_version=4
)
@ -78,11 +79,12 @@ class RedirectWindow(rq.Request):
rq.Pad(3),
)
def redirect_window(self, update):
def redirect_window(self, update, onerror = None):
"""Redirect the hierarchy starting at this window to off-screen
storage.
"""
RedirectWindow(display = self.display,
onerror = onerror,
opcode = self.display.get_extension_major(extname),
window = self,
update = update,
@ -99,11 +101,12 @@ class RedirectSubwindows(rq.Request):
rq.Pad(3),
)
def redirect_subwindows(self, update):
def redirect_subwindows(self, update, onerror = None):
"""Redirect the hierarchies starting at all current and future
children to this window to off-screen storage.
"""
RedirectSubwindows(display = self.display,
onerror = onerror,
opcode = self.display.get_extension_major(extname),
window = self,
update = update,
@ -120,10 +123,11 @@ class UnredirectWindow(rq.Request):
rq.Pad(3),
)
def unredirect_window(self, update):
def unredirect_window(self, update, onerror = None):
"""Stop redirecting this window hierarchy.
"""
UnredirectWindow(display = self.display,
onerror = onerror,
opcode = self.display.get_extension_major(extname),
window = self,
update = update,
@ -140,10 +144,11 @@ class UnredirectSubindows(rq.Request):
rq.Pad(3),
)
def unredirect_subwindows(self, update):
def unredirect_subwindows(self, update, onerror = None):
"""Stop redirecting the hierarchies of children to this window.
"""
RedirectWindow(display = self.display,
onerror = onerror,
opcode = self.display.get_extension_major(extname),
window = self,
update = update,
@ -159,7 +164,7 @@ class CreateRegionFromBorderClip(rq.Request):
rq.Window('window'),
)
def create_region_from_border_clip(self):
def create_region_from_border_clip(self, onerror = None):
"""Create a region of the border clip of the window, i.e. the area
that is not clipped by the parent and any sibling windows.
"""
@ -167,6 +172,7 @@ def create_region_from_border_clip(self):
rid = self.display.allocate_resource_id()
CreateRegionFromBorderClip(
display = self.display,
onerror = onerror,
opcode = self.display.get_extension_major(extname),
region = rid,
window = self,
@ -185,7 +191,7 @@ class NameWindowPixmap(rq.Request):
rq.Pixmap('pixmap'),
)
def name_window_pixmap(self):
def name_window_pixmap(self, onerror = None):
"""Create a new pixmap that refers to the off-screen storage of
the window, including its border.
@ -198,6 +204,7 @@ def name_window_pixmap(self):
pid = self.display.allocate_resource_id()
NameWindowPixmap(display = self.display,
onerror = onerror,
opcode = self.display.get_extension_major(extname),
window = self,
pixmap = pid,

181
Xlib/ext/damage.py Normal file
View File

@ -0,0 +1,181 @@
# Xlib.ext.damage -- DAMAGE extension module
#
# Copyright (C) 2018 Joseph Kogut <joseph.kogut@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
from Xlib import X
from Xlib.protocol import rq, structs
from Xlib.error import XError
extname = 'DAMAGE'
# Event codes #
DamageNotifyCode = 0
# Error codes #
BadDamageCode = 0
class BadDamageError(XError):
pass
# DamageReportLevel options
DamageReportRawRectangles = 0
DamageReportDeltaRectangles = 1
DamageReportBoundingBox = 2
DamageReportNonEmpty = 3
DamageReportLevel = (
DamageReportRawRectangles,
DamageReportDeltaRectangles,
DamageReportBoundingBox,
DamageReportNonEmpty,
)
DAMAGE = rq.Card32
# Methods
class QueryVersion(rq.ReplyRequest):
_request = rq.Struct(rq.Card8('opcode'),
rq.Opcode(0),
rq.RequestLength(),
rq.Card32('major_version'),
rq.Card32('minor_version'),
)
_reply = rq.Struct(rq.ReplyCode(),
rq.Pad(1),
rq.Card16('sequence_number'),
rq.ReplyLength(),
rq.Card32('major_version'),
rq.Card32('minor_version'),
rq.Pad(16),
)
def query_version(self):
return QueryVersion(display=self.display,
opcode=self.display.get_extension_major(extname),
major_version=1,
minor_version=1)
class DamageCreate(rq.Request):
_request = rq.Struct(rq.Card8('opcode'),
rq.Opcode(1),
rq.RequestLength(),
DAMAGE('damage'),
rq.Drawable('drawable'),
rq.Set('level', 1, DamageReportLevel),
rq.Pad(3),
)
def damage_create(self, level):
did = self.display.allocate_resource_id()
DamageCreate(display=self.display,
opcode=self.display.get_extension_major(extname),
damage=did,
drawable=self.id,
level=level,
)
return did
class DamageDestroy(rq.Request):
_request = rq.Struct(rq.Card8('opcode'),
rq.Opcode(2),
rq.RequestLength(),
DAMAGE('damage')
)
def damage_destroy(self, damage):
DamageDestroy(display=self.display,
opcode=self.display.get_extension_major(extname),
damage=damage,
)
self.display.free_resource_id(damage)
class DamageSubtract(rq.Request):
_request = rq.Struct(rq.Card8('opcode'),
rq.Opcode(3),
rq.RequestLength(),
DAMAGE('damage'),
rq.Card32('repair'),
rq.Card32('parts')
)
def damage_subtract(self, damage, repair=X.NONE, parts=X.NONE):
DamageSubtract(display=self.display,
opcode=self.display.get_extension_major(extname),
damage=damage,
repair=repair,
parts=parts)
class DamageAdd(rq.Request):
_request = rq.Struct(rq.Card8('opcode'),
rq.Opcode(4),
rq.RequestLength(),
rq.Card32('repair'),
rq.Card32('parts'),
)
def damage_add(self, repair, parts):
DamageAdd(display=self.display,
opcode=self.display.get_extension_major(extname),
repair=repair,
parts=parts)
# Events #
class DamageNotify(rq.Event):
_code = None
_fields = rq.Struct(
rq.Card8('type'),
rq.Card8('level'),
rq.Card16('sequence_number'),
rq.Drawable('drawable'),
DAMAGE('damage'),
rq.Card32('timestamp'),
rq.Object('area', structs.Rectangle),
rq.Object('drawable_geometry', structs.Rectangle)
)
def init(disp, info):
disp.extension_add_method('display',
'damage_query_version',
query_version)
disp.extension_add_method('drawable',
'damage_create',
damage_create)
disp.extension_add_method('display',
'damage_destroy',
damage_destroy)
disp.extension_add_method('display',
'damage_subtract',
damage_subtract)
disp.extension_add_method('drawable',
'damage_add',
damage_add)
disp.extension_add_event(info.first_event + DamageNotifyCode, DamageNotify)
disp.extension_add_error(code=BadDamageCode, err=BadDamageError)

232
Xlib/ext/dpms.py Normal file
View File

@ -0,0 +1,232 @@
# Xlib.ext.dpms -- X Display Power Management Signaling
#
# Copyright (C) 2020 Thiago Kenji Okada <thiagokokada@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
'''
This extension provides X Protocol control over the VESA Display
Power Management Signaling (DPMS) characteristics of video boards
under control of the X Window System.
Documentation: https://www.x.org/releases/X11R7.7/doc/xextproto/dpms.html
'''
from Xlib.protocol import rq
extname = 'DPMS'
# DPMS Extension Power Levels
# 0 DPMSModeOn In use
# 1 DPMSModeStandby Blanked, low power
# 2 DPMSModeSuspend Blanked, lower power
# 3 DPMSModeOff Shut off, awaiting activity
DPMSModeOn = 0
DPMSModeStandby = 1
DPMSModeSuspend = 2
DPMSModeOff = 3
DPMSPowerLevel = (
DPMSModeOn,
DPMSModeStandby,
DPMSModeSuspend,
DPMSModeOff,
)
class DPMSGetVersion(rq.ReplyRequest):
_request = rq.Struct(
rq.Card8('opcode'),
rq.Opcode(0),
rq.RequestLength(),
rq.Card16('major_version'),
rq.Card16('minor_version'),
)
_reply = rq.Struct(
rq.ReplyCode(),
rq.Pad(1),
rq.Card16('sequence_number'),
rq.ReplyLength(),
rq.Card16('major_version'),
rq.Card16('minor_version'),
rq.Pad(20),
)
def get_version(self):
return DPMSGetVersion(display=self.display,
opcode=self.display.get_extension_major(extname),
major_version=1,
minor_version=1)
class DPMSCapable(rq.ReplyRequest):
_request = rq.Struct(
rq.Card8('opcode'),
rq.Opcode(1),
rq.RequestLength(),
)
_reply = rq.Struct(
rq.ReplyCode(),
rq.Pad(1),
rq.Card16('sequence_number'),
rq.ReplyLength(),
rq.Bool('capable'),
rq.Pad(23),
)
def capable(self):
return DPMSCapable(display=self.display,
opcode=self.display.get_extension_major(extname),
major_version=1,
minor_version=1)
class DPMSGetTimeouts(rq.ReplyRequest):
_request = rq.Struct(
rq.Card8('opcode'),
rq.Opcode(2),
rq.RequestLength(),
)
_reply = rq.Struct(
rq.ReplyCode(),
rq.Pad(1),
rq.Card16('sequence_number'),
rq.ReplyLength(),
rq.Card16('standby_timeout'),
rq.Card16('suspend_timeout'),
rq.Card16('off_timeout'),
rq.Pad(18),
)
def get_timeouts(self):
return DPMSGetTimeouts(display=self.display,
opcode=self.display.get_extension_major(extname),
major_version=1,
minor_version=1)
class DPMSSetTimeouts(rq.Request):
_request = rq.Struct(
rq.Card8('opcode'),
rq.Opcode(3),
rq.RequestLength(),
rq.Card16('standby_timeout'),
rq.Card16('suspend_timeout'),
rq.Card16('off_timeout'),
rq.Pad(2)
)
def set_timeouts(self, standby_timeout, suspend_timeout, off_timeout):
return DPMSSetTimeouts(display=self.display,
opcode=self.display.get_extension_major(extname),
major_version=1,
minor_version=1,
standby_timeout=standby_timeout,
suspend_timeout=suspend_timeout,
off_timeout=off_timeout)
class DPMSEnable(rq.Request):
_request = rq.Struct(
rq.Card8('opcode'),
rq.Opcode(4),
rq.RequestLength(),
)
def enable(self):
return DPMSEnable(display=self.display,
opcode=self.display.get_extension_major(extname),
major_version=1,
minor_version=1)
class DPMSDisable(rq.Request):
_request = rq.Struct(
rq.Card8('opcode'),
rq.Opcode(5),
rq.RequestLength(),
)
def disable(self):
return DPMSDisable(display=self.display,
opcode=self.display.get_extension_major(extname),
major_version=1,
minor_version=1)
class DPMSForceLevel(rq.Request):
_request = rq.Struct(
rq.Card8('opcode'),
rq.Opcode(6),
rq.RequestLength(),
rq.Resource('power_level', DPMSPowerLevel),
)
def force_level(self, power_level):
return DPMSForceLevel(display=self.display,
opcode=self.display.get_extension_major(extname),
major_version=1,
minor_version=1,
power_level=power_level)
class DPMSInfo(rq.ReplyRequest):
_request = rq.Struct(
rq.Card8('opcode'),
rq.Opcode(7),
rq.RequestLength(),
)
_reply = rq.Struct(
rq.ReplyCode(),
rq.Pad(1),
rq.Card16('sequence_number'),
rq.ReplyLength(),
rq.Card16('power_level'),
rq.Bool('state'),
rq.Pad(21),
)
def info(self):
return DPMSInfo(display=self.display,
opcode=self.display.get_extension_major(extname),
major_version=1,
minor_version=1)
def init(disp, _info):
disp.extension_add_method('display', 'dpms_get_version', get_version)
disp.extension_add_method('display', 'dpms_capable', capable)
disp.extension_add_method('display', 'dpms_get_timeouts', get_timeouts)
disp.extension_add_method('display', 'dpms_set_timeouts', set_timeouts)
disp.extension_add_method('display', 'dpms_enable', enable)
disp.extension_add_method('display', 'dpms_disable', disable)
disp.extension_add_method('display', 'dpms_force_level', force_level)
disp.extension_add_method('display', 'dpms_info', info)

5393
Xlib/ext/nvcontrol.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -22,10 +22,10 @@
"""RandR - provide access to the RandR extension information.
This implementation is based off version 1.3 of the XRandR protocol, and may
This implementation is based off version 1.5 of the XRandR protocol, and may
not be compatible with other versions.
Version 1.2 of the protocol is documented at:
Version 1.5 of the protocol is documented at:
http://cgit.freedesktop.org/xorg/proto/randrproto/tree/randrproto.txt
Version 1.3.1 here:
@ -35,7 +35,7 @@ http://www.x.org/releases/X11R7.5/doc/randrproto/randrproto.txt
from Xlib import X
from Xlib.protocol import rq, structs
from Xlib.protocol import rq
extname = 'RANDR'
@ -122,6 +122,12 @@ BadRROutput = 0
BadRRCrtc = 1
BadRRMode = 2
# Error classes #
class BadRROutputError(Exception): pass
class BadRRCrtcError(Exception): pass
class BadRRModeError(Exception): pass
# Data Structures #
@ -168,6 +174,19 @@ Render_Transform = rq.Struct(
rq.Card32('matrix33'),
)
MonitorInfo = rq.Struct(
rq.Card32('name'),
rq.Bool('primary'),
rq.Bool('automatic'),
rq.LengthOf('crtcs', 2),
rq.Int16('x'),
rq.Int16('y'),
rq.Card16('width_in_pixels'),
rq.Card16('height_in_pixels'),
rq.Card32('width_in_millimeters'),
rq.Card32('height_in_millimeters'),
rq.List('crtcs', rq.Card32Obj)
)
# Requests #
@ -197,7 +216,7 @@ def query_version(self):
display=self.display,
opcode=self.display.get_extension_major(extname),
major_version=1,
minor_version=3,
minor_version=5,
)
@ -699,7 +718,7 @@ class DeleteOutputMode(rq.Request):
rq.Card32('mode'),
)
def delete_output_mode(self):
def delete_output_mode(self, output, mode):
return DeleteOutputMode(
display=self.display,
opcode=self.display.get_extension_major(extname),
@ -1078,6 +1097,76 @@ def get_output_primary(self):
)
# Version 1.5 methods
class GetMonitors(rq.ReplyRequest):
_request = rq.Struct(
rq.Card8('opcode'),
rq.Opcode(42),
rq.RequestLength(),
rq.Window('window'),
rq.Bool('is_active'),
rq.Pad(3)
)
_reply = rq.Struct(
rq.ReplyCode(),
rq.Pad(1),
rq.Card16('sequence_number'),
rq.ReplyLength(),
rq.Card32('timestamp'),
rq.LengthOf('monitors', 4),
rq.Card32('outputs'),
rq.Pad(12),
rq.List('monitors', MonitorInfo)
)
def get_monitors(self, is_active=True):
return GetMonitors(
display=self.display,
opcode=self.display.get_extension_major(extname),
window=self,
is_active=is_active
)
class SetMonitor(rq.Request):
_request = rq.Struct(
rq.Card8('opcode'),
rq.Opcode(43),
rq.RequestLength(),
rq.Window('window'),
rq.Object('monitor_info', MonitorInfo)
)
def set_monitor(self, monitor_info):
return SetMonitor(
display=self.display,
opcode=self.display.get_extension_major(extname),
window=self,
monitor_info=monitor_info
)
class DeleteMonitor(rq.Request):
_request = rq.Struct(
rq.Card8('opcode'),
rq.Opcode(44),
rq.RequestLength(),
rq.Window('window'),
rq.Card32('name')
)
def delete_monitor(self, name):
return DeleteMonitor(
display=self.display,
opcode=self.display.get_extension_major(extname),
window=self,
name=name
)
# Events #
class ScreenChangeNotify(rq.Event):
@ -1149,8 +1238,6 @@ class OutputPropertyNotify(rq.Event):
rq.Card8('state'),
rq.Pad(11),
)
# Initialization #
def init(disp, info):
@ -1186,12 +1273,20 @@ def init(disp, info):
disp.extension_add_method('display', 'xrandr_get_panning', get_panning)
disp.extension_add_method('display', 'xrandr_set_panning', set_panning)
disp.extension_add_event(info.first_event + RRScreenChangeNotify, ScreenChangeNotify)
# add RRNotify events (1 event code with 3 subcodes)
disp.extension_add_subevent(info.first_event + RRNotify, RRNotify_CrtcChange, CrtcChangeNotify)
disp.extension_add_subevent(info.first_event + RRNotify, RRNotify_OutputChange, OutputChangeNotify)
disp.extension_add_subevent(info.first_event + RRNotify, RRNotify_OutputProperty, OutputPropertyNotify)
# If the server is running RANDR 1.5+, enable 1.5 compatible methods and events
version = query_version(disp)
if version.major_version == 1 and version.minor_version >= 5:
# version 1.5 compatible
disp.extension_add_method('window', 'xrandr_get_monitors', get_monitors)
disp.extension_add_method('window', 'xrandr_set_monitor', set_monitor)
disp.extension_add_method('window', 'xrandr_delete_monitor', delete_monitor)
#disp.extension_add_error(BadRROutput, BadRROutputError)
#disp.extension_add_error(BadRRCrtc, BadRRCrtcError)
#disp.extension_add_error(BadRRMode, BadRRModeError)
disp.extension_add_event(info.first_event + RRScreenChangeNotify, ScreenChangeNotify)
# add RRNotify events (1 event code with 3 subcodes)
disp.extension_add_subevent(info.first_event + RRNotify, RRNotify_CrtcChange, CrtcChangeNotify)
disp.extension_add_subevent(info.first_event + RRNotify, RRNotify_OutputChange, OutputChangeNotify)
disp.extension_add_subevent(info.first_event + RRNotify, RRNotify_OutputProperty, OutputPropertyNotify)
disp.extension_add_error(BadRROutput, BadRROutputError)
disp.extension_add_error(BadRRCrtc, BadRRCrtcError)
disp.extension_add_error(BadRRMode, BadRRModeError)

View File

@ -19,7 +19,6 @@
# Suite 330,
# Boston, MA 02111-1307 USA
from Xlib import X
from Xlib.protocol import rq
extname = 'RECORD'

288
Xlib/ext/res.py Normal file
View File

@ -0,0 +1,288 @@
# Xlib.ext.res -- X-Resource extension module
#
# Copyright (C) 2021 Aleksei Bavshin <alebastr89@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.,
# 51 Franklin Street,
# Fifth Floor,
# Boston, MA 02110-1301 USA
"""X-Resource extension allows a client to query the X server about its usage
of various resources.
For detailed description see any of the following documents.
Protocol specification:
https://www.x.org/releases/current/doc/resourceproto/resproto.txt
XCB Protocol specification:
https://cgit.freedesktop.org/xcb/proto/tree/src/res.xml
"""
from Xlib.protocol import rq
RES_MAJOR_VERSION = 1
RES_MINOR_VERSION = 2
extname = "X-Resource"
# v1.0
ResQueryVersion = 0
ResQueryClients = 1
ResQueryClientResources = 2
ResQueryClientPixmapBytes = 3
# v1.2
ResQueryClientIds = 4
ResQueryResourceBytes = 5
class QueryVersion(rq.ReplyRequest):
_request = rq.Struct(
rq.Card8("opcode"),
rq.Opcode(ResQueryVersion),
rq.RequestLength(),
rq.Card8("client_major"),
rq.Card8("client_minor"),
rq.Pad(2))
_reply = rq.Struct(
rq.ReplyCode(),
rq.Pad(1),
rq.Card16("sequence_number"),
rq.ReplyLength(),
rq.Card16("server_major"),
rq.Card16("server_minor"),
rq.Pad(20))
def query_version(self, client_major=RES_MAJOR_VERSION,
client_minor=RES_MINOR_VERSION):
""" Query the protocol version supported by the X server.
The client sends the highest supported version to the server and the
server sends the highest version it supports, but no higher than the
requested version."""
return QueryVersion(
display=self.display,
opcode=self.display.get_extension_major(extname),
client_major=client_major,
client_minor=client_minor)
Client = rq.Struct(
rq.Card32("resource_base"),
rq.Card32("resource_mask"))
class QueryClients(rq.ReplyRequest):
_request = rq.Struct(
rq.Card8("opcode"),
rq.Opcode(ResQueryClients),
rq.RequestLength())
_reply = rq.Struct(
rq.ReplyCode(),
rq.Pad(1),
rq.Card16("sequence_number"),
rq.ReplyLength(),
rq.LengthOf("clients", 4),
rq.Pad(20),
rq.List("clients", Client))
def query_clients(self):
"""Request the list of all currently connected clients."""
return QueryClients(
display=self.display,
opcode=self.display.get_extension_major(extname))
Type = rq.Struct(
rq.Card32("resource_type"),
rq.Card32("count"))
class QueryClientResources(rq.ReplyRequest):
_request = rq.Struct(
rq.Card8("opcode"),
rq.Opcode(ResQueryClientResources),
rq.RequestLength(),
rq.Card32("client"))
_reply = rq.Struct(
rq.ReplyCode(),
rq.Pad(1),
rq.Card16("sequence_number"),
rq.ReplyLength(),
rq.LengthOf("types", 4),
rq.Pad(20),
rq.List("types", Type))
def query_client_resources(self, client):
"""Request the number of resources owned by a client.
The server will return the counts of each type of resource.
"""
return QueryClientResources(
display=self.display,
opcode=self.display.get_extension_major(extname),
client=client)
class QueryClientPixmapBytes(rq.ReplyRequest):
_request = rq.Struct(
rq.Card8("opcode"),
rq.Opcode(ResQueryClientPixmapBytes),
rq.RequestLength(),
rq.Card32("client"))
_reply = rq.Struct(
rq.ReplyCode(),
rq.Pad(1),
rq.Card16("sequence_number"),
rq.ReplyLength(),
rq.Card32("bytes"),
rq.Card32("bytes_overflow"),
rq.Pad(16))
def query_client_pixmap_bytes(self, client):
"""Query the pixmap usage of some client.
The returned number is a sum of memory usage of each pixmap that can be
attributed to the given client.
"""
return QueryClientPixmapBytes(
display=self.display,
opcode=self.display.get_extension_major(extname),
client=client)
class SizeOf(rq.LengthOf):
"""A SizeOf stores the size in bytes of some other Field whose size
may vary, e.g. List
"""
def __init__(self, name, size, item_size):
rq.LengthOf.__init__(self, name, size)
self.item_size = item_size
def parse_value(self, length, display):
return length // self.item_size
ClientXIDMask = 1 << 0
LocalClientPIDMask = 1 << 1
ClientIdSpec = rq.Struct(
rq.Card32("client"),
rq.Card32("mask"))
ClientIdValue = rq.Struct(
rq.Object("spec", ClientIdSpec),
SizeOf("value", 4, 4),
rq.List("value", rq.Card32Obj))
class QueryClientIds(rq.ReplyRequest):
_request = rq.Struct(
rq.Card8("opcode"),
rq.Opcode(ResQueryClientIds),
rq.RequestLength(),
rq.LengthOf("specs", 4),
rq.List("specs", ClientIdSpec))
_reply = rq.Struct(
rq.ReplyCode(),
rq.Pad(1),
rq.Card16("sequence_number"),
rq.ReplyLength(),
rq.LengthOf("ids", 4),
rq.Pad(20),
rq.List("ids", ClientIdValue))
def query_client_ids(self, specs):
"""Request to identify a given set of clients with some identification method.
The request sends a list of specifiers that select clients and
identification methods to server. The server then tries to identify the
chosen clients using the identification methods specified for each client.
The server returns IDs for those clients that were successfully identified.
"""
return QueryClientIds(
display=self.display,
opcode=self.display.get_extension_major(extname),
specs=specs)
ResourceIdSpec = rq.Struct(
rq.Card32("resource"),
rq.Card32("type"))
ResourceSizeSpec = rq.Struct(
# inline struct ResourceIdSpec to work around
# a parser bug with nested objects
rq.Card32("resource"),
rq.Card32("type"),
rq.Card32("bytes"),
rq.Card32("ref_count"),
rq.Card32("use_count"))
ResourceSizeValue = rq.Struct(
rq.Object("size", ResourceSizeSpec),
rq.LengthOf("cross_references", 4),
rq.List("cross_references", ResourceSizeSpec))
class QueryResourceBytes(rq.ReplyRequest):
_request = rq.Struct(
rq.Card8("opcode"),
rq.Opcode(ResQueryResourceBytes),
rq.RequestLength(),
rq.Card32("client"),
rq.LengthOf("specs", 4),
rq.List("specs", ResourceIdSpec))
_reply = rq.Struct(
rq.ReplyCode(),
rq.Pad(1),
rq.Card16("sequence_number"),
rq.ReplyLength(),
rq.LengthOf("sizes", 4),
rq.Pad(20),
rq.List("sizes", ResourceSizeValue))
def query_resource_bytes(self, client, specs):
"""Query the sizes of resources from X server.
The request sends a list of specifiers that selects resources for size
calculation. The server tries to calculate the sizes of chosen resources
and returns an estimate for a resource only if the size could be determined
"""
return QueryResourceBytes(
display=self.display,
opcode=self.display.get_extension_major(extname),
client=client,
specs=specs)
def init(disp, info):
disp.extension_add_method("display", "res_query_version", query_version)
disp.extension_add_method("display", "res_query_clients", query_clients)
disp.extension_add_method("display", "res_query_client_resources",
query_client_resources)
disp.extension_add_method("display", "res_query_client_pixmap_bytes",
query_client_pixmap_bytes)
disp.extension_add_method("display", "res_query_client_ids",
query_client_ids)
disp.extension_add_method("display", "res_query_resource_bytes",
query_resource_bytes)

198
Xlib/ext/screensaver.py Normal file
View File

@ -0,0 +1,198 @@
# Xlib.ext.screensaver -- X ScreenSaver extension module
#
# Copyright (C) 2022 Vladimir Panteleev <git@cy.md>
#
# 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.,
# 51 Franklin Street,
# Fifth Floor,
# Boston, MA 02110-1301 USA
"""This extension allows registering the client as an X screensaver,
or query information about the current screensaver.
For detailed description see any of the following documents.
Protocol specification:
https://www.x.org/releases/X11R7.7/doc/scrnsaverproto/saver.html
XCB Protocol specification:
https://cgit.freedesktop.org/xcb/proto/tree/src/screensaver.xml
"""
from Xlib import X
from Xlib.protocol import rq, structs
extname = 'MIT-SCREEN-SAVER'
# Event members
NotifyMask = 1
CycleMask = 2
# Notify state
StateOff = 0
StateOn = 1
StateCycle = 2
# Notify kind
KindBlanked = 0
KindInternal = 1
KindExternal = 2
class QueryVersion(rq.ReplyRequest):
_request = rq.Struct(
rq.Card8('opcode'),
rq.Opcode(0),
rq.RequestLength(),
rq.Card8('major_version'),
rq.Card8('minor_version'),
rq.Pad(2),
)
_reply = rq.Struct(
rq.ReplyCode(),
rq.Pad(1),
rq.Card16('sequence_number'),
rq.ReplyLength(),
rq.Card16('major_version'),
rq.Card16('minor_version'),
rq.Pad(20),
)
def query_version(self):
return QueryVersion(display=self.display,
opcode=self.display.get_extension_major(extname),
major_version=1,
minor_version=0)
class QueryInfo(rq.ReplyRequest):
_request = rq.Struct(
rq.Card8('opcode'),
rq.Opcode(1),
rq.RequestLength(),
rq.Drawable('drawable'),
)
_reply = rq.Struct(
rq.ReplyCode(),
rq.Card8('state'),
rq.Card16('sequence_number'),
rq.ReplyLength(),
rq.Window('saver_window'),
rq.Card32('til_or_since'),
rq.Card32('idle'),
rq.Card32('event_mask'), # rq.Set('event_mask', 4, (NotifyMask, CycleMask)),
rq.Card8('kind'),
rq.Pad(7),
)
def query_info(self):
return QueryInfo(display=self.display,
opcode=self.display.get_extension_major(extname),
drawable=self,
)
class SelectInput(rq.Request):
_request = rq.Struct(
rq.Card8('opcode'),
rq.Opcode(2),
rq.RequestLength(),
rq.Drawable('drawable'),
rq.Card32('event_mask'), # rq.Set('event_mask', 4, (NotifyMask, CycleMask)),
)
def select_input(self, mask):
return SelectInput(display=self.display,
opcode=self.display.get_extension_major(extname),
drawable=self,
event_mask=mask,
)
class SetAttributes(rq.Request):
_request = rq.Struct(
rq.Card8('opcode'),
rq.Opcode(3),
rq.RequestLength(),
rq.Drawable('drawable'),
rq.Int16('x'),
rq.Int16('y'),
rq.Card16('width'),
rq.Card16('height'),
rq.Card16('border_width'),
rq.Set('window_class', 1, (X.CopyFromParent, X.InputOutput, X.InputOnly)),
rq.Card8('depth'),
rq.Card32('visual'),
structs.WindowValues('attrs'),
)
def set_attributes(self, x, y, width, height, border_width,
window_class = X.CopyFromParent,
depth = X.CopyFromParent,
visual = X.CopyFromParent,
onerror = None,
**keys):
return SetAttributes(display=self.display,
onerror = onerror,
opcode=self.display.get_extension_major(extname),
drawable=self,
x = x,
y = y,
width = width,
height = height,
border_width = border_width,
window_class = window_class,
depth = depth,
visual = visual,
attrs = keys)
class UnsetAttributes(rq.Request):
_request = rq.Struct(
rq.Card8('opcode'),
rq.Opcode(4),
rq.RequestLength(),
rq.Drawable('drawable'),
)
def unset_attributes(self, onerror = None):
return UnsetAttributes(display=self.display,
onerror = onerror,
opcode=self.display.get_extension_major(extname),
drawable=self)
class Notify(rq.Event):
_code = None
_fields = rq.Struct(
rq.Card8('type'),
rq.Set('state', 1, (StateOff, StateOn, StateCycle)),
rq.Card16('sequence_number'),
rq.Card32('timestamp'),
rq.Window('root'),
rq.Window('window'),
rq.Set('kind', 1, (KindBlanked, KindInternal, KindExternal)),
rq.Bool('forced'),
rq.Pad(14),
)
def init(disp, info):
disp.extension_add_method('display', 'screensaver_query_version', query_version)
disp.extension_add_method('drawable', 'screensaver_query_info', query_info)
disp.extension_add_method('drawable', 'screensaver_select_input', select_input)
disp.extension_add_method('drawable', 'screensaver_set_attributes', set_attributes)
disp.extension_add_method('drawable', 'screensaver_unset_attributes', unset_attributes)
disp.extension_add_event(info.first_event + 0, Notify)

View File

@ -22,13 +22,25 @@
'''
A partial implementation of the XFIXES extension. Only the HideCursor and
ShowCursor requests are provided.
ShowCursor requests and SelectionNotify events are provided.
'''
from Xlib.protocol import rq
extname = 'XFIXES'
XFixesSelectionNotify = 0
XFixesCursorNotify = 1
XFixesSetSelectionOwnerNotifyMask = (1 << 0)
XFixesSelectionWindowDestroyNotifyMask = (1 << 1)
XFixesSelectionClientCloseNotifyMask = (1 << 2)
XFixesDisplayCursorNotifyMask = (1 << 0)
XFixesSetSelectionOwnerNotify = 0
XFixesSelectionWindowDestroyNotify = 1
XFixesSelectionClientCloseNotify = 2
XFixesDisplayCursorNotify = 0
class QueryVersion(rq.ReplyRequest):
_request = rq.Struct(rq.Card8('opcode'),
@ -80,8 +92,109 @@ def show_cursor(self):
opcode=self.display.get_extension_major(extname),
window=self)
class SelectSelectionInput(rq.Request):
_request = rq.Struct(rq.Card8('opcode'),
rq.Opcode(2),
rq.RequestLength(),
rq.Window('window'),
rq.Card32('selection'),
rq.Card32('mask')
)
def select_selection_input(self, window, selection, mask):
return SelectSelectionInput(opcode=self.display.get_extension_major(extname),
display=self.display,
window=window,
selection=selection,
mask=mask)
class SelectionNotify(rq.Event):
_code = None
_fields = rq.Struct(rq.Card8('type'),
rq.Card8('sub_code'),
rq.Card16('sequence_number'),
rq.Window('window'),
rq.Window('owner'),
rq.Card32('selection'),
rq.Card32('timestamp'),
rq.Card32('selection_timestamp'),
rq.Pad(8))
class SetSelectionOwnerNotify(SelectionNotify):
pass
class SelectionWindowDestroyNotify(SelectionNotify):
pass
class SelectionClientCloseNotify(SelectionNotify):
pass
class SelectCursorInput(rq.Request):
_request = rq.Struct(rq.Card8('opcode'),
rq.Opcode(3),
rq.RequestLength(),
rq.Window('window'),
rq.Card32('mask')
)
def select_cursor_input(self, window, mask):
return SelectCursorInput(opcode=self.display.get_extension_major(extname),
display=self.display,
window=window,
cursor_serial=0,
mask=mask)
class GetCursorImage(rq.ReplyRequest):
_request = rq.Struct(rq.Card8('opcode'),
rq.Opcode(4),
rq.RequestLength()
)
_reply = rq.Struct(rq.ReplyCode(),
rq.Pad(1),
rq.Card16('sequence_number'),
rq.ReplyLength(),
rq.Int16('x'),
rq.Int16('y'),
rq.Card16('width'),
rq.Card16('height'),
rq.Card16('xhot'),
rq.Card16('yhot'),
rq.Card32('cursor_serial'),
rq.Pad(8),
rq.List('cursor_image', rq.Card32)
)
def get_cursor_image(self, window):
return GetCursorImage(opcode=self.display.get_extension_major(extname),
display=self.display,
)
class DisplayCursorNotify(rq.Event):
_code = None
_fields = rq.Struct(rq.Card8('type'),
rq.Card8('sub_code'),
rq.Card16('sequence_number'),
rq.Window('window'),
rq.Card32('cursor_serial'),
rq.Card32('timestamp'))
def init(disp, info):
disp.extension_add_method('display', 'xfixes_select_selection_input', select_selection_input)
disp.extension_add_method('display', 'xfixes_query_version', query_version)
disp.extension_add_method('window', 'xfixes_hide_cursor', hide_cursor)
disp.extension_add_method('window', 'xfixes_show_cursor', show_cursor)
disp.extension_add_method('display', 'xfixes_select_cursor_input', select_cursor_input)
disp.extension_add_method('display', 'xfixes_get_cursor_image', get_cursor_image)
disp.extension_add_subevent(info.first_event + XFixesSelectionNotify, XFixesSetSelectionOwnerNotify, SetSelectionOwnerNotify)
disp.extension_add_subevent(info.first_event + XFixesSelectionNotify, XFixesSelectionWindowDestroyNotify, SelectionWindowDestroyNotify)
disp.extension_add_subevent(info.first_event + XFixesSelectionNotify, XFixesSelectionClientCloseNotify, SelectionClientCloseNotify)
disp.extension_add_subevent(info.first_event + XFixesCursorNotify, XFixesDisplayCursorNotify, DisplayCursorNotify)

View File

@ -30,12 +30,11 @@ provide code for the lone Sun 1.0 request that isn't part of 1.1, but
this is untested because I don't have a server that implements it.
The functions loosely follow the libXineram functions. Mostly, they
return an rq.Struct in lieue of passing in pointers that get data from
return an rq.Struct in lieu of passing in pointers that get data from
the rq.Struct crammed into them. The exception is isActive, which
returns the state information - because that's what libXinerama does."""
from Xlib import X
from Xlib.protocol import rq, structs
extname = 'XINERAMA'

View File

@ -158,6 +158,8 @@ DEVICEID = rq.Card16
DEVICE = rq.Card16
DEVICEUSE = rq.Card8
PROPERTY_TYPE_FLOAT = 'FLOAT'
class FP1616(rq.Int32):
def check_value(self, value):
@ -236,7 +238,7 @@ class Mask(rq.List):
else:
mask_seq.extend(val)
return mask_seq.tostring(), len(mask_seq), None
return rq.encode_array(mask_seq), len(mask_seq), None
EventMask = rq.Struct(
DEVICE('deviceid'),
@ -426,6 +428,114 @@ def query_device(self, deviceid):
deviceid=deviceid,
)
class XIListProperties(rq.ReplyRequest):
_request = rq.Struct(
rq.Card8('opcode'),
rq.Opcode(56),
rq.RequestLength(),
DEVICEID('deviceid'),
rq.Pad(2),
)
_reply = rq.Struct(
rq.ReplyCode(),
rq.Pad(1),
rq.Card16('sequence_number'),
rq.ReplyLength(),
rq.LengthOf('atoms', 2),
rq.Pad(22),
rq.List('atoms', rq.Card32Obj),
)
def list_device_properties(self, deviceid):
return XIListProperties(
display=self.display,
opcode=self.display.get_extension_major(extname),
deviceid=deviceid,
)
class XIGetProperty(rq.ReplyRequest):
_request = rq.Struct(
rq.Card8('opcode'),
rq.Opcode(59),
rq.RequestLength(),
DEVICEID('deviceid'),
rq.Card8('delete'),
rq.Pad(1),
rq.Card32('property'),
rq.Card32('type'),
rq.Card32('offset'),
rq.Card32('length'),
)
_reply = rq.Struct(
rq.ReplyCode(),
rq.Pad(1),
rq.Card16('sequence_number'),
rq.ReplyLength(),
rq.Card32('type'),
rq.Card32('bytes_after'),
rq.LengthOf('value', 4),
rq.Format('value', 1),
rq.Pad(11),
rq.PropertyData('value')
)
def get_device_property(self, deviceid, property, type, offset, length, delete=False):
return XIGetProperty(
display=self.display,
opcode=self.display.get_extension_major(extname),
deviceid=deviceid,
property=property,
type=type,
offset=offset,
length=length,
delete=delete,
)
class XIChangeProperty(rq.Request):
_request = rq.Struct(
rq.Card8('opcode'),
rq.Opcode(57),
rq.RequestLength(),
DEVICEID('deviceid'),
rq.Card8('mode'),
rq.Format('value', 1),
rq.Card32('property'),
rq.Card32('type'),
rq.LengthOf('value', 4),
rq.PropertyData('value'),
)
def change_device_property(self, deviceid, property, type, mode, value):
return XIChangeProperty(
display=self.display,
opcode=self.display.get_extension_major(extname),
deviceid=deviceid,
property=property,
type=type,
mode=mode,
value=value,
)
class XIDeleteProperty(rq.Request):
_request = rq.Struct(
rq.Card8('opcode'),
rq.Opcode(58),
rq.RequestLength(),
DEVICEID('deviceid'),
rq.Pad(2),
rq.Card32('property'),
)
def delete_device_property(self, deviceid, property):
return XIDeleteProperty(
display=self.display,
opcode=self.display.get_extension_major(extname),
deviceid=deviceid,
property=property,
)
class XIGrabDevice(rq.ReplyRequest):
_request = rq.Struct(
rq.Card8('opcode'),
@ -639,6 +749,14 @@ DeviceChangedEventData = rq.Struct(
rq.List('classes', ClassInfo),
)
PropertyEventData = rq.Struct(
DEVICEID('deviceid'),
rq.Card32('time'),
rq.Card32('property'),
rq.Card8('what'),
rq.Pad(11),
)
def init(disp, info):
disp.extension_add_method('display', 'xinput_query_version', query_version)
disp.extension_add_method('window', 'xinput_select_events', select_events)
@ -647,8 +765,13 @@ def init(disp, info):
disp.extension_add_method('display', 'xinput_ungrab_device', ungrab_device)
disp.extension_add_method('window', 'xinput_grab_keycode', grab_keycode)
disp.extension_add_method('window', 'xinput_ungrab_keycode', ungrab_keycode)
for device_event in (ButtonPress, ButtonRelease, KeyPress, KeyRelease, Motion):
disp.ge_add_event_data(info.major_opcode, device_event, DeviceEventData)
disp.ge_add_event_data(info.major_opcode, DeviceChanged, DeviceEventData)
disp.ge_add_event_data(info.major_opcode, HierarchyChanged, HierarchyEventData)
disp.extension_add_method('display', 'xinput_get_device_property', get_device_property)
disp.extension_add_method('display', 'xinput_list_device_properties', list_device_properties)
disp.extension_add_method('display', 'xinput_change_device_property', change_device_property)
disp.extension_add_method('display', 'xinput_delete_device_property', delete_device_property)
if hasattr(disp,"ge_add_event_data"):
for device_event in (ButtonPress, ButtonRelease, KeyPress, KeyRelease, Motion):
disp.ge_add_event_data(info.major_opcode, device_event, DeviceEventData)
disp.ge_add_event_data(info.major_opcode, DeviceChanged, DeviceEventData)
disp.ge_add_event_data(info.major_opcode, HierarchyChanged, HierarchyEventData)
disp.ge_add_event_data(info.major_opcode, PropertyEvent, PropertyEventData)

View File

@ -1,8 +1,11 @@
XK_XF86_MonBrightnessUp = 0x1008FF02
XK_XF86_MonBrightnessDown = 0x1008FF03
XK_XF86_KbdLightOnOff = 0x1008FF04
XK_XF86_KbdBrightnessUp = 0x1008FF05
XK_XF86_KbdBrightnessDown = 0x1008FF06
XK_XF86_ModeLock = 0x1008FF01
XK_XF86_MonBrightnessUp = 0x1008FF02
XK_XF86_MonBrightnessDown = 0x1008FF03
XK_XF86_KbdLightOnOff = 0x1008FF04
XK_XF86_KbdBrightnessUp = 0x1008FF05
XK_XF86_KbdBrightnessDown = 0x1008FF06
XK_XF86_MonBrightnessCycle = 0x1008FF07
XK_XF86_Standby = 0x1008FF10
XK_XF86_AudioLowerVolume = 0x1008FF11
@ -159,6 +162,25 @@ XK_XF86_Green = 0x1008FFA4
XK_XF86_Yellow = 0x1008FFA5
XK_XF86_Blue = 0x1008FFA6
XK_XF86_Suspend = 0x1008FFA7
XK_XF86_Hibernate = 0x1008FFA8
XK_XF86_TouchpadToggle = 0x1008FFA9
XK_XF86_TouchpadOn = 0x1008FFB0
XK_XF86_TouchpadOff = 0x1008FFB1
XK_XF86_AudioMicMute = 0x1008FFB2
XK_XF86_Keyboard = 0x1008FFB3
XK_XF86_WWAN = 0x1008FFB4
XK_XF86_RFKill = 0x1008FFB5
XK_XF86_AudioPreset = 0x1008FFB6
XK_XF86_RotationLockToggle = 0x1008FFB7
XK_XF86_FullScreen = 0x1008FFB8
XK_XF86_Switch_VT_1 = 0x1008FE01
XK_XF86_Switch_VT_2 = 0x1008FE02
XK_XF86_Switch_VT_3 = 0x1008FE03
@ -176,3 +198,5 @@ XK_XF86_Ungrab = 0x1008FE20
XK_XF86_ClearGrab = 0x1008FE21
XK_XF86_Next_VMode = 0x1008FE22
XK_XF86_Prev_VMode = 0x1008FE23
XK_XF86_LogWindowTree = 0x1008FE24
XK_XF86_LogGrabInfo = 0x1008FE25

View File

@ -76,7 +76,6 @@ else:
class Display(object):
resource_classes = {}
extension_major_opcodes = {}
error_classes = error.xerror_class.copy()
event_classes = event.event_class.copy()
@ -89,8 +88,8 @@ class Display(object):
self.socket = connect.get_socket(name, protocol, host, displayno)
auth_name, auth_data = connect.get_auth(self.socket,
name, host, displayno)
auth_name, auth_data = connect.get_auth(self.socket, name,
protocol, host, displayno)
# Internal structures for communication, grouped
# by their function and locks
@ -110,7 +109,7 @@ class Display(object):
self.request_serial = 1
self.request_queue = []
# Send-and-recieve loop, see function send_and_recive
# Send-and-receive loop, see function send_and_receive
# for a detailed explanation
self.send_recv_lock = lock.allocate_lock()
self.send_active = 0
@ -127,7 +126,7 @@ class Display(object):
buffer_size = math.pow(2, math.floor(math.log(buffer_size, 2)))
self.recv_buffer_size = int(buffer_size)
# Data used by the send-and-recieve loop
# Data used by the send-and-receive loop
self.sent_requests = []
self.recv_packet_len = 0
self.data_send = b''
@ -146,7 +145,7 @@ class Display(object):
# Right, now we're all set up for the connection setup
# request with the server.
# Figure out which endianess the hardware uses
# Figure out which endianness the hardware uses
self.big_endian = struct.unpack('BB', struct.pack('H', 0x0100))[0]
if self.big_endian:
@ -204,7 +203,7 @@ class Display(object):
while not self.event_queue:
# Lock send_recv so no send_and_recieve
# Lock send_recv so no send_and_receive
# can start or stop while we're checking
# whether there are one active.
self.send_recv_lock.acquire()
@ -215,7 +214,7 @@ class Display(object):
# Call send_and_recv, which will return when
# something has occured
self.send_and_recv(event = 1)
self.send_and_recv(event = True)
# Before looping around, lock the event queue against
# modifications.
@ -241,7 +240,7 @@ class Display(object):
# Make a send_and_recv pass, receiving any events
self.send_recv_lock.acquire()
self.send_and_recv(recv = 1)
self.send_and_recv(recv = True)
# Lock the queue, get the event count, and unlock again.
self.event_queue_write_lock.acquire()
@ -253,7 +252,7 @@ class Display(object):
def flush(self):
self.check_for_error()
self.send_recv_lock.acquire()
self.send_and_recv(flush = 1)
self.send_and_recv(flush = True)
def close(self):
self.flush()
@ -385,7 +384,7 @@ class Display(object):
self.socket_error_lock.release()
def send_and_recv(self, flush = None, event = None, request = None, recv = None):
def send_and_recv(self, flush = False, event = False, request = None, recv = False):
"""send_and_recv(flush = None, event = None, request = None, recv = None)
Perform I/O, or wait for some other thread to do it for us.
@ -400,10 +399,10 @@ class Display(object):
be true. Will return immediately if another thread is
already doing send_and_recv.
To wait for an event to be recieved, event should be true.
To wait for an event to be received, event should be true.
To wait for a response to a certain request (either an error
or a response), request should be set the that request's
or a response), request should be set to that request's
serial number.
To just read any pending data from the server, recv should be true.
@ -485,19 +484,19 @@ class Display(object):
# There's no thread doing what we need to do. Find out exactly
# what to do
# There must always be some thread recieving data, but it must not
# There must always be some thread receiving data, but it must not
# necessarily be us
if not self.recv_active:
recieving = 1
receiving = 1
self.recv_active = 1
else:
recieving = 0
receiving = 0
flush_bytes = None
sending = 0
# Loop, recieving and sending data.
# Loop, receiving and sending data.
while 1:
# We might want to start sending data
@ -529,7 +528,7 @@ class Display(object):
self.send_recv_lock.release()
# There's no longer anything useful we can do here.
if not (sending or recieving):
if not (sending or receiving):
break
# If we're flushing, figure out how many bytes we
@ -542,9 +541,9 @@ class Display(object):
try:
# We're only checking for the socket to be writable
# if we're the sending thread. We always check for it
# to become readable: either we are the recieving thread
# and should take care of the data, or the recieving thread
# might finish recieving after having read the data
# to become readable: either we are the receiving thread
# and should take care of the data, or the receiving thread
# might finish receiving after having read the data
if sending:
writeset = [self.socket]
@ -561,7 +560,7 @@ class Display(object):
rs, ws, es = select.select([self.socket], writeset, [], timeout)
# Ignore errors caused by a signal recieved while blocking.
# Ignore errors caused by a signal received while blocking.
# All other errors are re-raised.
except select.error as err:
if isinstance(err, OSError):
@ -583,7 +582,7 @@ class Display(object):
try:
i = self.socket.send(self.data_send)
except socket.error as err:
self.close_internal('server: %s' % err[1])
self.close_internal('server: %s' % err)
raise self.socket_error
self.data_send = self.data_send[i:]
@ -594,14 +593,14 @@ class Display(object):
gotreq = 0
if rs:
# We're the recieving thread, parse the data
if recieving:
# We're the receiving thread, parse the data
if receiving:
try:
count = self.recv_packet_len - len(self.data_recv)
count = max(self.recv_buffer_size, count)
bytes_recv = self.socket.recv(count)
except socket.error as err:
self.close_internal('server: %s' % err[1])
self.close_internal('server: %s' % err)
raise self.socket_error
if not bytes_recv:
@ -627,7 +626,7 @@ class Display(object):
# There are three different end of send-recv-loop conditions.
# However, we don't leave the loop immediately, instead we
# try to send and recieve any data that might be left. We
# try to send and receive any data that might be left. We
# do this by giving a timeout of 0 to select to poll
# the socket.
@ -643,7 +642,7 @@ class Display(object):
if request is not None and gotreq:
break
# Always break if we just want to recieve as much as possible
# Always break if we just want to receive as much as possible
if recv:
break
@ -661,7 +660,7 @@ class Display(object):
if sending:
self.send_active = 0
if recieving:
if receiving:
self.recv_active = 0
if self.event_waiting:
@ -678,9 +677,9 @@ class Display(object):
def parse_response(self, request):
"""Internal method.
Parse data recieved from server. If REQUEST is not None
Parse data received from server. If REQUEST is not None
true is returned if the request with that serial number
was recieved, otherwise false is returned.
was received, otherwise false is returned.
If REQUEST is -1, we're parsing the server connection setup
response.
@ -690,8 +689,8 @@ class Display(object):
return self.parse_connection_setup()
# Parse ordinary server response
gotreq = 0
while 1:
gotreq = False
while True:
if self.data_recv:
# Check the first byte to find out what kind of response it is
rtype = byte2int(self.data_recv)
@ -711,11 +710,11 @@ class Display(object):
raise AssertionError(rtype)
# Every response is at least 32 bytes long, so don't bother
# until we have recieved that much
# until we have received that much
if len(self.data_recv) < 32:
return gotreq
# Error resposne
# Error response
if rtype == 0:
gotreq = self.parse_error_response(request) or gotreq
@ -773,7 +772,7 @@ class Display(object):
else:
self.default_error_handler(e)
return 0
return False
def default_error_handler(self, err):
@ -822,8 +821,14 @@ class Display(object):
estruct = self.event_classes.get(etype, event.AnyEvent)
if type(estruct) == dict:
subcode = self.data_recv[1]
# Python2 compatibility
if type(subcode) == str:
subcode = ord(subcode)
# this etype refers to a set of sub-events with individual subcodes
estruct = estruct[ord(self.data_recv[1])]
estruct = estruct[subcode]
e = estruct(display = self, binarydata = self.data_recv[:length])
@ -932,7 +937,7 @@ class Display(object):
# Only the ConnectionSetupRequest has been sent so far
r = self.sent_requests[0]
while 1:
while True:
# print 'data_send:', repr(self.data_send)
# print 'data_recv:', repr(self.data_recv)
@ -941,7 +946,7 @@ class Display(object):
# The full response haven't arrived yet
if len(self.data_recv) < alen:
return 0
return False
# Connection failed or further authentication is needed.
# Set reason to the reason string
@ -951,22 +956,22 @@ class Display(object):
# Else connection succeeded, parse the reply
else:
x, d = r._success_reply.parse_binary(self.data_recv[:alen],
self, rawdict = 1)
self, rawdict = True)
r._data.update(x)
del self.sent_requests[0]
self.data_recv = self.data_recv[alen:]
return 1
return True
else:
# The base reply is 8 bytes long
if len(self.data_recv) < 8:
return 0
return False
r._data, d = r._reply.parse_binary(self.data_recv[:8],
self, rawdict = 1)
self, rawdict = True)
self.data_recv = self.data_recv[8:]
# Loop around to see if we have got the additional data
@ -1061,7 +1066,7 @@ class ConnectionSetupRequest(rq.GetAttrData):
# Don't bother about locking, since no other threads have
# access to the display yet
display.request_queue.append((self, 1))
display.request_queue.append((self, True))
# However, we must lock send_and_recv, but we don't have
# to loop.

View File

@ -1640,7 +1640,8 @@ class ChangeHosts(rq.Request):
rq.Opcode(109),
rq.Set('mode', 1, (X.HostInsert, X.HostDelete)),
rq.RequestLength(),
rq.Set('host_family', 1, (X.FamilyInternet, X.FamilyDECnet, X.FamilyChaos)),
rq.Set('host_family', 1, (X.FamilyInternet, X.FamilyDECnet, X.FamilyChaos,
X.FamilyServerInterpreted, X.FamilyInternetV6)),
rq.Pad(1),
rq.LengthOf('host', 2),
rq.List('host', rq.Card8Obj)

View File

@ -24,7 +24,6 @@ import sys
import traceback
import struct
from array import array
import types
# Python 2/3 compatibility.
from six import PY3, binary_type, byte2int, indexbytes, iterbytes
@ -119,7 +118,7 @@ class Field(object):
check_value = None
parse_value = None
keyword_args = 0
keyword_args = False
def __init__(self):
pass
@ -724,7 +723,7 @@ class FixedPropertyData(PropertyData):
class ValueList(Field):
structcode = None
keyword_args = 1
keyword_args = True
default = 'usekeywords'
def __init__(self, name, mask, pad, *fields):
@ -1058,7 +1057,7 @@ class Struct(object):
pack_items.append(field_args[f.name])
# Multivalue field. Handled like single valuefield,
# but the value are tuple unpacked into seperate arguments
# but the value are tuple unpacked into separate arguments
# which are appended to pack_items
else:
if f.check_value is not None:
@ -1089,7 +1088,7 @@ class Struct(object):
raise BadDataError('%s is not a tuple or a list' % (value))
def parse_value(self, val, display, rawdict = 0):
def parse_value(self, val, display, rawdict = False):
"""This function is used by List and Object fields to convert
Struct objects with no var_fields into Python values.
@ -1132,9 +1131,9 @@ class Struct(object):
return DictWrapper(ret)
return ret
def parse_binary(self, data, display, rawdict = 0):
def parse_binary(self, data, display, rawdict = False):
"""values, remdata = s.parse_binary(data, display, rawdict = 0)
"""values, remdata = s.parse_binary(data, display, rawdict = False)
Convert a binary representation of the structure into Python values.
@ -1221,7 +1220,7 @@ class TextElements8(ValueField):
for v in value:
# Let values be simple strings, meaning a delta of 0
if type(v) is bytes:
if type(v) in (str, bytes):
v = (0, v)
# A tuple, it should be (delta, string)
@ -1230,19 +1229,19 @@ class TextElements8(ValueField):
if isinstance(v, (tuple, dict, DictWrapper)):
if isinstance(v, tuple):
delta, str = v
delta, m_str = v
else:
delta = v['delta']
str = v['string']
m_str = v['string']
while delta or str:
while delta or m_str:
args['delta'] = delta
args['string'] = str[:254]
args['string'] = m_str[:254]
data = data + self.string_textitem.to_binary(*(), **args)
delta = 0
str = str[254:]
m_str = m_str[254:]
# Else an integer, i.e. a font change
else:
@ -1320,7 +1319,7 @@ class DictWrapper(GetAttrData):
return str(self._data)
def __repr__(self):
return '%s(%s)' % (self.__class__, repr(self._data))
return '%s(%s)' % (self.__class__.__name__, repr(self._data))
def __lt__(self, other):
if isinstance(other, DictWrapper):
@ -1355,7 +1354,7 @@ class Request(object):
return 0
class ReplyRequest(GetAttrData):
def __init__(self, display, defer = 0, *args, **keys):
def __init__(self, display, defer = False, *args, **keys):
self._display = display
self._binary = self._request.to_binary(*args, **keys)
self._serial = None
@ -1364,7 +1363,7 @@ class ReplyRequest(GetAttrData):
self._response_lock = lock.allocate_lock()
self._display.send_request(self, 1)
self._display.send_request(self, True)
if not defer:
self.reply()
@ -1390,7 +1389,7 @@ class ReplyRequest(GetAttrData):
def _parse_response(self, data):
self._response_lock.acquire()
self._data, d = self._reply.parse_binary(data, self._display, rawdict = 1)
self._data, d = self._reply.parse_binary(data, self._display, rawdict = True)
self._response_lock.release()
def _set_error(self, error):
@ -1400,7 +1399,7 @@ class ReplyRequest(GetAttrData):
return 1
def __repr__(self):
return '<%s serial = %s, data = %s, error = %s>' % (self.__class__, self._serial, self._data, self._error)
return '<%s serial = %s, data = %s, error = %s>' % (self.__class__.__name__, self._serial, self._data, self._error)
class Event(GetAttrData):
@ -1409,7 +1408,7 @@ class Event(GetAttrData):
if binarydata:
self._binary = binarydata
self._data, data = self._fields.parse_binary(binarydata, display,
rawdict = 1)
rawdict = True)
# split event type into type and send_event bit
self._data['send_event'] = not not self._data['type'] & 0x80
self._data['type'] = self._data['type'] & 0x7f
@ -1434,7 +1433,7 @@ class Event(GetAttrData):
kwlist.append('%s = %s' % (kw, repr(val)))
kws = ', '.join(kwlist)
return '%s(%s)' % (self.__class__, kws)
return '%s(%s)' % (self.__class__.__name__, kws)
def __lt__(self, other):
if isinstance(other, Event):

View File

@ -699,7 +699,7 @@ stdopts = {'-bg': SepArg('*background'),
# the resource object.
# Example: Inserting "foo.bar*gazonk: yep" into an otherwise empty
# resource database would give the folliwing structure:
# resource database would give the following structure:
# { 'foo': ( { 'bar': ( { },
# { 'gazonk': ( { },

View File

@ -87,11 +87,11 @@ def get_socket(dname, protocol, host, dno):
return mod.get_socket(dname, protocol, host, dno)
def get_auth(sock, dname, host, dno):
"""auth_name, auth_data = get_auth(sock, dname, host, dno)
def get_auth(sock, dname, protocol, host, dno):
"""auth_name, auth_data = get_auth(sock, dname, protocol, host, dno)
Return authentication data for the display on the other side of
SOCK, which was opened with DNAME, HOST and DNO.
SOCK, which was opened with DNAME, HOST and DNO, using PROTOCOL.
Return AUTH_NAME and AUTH_DATA, two strings to be used in the
connection setup request.
@ -99,4 +99,4 @@ def get_auth(sock, dname, host, dno):
modname = _auth_mods.get(platform, _default_auth_mod)
mod = _relative_import(modname)
return mod.get_auth(sock, dname, host, dno)
return mod.get_auth(sock, dname, protocol, host, dno)

View File

@ -23,55 +23,52 @@ import re
import os
import platform
import socket
# FCNTL is deprecated from Python 2.2, so only import it if we doesn't
# get the names we need. Furthermore, FD_CLOEXEC seems to be missing
# in Python 2.2.
import fcntl
if hasattr(fcntl, 'F_SETFD'):
F_SETFD = fcntl.F_SETFD
if hasattr(fcntl, 'FD_CLOEXEC'):
FD_CLOEXEC = fcntl.FD_CLOEXEC
else:
FD_CLOEXEC = 1
else:
from FCNTL import F_SETFD, FD_CLOEXEC
from Xlib import error, xauth
SUPPORTED_PROTOCOLS = (None, 'tcp', 'unix')
# Darwin funky socket.
uname = platform.uname()
if (uname[0] == 'Darwin') and ([int(x) for x in uname[2].split('.')] >= [9, 0]):
SUPPORTED_PROTOCOLS += ('darwin',)
DARWIN_DISPLAY_RE = re.compile(r'^/private/tmp/[-:a-zA-Z0-9._]*:(?P<dno>[0-9]+)(\.(?P<screen>[0-9]+))?$')
display_re = re.compile(r'^(?P<proto>)(?P<host>[-:a-zA-Z0-9._/]*):(?P<dno>[0-9]+)(\.(?P<screen>[0-9]+))?$')
DISPLAY_RE = re.compile(r'^((?P<proto>tcp|unix)/)?(?P<host>[-:a-zA-Z0-9._]*):(?P<dno>[0-9]+)(\.(?P<screen>[0-9]+))?$')
else:
display_re = re.compile(r'^((?P<proto>tcp|unix)/)?(?P<host>[-:a-zA-Z0-9._]*):(?P<dno>[0-9]+)(\.(?P<screen>[0-9]+))?$')
def get_display(display):
# Use $DISPLAY if display isn't provided
if display is None:
display = os.environ.get('DISPLAY', '')
m = display_re.match(display)
if not m:
re_list = [(DISPLAY_RE, {})]
if 'darwin' in SUPPORTED_PROTOCOLS:
re_list.insert(0, (DARWIN_DISPLAY_RE, {'protocol': 'darwin'}))
for re, defaults in re_list:
m = re.match(display)
if m is not None:
protocol, host, dno, screen = [
m.groupdict().get(field, defaults.get(field))
for field in ('proto', 'host', 'dno', 'screen')
]
break
else:
raise error.DisplayNameError(display)
name = display
protocol, host, dno, screen = m.group('proto', 'host', 'dno', 'screen')
if protocol == 'tcp' and not host:
# Host is mandatory when protocol is TCP.
raise error.DisplayNameError(display)
dno = int(dno)
if screen:
screen = int(screen)
else:
screen = 0
return name, protocol, host, dno, screen
return display, protocol, host, dno, screen
def _get_tcp_socket(host, dno):
@ -79,20 +76,22 @@ def _get_tcp_socket(host, dno):
s.connect((host, 6000 + dno))
return s
def _get_unix_socket(address):
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect(address)
return s
def get_socket(dname, protocol, host, dno):
assert protocol in (None, 'tcp', 'unix')
assert protocol in SUPPORTED_PROTOCOLS
try:
# Darwin funky socket.
if uname[0] == 'Darwin' and host and host.startswith('/private/tmp/'):
if protocol == 'darwin':
s = _get_unix_socket(dname)
# TCP socket, note the special case: `unix:0.0` is equivalent to `:0.0`.
elif (not protocol or protocol != 'unix') and host and host != 'unix':
elif (protocol is None or protocol != 'unix') and host and host != 'unix':
s = _get_tcp_socket(host, dno)
# Unix socket.
@ -113,18 +112,45 @@ def get_socket(dname, protocol, host, dno):
raise error.DisplayConnectionError(dname, str(val))
# Make sure that the connection isn't inherited in child processes.
fcntl.fcntl(s.fileno(), F_SETFD, FD_CLOEXEC)
_ensure_not_inheritable(s)
return s
def new_get_auth(sock, dname, host, dno):
def _ensure_not_inheritable(sock):
# According to PEP446, in Python 3.4 and above,
# it is not inherited in child processes by default.
# However, just in case, we explicitly make it non-inheritable.
# Also, we don't use the code like the following,
# because there would be no possibility of backporting to past versions.
# if sys.version_info.major == 3 and sys.version_info.minor >= 4:
# sock.set_inheritable(False)
# return
# We just check if the socket has `set_inheritable`.
if hasattr(sock, 'set_inheritable'):
sock.set_inheritable(False)
return
# On Windows,
# Python doesn't support fcntl module because Windows doesn't have fcntl API.
# At least by not importing fcntl, we will be able to import python-xlib on Windows.
if platform.system() == 'Windows':
# so.. unfortunately, for Python 3.3 and below, on Windows,
# we can't make sure that the connection isn't inherited in child processes for now.
return
import fcntl
fcntl.fcntl(sock.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC)
def new_get_auth(sock, dname, protocol, host, dno):
assert protocol in SUPPORTED_PROTOCOLS
# Translate socket address into the xauth domain
if (uname[0] == 'Darwin') and host and host.startswith('/private/tmp/'):
if protocol == 'darwin':
family = xauth.FamilyLocal
addr = socket.gethostname()
elif host:
elif protocol == 'tcp':
family = xauth.FamilyInternet
# Convert the prettyprinted IP number into 4-octet string.
@ -186,14 +212,6 @@ def old_get_auth(sock, dname, host, dno):
except os.error:
pass
if not auth_data and host=='localhost':
# 127.0.0.1 counts as FamilyLocal, not FamilyInternet
# See Xtransutil.c:ConvertAddress.
# There might be more ways to spell 127.0.0.1 but
# 'localhost', yet this code fixes a the case of
# OpenSSH tunneling X.
return get_auth('unix:%d' % dno, 'unix', dno)
return auth_name, auth_data
get_auth = new_get_auth

View File

@ -27,6 +27,8 @@ from Xlib import X, error
FamilyInternet = X.FamilyInternet
FamilyDECnet = X.FamilyDECnet
FamilyChaos = X.FamilyChaos
FamilyServerInterpreted = X.FamilyServerInterpreted
FamilyInternetV6 = X.FamilyInternetV6
FamilyLocal = 256
class Xauthority(object):
@ -118,6 +120,8 @@ class Xauthority(object):
matches = {}
for efam, eaddr, enum, ename, edata in self.entries:
if enum == b'' and ename not in matches:
enum = num
if efam == family and eaddr == address and num == enum:
matches[ename] = edata

View File

@ -19,7 +19,7 @@
# Suite 330,
# Boston, MA 02111-1307 USA
from Xlib import X, Xatom, Xutil
from Xlib import X, Xatom
from Xlib.protocol import request, rq
# Other X resource objects
@ -451,7 +451,7 @@ class Window(Drawable):
window = self.id,
property = property)
def get_property(self, property, property_type, offset, length, delete = 0):
def get_property(self, property, property_type, offset, length, delete = False):
r = request.GetProperty(display = self.display,
delete = delete,
window = self.id,
@ -516,7 +516,7 @@ class Window(Drawable):
property = property,
time = time)
def send_event(self, event, event_mask = 0, propagate = 0, onerror = None):
def send_event(self, event, event_mask = 0, propagate = False, onerror = None):
request.SendEvent(display = self.display,
onerror = onerror,
propagate = propagate,
@ -629,7 +629,7 @@ class Window(Drawable):
focus = self.id,
time = time)
def clear_area(self, x = 0, y = 0, width = 0, height = 0, exposures = 0, onerror = None):
def clear_area(self, x = 0, y = 0, width = 0, height = 0, exposures = False, onerror = None):
request.ClearArea(display = self.display,
onerror = onerror,
exposures = exposures,
@ -779,7 +779,7 @@ class Window(Drawable):
def _get_struct_prop(self, pname, ptype, pstruct):
r = self.get_property(pname, ptype, 0, pstruct.static_size // 4)
if r and r.format == 32:
value = r.value.tostring()
value = rq.encode_array(r.value)
if len(value) == pstruct.static_size:
return pstruct.parse_binary(value, self.display)[0]

View File

@ -45,11 +45,8 @@ class Resource(object):
def __hash__(self):
return int(self.id)
def __str__(self):
return '%s(0x%08x)' % (self.__class__, self.id)
def __repr__(self):
return '<%s 0x%08x>' % (self.__class__, self.id)
return '<%s 0x%08x>' % (self.__class__.__name__, self.id)
def kill_client(self, onerror = None):
request.KillClient(display = self.display,

10
debian/changelog vendored
View File

@ -1,5 +1,9 @@
python-xlib (0.23-ok1) yangtze; urgency=medium
python-xlib (0.8-1) unstable; urgency=low
* Build for openKylin.
* Initial Release. (Closes: #105388)
-- openKylinBot <openKylinBot@openkylin.com> Mon, 25 Apr 2022 22:03:04 +0800
-- Moshe Zadka <moshez@debian.org> Sun, 15 Jul 2001 13:12:01 +0300
Local variables:
mode: debian-changelog
End:

1
debian/clean vendored
View File

@ -1 +0,0 @@
.eggs/*

1
debian/compat vendored
View File

@ -1 +0,0 @@
9

51
debian/control vendored
View File

@ -1,46 +1,13 @@
Source: python-xlib
Section: python
Priority: optional
Maintainer: Debian Python Modules Team <python-modules-team@lists.alioth.debian.org>
Build-Depends: debhelper (>= 9),
dh-python,
python-all (>= 2.6.6-0),
python-setuptools (>= 0.6.24),
python-setuptools-scm,
python-mock <!nocheck>,
python-six <!nocheck>,
python3-all,
python3-setuptools (>= 0.6.24),
python3-setuptools-scm,
python3-mock <!nocheck>,
python3-six <!nocheck>,
texinfo,
xauth <!nocheck>,
xvfb <!nocheck>
Standards-Version: 3.9.6
Homepage: https://github.com/python-xlib/python-xlib
Vcs-Git: https://salsa.debian.org/python-team/modules/python-xlib.git
Vcs-Browser: https://salsa.debian.org/python-team/modules/python-xlib
X-Python-Version: >= 2.5
X-Python3-Version: >= 3.1
Section: x11
Priority: extra
Maintainer: Moshe Zadka <moshez@debian.org>
Build-Depends: debhelper
Standards-Version: 3.0.1
Package: python-xlib
Architecture: all
Depends: ${misc:Depends}, ${python:Depends}
Provides: ${python:Provides}
Description: interface for Python to the X11 protocol
python-xlib is a 100% pure Python implementation of the X11
protocol. It currently implements client-side X11R6 fully, supports
the resource database, ICCM, and the Shape extension.
.
This is a Python 2 version of the package
Package: python3-xlib
Architecture: all
Depends: ${misc:Depends}, ${python3:Depends}
Description: interface for Python 3 to the X11 protocol
python-xlib is a 100% pure Python 3 implementation of the X11
protocol. It currently implements client-side X11R6 fully, supports
the resource database, ICCM, and the Shape extension.
.
This is a Python 3 version of the package
Depends: python
Description: Interface for Python to the X11 Protocol
python-xlib is a 100% pure python implementation of the X11
protocol.

36
debian/copyright vendored
View File

@ -3,37 +3,11 @@ sun, 15 Jul 2001 13:03:04 +0300.
It was downloaded from http://python-xlib.sf.net
Upstream Author: Peter Liljenberg
Upstream Author(s): Peter Liljenberg
examples/record_demo.py is Copyright (C) 2006 Alex Badea <vamposdecampos@gmail.com>
Xlib/ext/record.py is Copyright (C) 2006 Alex Badea <vamposdecampos@gmail.com>
Xlib/ext/xinerama.py is Copyright (C) 2006 Mike Meyer <mwm@mired.org>
Xlib/ext/shape.py is Copyright (C) 2002 Jeffrey Boser <verin@lvcm.com>
Copyright:
doc/html/texi2html is Copyright (C) 1998, 1999 Lionel Cons, Lionel.Cons@cern.ch
Copyright (C) 2000,2001 Peter Liljenberg
Other files are Copyright (C) 2000-2002 Peter Liljenberg
The Debian packaging is
Copyright (C) 2001-2002 Moshe Zadka
2005 Martin v. Loewis
License:
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
On Debian systems, the complete text of the GNU General
Public License version 2 can be found in `/usr/share/common-licenses/GPL-2'.
The Python X Library is released under GPL, see the file COPYING for
details.

5
debian/dirs vendored Normal file
View File

@ -0,0 +1,5 @@
usr/lib/python1.5/site-packages/Xlib
usr/share/info
usr/share/doc/python-xlib/
usr/share/doc/python-xlib/examples
usr/share/doc/python-xlib/html

20
debian/postinst vendored Normal file
View File

@ -0,0 +1,20 @@
#!/bin/sh
if [ "$1" = "configure" -o "$1" = "upgrade" ]; then
install-info --section "Development" "Development" --quiet /usr/share/info/python-xlib.info
fi
if [ "$1" = "configure" ]; then
if [ -d /usr/doc -a ! -e /usr/doc/python-xlib -a -d /usr/share/doc/python-xlib ]; then
ln -sf ../share/doc/python-xlib /usr/doc/python-xlib
fi
fi
NAME=python-xlib
case "$1" in
configure|abort-upgrade|abort-remove|abort-deconfigure)
dpkg --listfiles $NAME | grep '\.py$' | \
xargs -n 1 /usr/bin/python -c 'import py_compile,sys;py_compile.compile(sys.argv[1])'
dpkg --listfiles $NAME | grep '\.py$' | \
xargs -n 1 /usr/bin/python -O -c 'import py_compile,sys;py_compile.compile(sys.argv[1])'
;;
esac

14
debian/prerm vendored Normal file
View File

@ -0,0 +1,14 @@
#!/bin/sh
if [ "$1" = "remove" -o "$1" = "upgrade" ]; then
install-info --quiet --remove /usr/share/info/python-xlib.info
fi
NAME=python-xlib
dpkg --listfiles $NAME |
awk '$0~/\.py$/ {print $0"c\n" $0"o"}' |
xargs rm -f >&2
if [ \( "$1" = "upgrade" -o "$1" = "remove" \) -a -L /usr/doc/python-xlib ]; then
rm -f /usr/doc/python-xlib
fi

View File

@ -1,3 +0,0 @@
README.rst
TODO
doc/html

View File

@ -1 +0,0 @@
examples/*

View File

@ -1,3 +0,0 @@
README.rst
TODO
doc/html

View File

@ -1 +0,0 @@
examples/*

80
debian/rules vendored Executable file → Normal file
View File

@ -1,41 +1,67 @@
#!/usr/bin/make -f
#-*- makefile -*-
# Made with the aid of dh_make, by Craig Small
# Sample debian/rules that uses debhelper. GNU copyright 1997 by Joey Hess.
# Some lines taken from debmake, by Christoph Lameter.
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
export PYBUILD_NAME=xlib
# This is the debhelper compatibility version to use.
export DH_COMPAT=1
%:
dh $@ --with python2,python3 --buildsystem=pybuild
build: build-stamp
build-stamp:
dh_testdir
override_dh_auto_build:
dh_auto_build
make -C doc html
# for some reason makeinfo doesnt create toc on the first run
make -C doc html
touch build-stamp
override_dh_auto_clean:
dh_auto_clean
make -C doc clean
clean:
dh_testdir
dh_testroot
rm -f build-stamp install-stamp
override_dh_installdocs:
dh_installdocs
rm -f debian/*/usr/share/doc/*/*/Makefile
# Add here commands to clean up after the build process.
dh_clean
override_dh_installexamples:
dh_installexamples
# adjust python3 examples hashbang
sed -i '1 s/python$$/python3/' debian/python3-xlib/usr/share/doc/*/examples/*.py
# set all examples executable
chmod +x debian/python*-xlib/usr/share/doc/*/examples/*.py
install: install-stamp
install-stamp: build-stamp
dh_testdir
dh_testroot
dh_clean -k
dh_installdirs
override_dh_compress:
dh_compress -X.py
# Add here commands to install the package into debian/tmp.
cp -r Xlib debian/tmp/usr/lib/python1.5/site-packages/
cp README NEWS TODO debian/tmp/usr/share/doc/python-xlib
cp doc/html/*.html debian/tmp/usr/share/doc/python-xlib/html
cp doc/info/*.info debian/tmp/usr/share/info
gzip -9 debian/tmp/usr/share/info/python-xlib.info
cp examples/*.py debian/tmp/usr/share/doc/python-xlib/examples
cp debian/copyright debian/tmp/usr/share/doc/python-xlib/
override_dh_auto_test:
ifeq (,$(filter nocheck, $(DEB_BUILD_OPTIONS)))
xvfb-run dh_auto_test
endif
touch install-stamp
.PHONY: override_dh_auto_build override_dh_auto_clean override_dh_installexamples override_dh_compress
binary-arch: build install
# We have nothing to do by default.
binary-indep: build install
# dh_testversion
dh_testdir
dh_testroot
dh_link
dh_strip
dh_installchangelogs
dh_compress
dh_fixperms
dh_installdeb
dh_shlibdeps
dh_gencontrol
dh_md5sums
dh_builddeb
source diff:
@echo >&2 'source and diff are obsolete - use dpkg-source -b'; false
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install

View File

@ -1 +0,0 @@
3.0 (native)

4
debian/watch vendored
View File

@ -1,4 +0,0 @@
version=4
https://github.com/@PACKAGE@/@PACKAGE@/releases \
.*/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@

View File

@ -3,7 +3,7 @@
include ../src/defs
python-xlib_toc.html: $(SRCS)
makeinfo --output=. --html --split=node $(TOPSRC)
texi2html --output=. --split=node --menu $(TOPSRC)
ln -sf python-xlib_toc.html index.html
clean:

View File

@ -9,4 +9,4 @@
Here you might find an introduction to X concepts sometime in the
future. For now, I just refer to the introduction parts of the standard
X documentation. A vast collection of X documentation links can be
found at @uref{http://www.rahul.net/kenton/xsites.html}.
found at @uref{https://web.archive.org/web/20201228053920/http://www.rahul.net/kenton/xsites.html}.

View File

@ -142,7 +142,7 @@ Forget any caught error.
Since the X protocol is mostly asynchronous any error we're watching for
might not have been recieved when we call @code{get_error}. To make
might not have been received when we call @code{get_error}. To make
sure that the request has been processed by the server and any error
generated has been received by the Xlib, we must synchronize with the
server.

View File

@ -22,7 +22,7 @@ typically by doing one or more X requests.
@section Getting Events
Events can be sent at any time, not necessarily when the client is ready
to recieve an event. Therefore they must be stored temporarily from that
to receive an event. Therefore they must be stored temporarily from that
they are read from the network until the client is ready to handle them.
Read but unhandled events are stored on an event queue in the Display
object. There are two functions to access this queue:
@ -72,7 +72,7 @@ while 1:
if not readable:
handle_timeout()
# if display is readable, handle as many events as have been recieved
# if display is readable, handle as many events as have been received
elif disp in readable:
i = disp.pending_events()
while i > 0:

View File

@ -205,7 +205,7 @@ list items have the following attributes:
The ID of this visual.
@item visual_class
One of @code{X.StaticGrey}, @code{X.StaticColor}, @code{X.TrueColor},
One of @code{X.StaticGray}, @code{X.StaticColor}, @code{X.TrueColor},
@code{X.GrayScale}, @code{X.PseudoColor}, or @code{X.DirectColor}.
@item bits_per_rgb_value
@ -475,7 +475,7 @@ The name of the font.
@itemx font_ascent
@itemx font_descent
@itemx replies_hint
See the descripton of XFontStruct in XGetFontProperty(3X11) for details
See the description of XFontStruct in XGetFontProperty(3X11) for details
on these values.
@item properties
@ -678,7 +678,8 @@ XGetScreenSaver(3X11) for details.
@var{mode} is either @code{X.HostInsert} or @code{X.HostDelete}.
@var{host_family} is one of @code{X.FamilyInternet},
@code{X.FamilyDECnet} or @code{X.FamilyChaos}.
@code{X.FamilyDECnet}, @code{X.FamilyChaos}, @code{X.FamilyServerInterpreted}
or @code{X.FamilyInternetV6}.
@var{host} is a list of bytes. For the Internet family, it should be
the four bytes of an IPv4 address.
@ -699,7 +700,8 @@ The hosts on the access list. Each entry has the following attributes:
@table @code
@item family
@code{X.FamilyInternet}, @code{X.FamilyDECnet}, or @code{X.FamilyChaos}.
@code{X.FamilyInternet}, @code{X.FamilyDECnet}, @code{X.FamilyChaos},
@code{X.FamilyServerInterpreted} or @code{X.FamilyInternetV6}.
@item name
A list of byte values, the coding depends on @code{family}. For the
@ -1175,7 +1177,7 @@ Returns None or string.
@end defmethod
@defmethod Window get_wm_class ( )
Returns None or (isntance, class)
Returns None or (instance, class)
@end defmethod
@defmethod Window set_wm_transient_for ( window, onerror = None )

View File

@ -39,13 +39,6 @@ except that this permission notice may be stated in a
translation approved by the Free Software Foundation.
@end ifinfo
@ifinfo
@dircategory Python
@direntry
* python-xlib: (python-xlib). Interface for Python to the X11 Protocol
@end direntry
@end ifinfo
@titlepage
@title The Python X Library
@author Peter Liljenberg

130
examples/dpms.py Executable file
View File

@ -0,0 +1,130 @@
#!/usr/bin/python
#
# examples/dpms.py -- DPMS usage examples.
#
# Copyright (C) 2020 Thiago Kenji Okada <thiagokokada@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
import random
import time
from Xlib import display
from Xlib.ext import dpms
class DPMSExamples(object):
def __init__(self):
self.d = display.Display()
capable = self.d.dpms_capable()
assert capable, 'DPMS is not supported in your system'
self.initial_info = self.d.dpms_info()
self.initial_timeouts = self.d.dpms_get_timeouts()
# Making sure that DPMS is enable for this examples
self.d.dpms_enable()
self.d.sync()
def print_dpms(self):
current_info = self.d.dpms_info()
print('\nDPMS state: {}\nPower level: {}'.format(current_info.state,
current_info.power_level))
current_timeouts = self.d.dpms_get_timeouts()
print('Standby: {}, Suspend: {}, Off: {}\n'.format(current_timeouts.standby_timeout,
current_timeouts.suspend_timeout,
current_timeouts.off_timeout))
def toggle_dpms(self):
current_info = self.d.dpms_info()
if current_info.state:
self.d.dpms_disable()
else:
self.d.dpms_enable()
self.d.sync()
def restore(self):
print('Restoring DPMS configuration')
self.d.dpms_set_timeouts(self.initial_timeouts.standby_timeout,
self.initial_timeouts.suspend_timeout,
self.initial_timeouts.off_timeout)
if self.initial_info.state:
self.d.dpms_enable()
else:
self.d.dpms_disable()
self.d.sync()
self.print_dpms()
def set_random_timeouts(self):
# Can be any number greater than 0
# Using 10 just to not turnoff the screen suddenly
standby_timeout = random.randint(10, 600)
# Shouldn't be smaller than standby_timeout
suspend_timeout = random.randint(standby_timeout, 600)
# Shouldn't be smaller than standby_timeout or suspend_timeout
off_timeout = random.randint(suspend_timeout, 600)
self.d.dpms_set_timeouts(standby_timeout, suspend_timeout, off_timeout)
self.d.sync()
def turn_off_display(self):
self.d.dpms_force_level(dpms.DPMSModeOff)
self.d.sync()
def turn_on_display(self):
self.d.dpms_force_level(dpms.DPMSModeOn)
self.d.sync()
def main():
try:
examples = DPMSExamples()
print('Initial state')
examples.print_dpms()
print('Setting random timeouts')
examples.set_random_timeouts()
examples.print_dpms()
print('The next example will turn-off your screen, press Ctrl-C to cancel.')
time.sleep(2)
examples.turn_off_display()
print('Turning it on again...')
time.sleep(2)
examples.turn_on_display()
print()
print('Toggle DPMS')
examples.toggle_dpms()
examples.print_dpms()
print('Toggle it again')
examples.toggle_dpms()
examples.print_dpms()
finally:
examples.restore()
if __name__ == '__main__':
main()

View File

@ -83,7 +83,7 @@ def main():
# since we don't have an event here we have to.
w.convert_selection(sel_atom, target_atom, data_atom, X.CurrentTime)
# Wait for the notificiaton that we got the selection
# Wait for the notification that we got the selection
while True:
e = d.next_event()
if e.type == X.SelectionNotify:

95
examples/nvcontrol.py Executable file
View File

@ -0,0 +1,95 @@
#!/usr/bin/python
#
# examples/nvcontrol.py -- demonstrate the NV-CONTROL extension
#
# Copyright (C) 2019 Roberto Leinardi <roberto@leinardi.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
# Change path so we find Xlib
from pprint import pprint
from Xlib.display import Display
from Xlib.ext.nvcontrol import Gpu, Cooler
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
if __name__ == '__main__':
display = Display()
# Check for extension
if not display.has_extension('NV-CONTROL'):
sys.stderr.write('{}: server does not have the NV-CONTROL extension\n'.format(sys.argv[0]))
ext = display.query_extension('NV-CONTROL')
print(ext)
sys.stderr.write("\n".join(display.list_extensions()))
if ext is None:
sys.exit(1)
gpu = Gpu(0)
fan = Cooler(0)
perf_level = 3
dic = {
'get_gpu_count': display.nvcontrol_get_gpu_count(),
'get_vram': display.nvcontrol_get_vram(gpu),
'get_irq': display.nvcontrol_get_irq(gpu),
'supports_framelock': display.nvcontrol_supports_framelock(gpu),
'get_core_temp': display.nvcontrol_get_core_temp(gpu),
'get_core_threshold': display.nvcontrol_get_core_threshold(gpu),
'get_default_core_threshold': display.nvcontrol_get_default_core_threshold(gpu),
'get_max_core_threshold': display.nvcontrol_get_max_core_threshold(gpu),
'get_ambient_temp': display.nvcontrol_get_ambient_temp(gpu),
'get_cuda_cores': display.nvcontrol_get_cuda_cores(gpu),
'get_memory_bus_width': display.nvcontrol_get_memory_bus_width(gpu),
'get_total_dedicated_gpu_memory': display.nvcontrol_get_total_dedicated_gpu_memory(gpu),
'get_used_dedicated_gpu_memory': display.nvcontrol_get_used_dedicated_gpu_memory(gpu),
'get_curr_pcie_link_width': display.nvcontrol_get_curr_pcie_link_width(gpu),
'get_max_pcie_link_width': display.nvcontrol_get_max_pcie_link_width(gpu),
'get_curr_pcie_link_generation': display.nvcontrol_get_curr_pcie_link_generation(gpu),
'get_encoder_utilization': display.nvcontrol_get_encoder_utilization(gpu),
'get_decoder_utilization': display.nvcontrol_get_decoder_utilization(gpu),
'get_current_performance_level': display.nvcontrol_get_current_performance_level(gpu),
'get_gpu_nvclock_offset': display.nvcontrol_get_gpu_nvclock_offset(gpu, perf_level),
'get_mem_transfer_rate_offset': display.nvcontrol_get_mem_transfer_rate_offset(gpu, perf_level),
'get_cooler_manual_control_enabled': display.nvcontrol_get_cooler_manual_control_enabled(gpu),
'get_fan_duty': display.nvcontrol_get_fan_duty(fan),
'get_fan_rpm': display.nvcontrol_get_fan_rpm(fan),
'get_coolers_used_by_gpu': display.nvcontrol_get_coolers_used_by_gpu(gpu),
'get_max_displays': display.nvcontrol_get_max_displays(gpu),
'get_name': display.nvcontrol_get_name(gpu),
'get_driver_version': display.nvcontrol_get_driver_version(gpu),
'get_vbios_version': display.nvcontrol_get_vbios_version(gpu),
'get_gpu_uuid': display.nvcontrol_get_gpu_uuid(gpu),
'get_utilization_rates': display.nvcontrol_get_utilization_rates(gpu),
'get_performance_modes': display.nvcontrol_get_performance_modes(gpu),
'get_gpu_nvclock_offset_range': display.nvcontrol_get_gpu_nvclock_offset_range(gpu, perf_level),
'get_mem_transfer_rate_offset_range': display.nvcontrol_get_mem_transfer_rate_offset_range(gpu, perf_level),
'get_clock_info': display.nvcontrol_get_clock_info(gpu)
}
pprint(dic)
display.close()

View File

@ -77,6 +77,10 @@ class TestExamples(unittest.TestCase):
""" Run xlsatoms.py -- show list atoms on X server """
self.assertEqual(run_example(examples_folder + "xlsatoms.py"), 0)
def test_xres(self):
""" Run xres.py -- demonstrate the X-Resource extension """
self.assertEqual(run_example(examples_folder + "xres.py"), 0)
if __name__ == '__main__':
unittest.main()

139
examples/xdamage.py Normal file
View File

@ -0,0 +1,139 @@
#!/usr/bin/python
#
# examples/xdamage.py -- demonstrate damage extension
#
# Copyright (C) 2019 Mohit Garg <mrmohitgarg1990@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
# Change path so we find Xlib
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from Xlib import display, X, threaded,Xutil
import time
try:
import thread
except ModuleNotFoundError:
import _thread as thread
from Xlib.ext import damage
from PIL import Image, ImageTk
import traceback
def redraw(win, gc):
# win.clear_area()
win.fill_rectangle(gc, 0, 0, 60, 60)
def blink(display, win, gc, cols):
while 1:
time.sleep(2)
print('Changing color', cols[0])
gc.change(foreground = cols[0])
cols = (cols[1], cols[0])
redraw(win, gc)
display.flush()
def get_image_from_win(win, pt_w, pt_h, pt_x=0, pt_y=0):
try:
raw = win.get_image(pt_x, pt_y, pt_w, pt_h, X.ZPixmap, 0xffffffff)
image = Image.frombytes("RGB", (pt_w, pt_h), raw.data, "raw", "BGRX")
return image
except Exception:
traceback.print_exc()
def check_ext(disp):
# Check for extension
if not disp.has_extension('DAMAGE'):
sys.stderr.write('server does not have the DAMAGE extension\n')
sys.stderr.write("\n".join(disp.list_extensions()))
if disp.query_extension('DAMAGE') is None:
sys.exit(1)
else:
r = disp.damage_query_version()
print('DAMAGE version {}.{}'.format(r.major_version, r.minor_version))
def main():
d = display.Display()
root = d.screen().root
check_ext(d)
colormap = d.screen().default_colormap
red = colormap.alloc_named_color("red").pixel
blue = colormap.alloc_named_color("blue").pixel
background = colormap.alloc_named_color("white").pixel
window1 = root.create_window(100, 100, 250, 100, 1,
X.CopyFromParent, X.InputOutput,
X.CopyFromParent,
background_pixel = background,
event_mask = X.StructureNotifyMask | X.ExposureMask)
window1.set_wm_name('Changing Window')
window1.map()
gc = window1.create_gc(foreground = red)
thread.start_new_thread(blink, (d, window1, gc, (blue, red)))
window1.damage_create(damage.DamageReportRawRectangles)
window1.set_wm_normal_hints(
flags=(Xutil.PPosition | Xutil.PSize | Xutil.PMinSize),
min_width=50,
min_height=50
)
window2 = root.create_window(100, 250, 250, 100, 1,
X.CopyFromParent, X.InputOutput,
X.CopyFromParent,
background_pixel = background,
event_mask = X.StructureNotifyMask | X.ExposureMask)
window2.set_wm_normal_hints(
flags=(Xutil.PPosition | Xutil.PSize | Xutil.PMinSize),
min_width=50,
min_height=50
)
window2.set_wm_name('Tracking Window')
window2.map()
while 1:
event = d.next_event()
if event.type == X.Expose:
if event.count == 0:
redraw(window1, gc)
elif event.type == d.extension_event.DamageNotify:
image = get_image_from_win(window1, event.area.width, event.area.height, event.area.x, event.area.y)
bgpm = window2.create_pixmap(image.width, image.height, d.screen().root_depth)
bggc = window2.create_gc(foreground=0, background=0)
bgpm.put_pil_image(bggc, 0, 0, image)
window2.copy_area(bggc, bgpm, 0, 0, image.width, image.height, 0, 0)
# bggc.free()
elif event.type == X.DestroyNotify:
sys.exit(0)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,72 @@
#!/usr/bin/python3
#
# examples/xfixes-cursor-notify.py -- demonstrate the XFIXES extension
# CursorNotify event.
#
# Copyright (C) 2022
# Dan Isla <dan.isla@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
from Xlib.display import Display
from Xlib.ext import xfixes
def main():
display = Display()
if not display.has_extension('XFIXES'):
if display.query_extension('XFIXES') is None:
print('XFIXES extension not supported')
return 1
xfixes_version = display.xfixes_query_version()
print('Found XFIXES version {}.{}'.format(
xfixes_version.major_version,
xfixes_version.minor_version
))
screen = display.screen()
display.xfixes_select_cursor_input(screen.root, xfixes.XFixesDisplayCursorNotifyMask)
cursor_cache = {}
while True:
e = display.next_event()
print(e)
if (e.type, e.sub_code) == display.extension_event.DisplayCursorNotify:
print("DisplayCursorNotify: cursor_serial={}".format(e.cursor_serial))
image = display.xfixes_get_cursor_image(screen.root)
cached = False
if cursor_cache.get(image.cursor_serial):
cached = True
else:
cursor_cache[image.cursor_serial] = image.cursor_image
print("Cursor position={},{}, size={}x{}, xyhot={},{}, cursor_serial={}, cached={}".format(
image.x, image.y, image.width,image.height, image.xhot, image.yhot, image.cursor_serial, cached
))
if __name__ == "__main__":
sys.exit(main())

View File

@ -0,0 +1,82 @@
#!/usr/bin/python3
#
# examples/xfixes-selection-notify.py -- demonstrate the XFIXES extension
# SelectionNotify event.
#
# Copyright (C) 2019
# Tony Crisci <tony@dubstepdish.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 time
# Change path so we find Xlib
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from Xlib.display import Display
from Xlib.ext import xfixes
def main(argv):
if len(sys.argv) != 2:
sys.exit('usage: {0} SELECTION\n\n'
'SELECTION is typically PRIMARY, SECONDARY or CLIPBOARD.\n'
.format(sys.argv[0]))
display = Display()
sel_name = sys.argv[1]
sel_atom = display.get_atom(sel_name)
if not display.has_extension('XFIXES'):
if display.query_extension('XFIXES') is None:
print('XFIXES extension not supported', file=sys.stderr)
return 1
xfixes_version = display.xfixes_query_version()
print('Found XFIXES version %s.%s' % (
xfixes_version.major_version,
xfixes_version.minor_version,
), file=sys.stderr)
screen = display.screen()
mask = xfixes.XFixesSetSelectionOwnerNotifyMask | \
xfixes.XFixesSelectionWindowDestroyNotifyMask | \
xfixes.XFixesSelectionClientCloseNotifyMask
display.xfixes_select_selection_input(screen.root, sel_atom, mask)
while True:
e = display.next_event()
print(e)
if (e.type, e.sub_code) == display.extension_event.SetSelectionOwnerNotify:
print('SetSelectionOwner: owner=0x{0:08x}'.format(e.owner.id))
elif (e.type, e.sub_code) == display.extension_event.SelectionWindowDestroyNotify:
print('SelectionWindowDestroy: owner=0x{0:08x}'.format(e.owner.id))
elif (e.type, e.sub_code) == display.extension_event.SelectionClientCloseNotify:
print('SelectionClientClose: owner=0x{0:08x}'.format(e.owner.id))
if __name__ == '__main__':
sys.exit(main(sys.argv))

View File

@ -58,7 +58,7 @@ def main(argv):
time.sleep(5)
print('Showing cursor ...', file=sys.stderr)
screen.root.xfixes_hide_cursor()
screen.root.xfixes_show_cursor()
display.sync()

View File

@ -42,11 +42,11 @@ class Window(object):
# Check for extension
if not self.d.has_extension('XINERAMA'):
sys.stderr.write('%s: server does not have the XINERAMA extension\n'
% sys.argv[0])
print(self.d.query_extension('XINERAMA'))
sys.stderr.write('{}: server does not have the XINERAMA extension\n'.format(sys.argv[0]))
ext = self.d.query_extension('XINERAMA')
print(ext)
sys.stderr.write("\n".join(self.d.list_extensions()))
if self.d.query_extension('XINERAMA') is None:
if ext is None:
sys.exit(1)
# print version

View File

@ -42,11 +42,11 @@ class Window(object):
# Check for extension
if not self.d.has_extension('RANDR'):
sys.stderr.write('%s: server does not have the RANDR extension\n'
% sys.argv[0])
print(self.d.query_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 self.d.query_extension('RANDR') is None:
if ext is None:
sys.exit(1)
# print(version)

85
examples/xres.py Executable file
View File

@ -0,0 +1,85 @@
#!/usr/bin/python
#
# examples/xres.py -- demonstrate the X-Resource extension
#
# Copyright (C) 2021 Aleksei Bavshin <alebastr89@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.,
# 51 Franklin Street,
# Fifth Floor,
# Boston, MA 02110-1301 USA
import os
import sys
# Change path so we find Xlib
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from Xlib.display import Display
from Xlib.ext import res as XRes
def check_ext(disp, extname, version):
if disp.query_extension(extname) is None:
raise AssertionError("Server has {} extension".format(extname))
r = disp.res_query_version()
if (r.server_major, r.server_minor) < version:
raise AssertionError(
"Server has requested version {} of {} extension".format(version, extname)
)
def query_client_id(display, wid):
specs = [{"client": wid, "mask": XRes.LocalClientPIDMask}]
r = display.res_query_client_ids(specs)
for id in r.ids:
if id.spec.client > 0 and id.spec.mask == XRes.LocalClientPIDMask:
for value in id.value:
return value
return None
def print_client_info(disp, client):
print("client: {}".format(client))
resources = disp.res_query_client_resources(client)
rc = [r.count for r in resources.types]
print("\tresouces: {} resources of {} types".format(sum(rc), len(rc)))
pb = disp.res_query_client_pixmap_bytes(client)
print("\tpixmaps: {} bytes {} overflow".format(pb.bytes, pb.bytes_overflow))
pid = query_client_id(disp, client)
print("\tpid: {}".format(pid))
rb = disp.res_query_resource_bytes(client, [{"resource": 0, "type": 0}])
sizes = [s.size.bytes for s in rb.sizes]
print("\t{} resources consume {} bytes".format(len(sizes), sum(sizes)))
def main():
display = Display()
check_ext(display, XRes.extname, (1, 2))
clients = display.res_query_clients().clients
print("{} clients connected to the server".format(len(clients)))
for client in clients:
print_client_info(display, client.resource_base)
if __name__ == "__main__":
main()

View File

@ -1,150 +0,0 @@
Metadata-Version: 1.1
Name: python-xlib
Version: 0.23
Summary: Python X Library
Home-page: https://github.com/python-xlib/python-xlib
Author: Peter Liljenberg
Author-email: petli@ctrl-c.liu.se
License: LGPLv2+
Download-URL: https://github.com/python-xlib/python-xlib/releases
Description-Content-Type: UNKNOWN
Description: The Python X Library
====================
|Build Status| |codecov.io| |Code Health|
`Homepage`_ | `Releases`_ | `Changelog`_
Copyright
~~~~~~~~~
The main part of the code is
::
Copyright (C) 2000-2002 Peter Liljenberg
Some contributed code is copyrighted by `the contributors <Contributors_>`_,
in these cases that is indicated in the source files in question.
The Python X Library is released under LGPL v2.1 or later (since 2016),
see the file LICENSE for details. 0.15rc1 and before were released under
GPL v2.
Requirements
~~~~~~~~~~~~
The Python X Library requires Python 2.7 or newer. It has been tested to
various extents with Python 2.7 and 3.3 through 3.6.
Installation
~~~~~~~~~~~~
The Python Xlib uses the standard setuptools package, to install run
this command:
::
python setup.py install
See the command help for details: ``python setup.py install -h``.
Alternatively, you can run programs from the distribution directory, or
change the module path in programs.
There's a simple example program, implemented twice using both the
high-level interface and the low-level protocol.
Introduction
~~~~~~~~~~~~
The Python X Library is intended to be a fully functional X client
library for Python programs. It is written entirely in Python, in
contrast to earlier X libraries for Python (the ancient X extension and
the newer plxlib) which were interfaces to the C Xlib.
This is possible to do since X client programs communicate with the X
server via the X protocol. The communication takes place over TCP/IP,
Unix sockets, DECnet or any other streaming network protocol. The C Xlib
is merely an interface to this protocol, providing functions suitable
for a C environment.
There are three advantages of implementing a pure Python library:
- Integration: The library can make use of the wonderful object system
in Python, providing an easy-to-use class hierarchy.
- Portability: The library will be usable on (almost) any computer
which have Python installed. A C interface could be problematic to
port to non-Unix systems, such as MS Windows or OpenVMS.
- Maintainability: It is much easier to develop and debug native Python
modules than modules written in C.
Documentation
~~~~~~~~~~~~~
The reference manual is not finished by far, but is probably still useful. It
can be `browsed online <http://python-xlib.sourceforge.net/doc/html/index.html>`__.
There are also some `example programs <Examples_>`_ and, of course,
`the standard X11 documentation <http://tronche.com/gui/x/xlib/>`__ applies.
Project status
~~~~~~~~~~~~~~
The low-level protocol is complete, implementing client-side X11R6. The
high-level object oriented interface is also fully functional. It is
possible to write client applications with the library. Currently, the
only real application using Python Xlib is the window manager PLWM,
starting with version 2.0.
There is a resource database implementation, ICCCM support and a
framework for adding X extension code. Several extensions have been
implemented; (RECORD, SHAPE, Xinerama, Composite, RANDR, and XTEST)
patches for additions are very welcome.
There are most likely still bugs, but the library is at least stable
enough to run PLWM. A continuously bigger part of the library is covered
by regression tests, improving stability.
The documentation is still quite rudimentary, but should be of some help
for people programming with the Xlib. X beginners should first find some
general texts on X. A very good starting point is
http://www.rahul.net/kenton/xsites.html
See the file TODO for a detailed list of what is missing, approximately
ordered by importance.
.. _Homepage: https://github.com/python-xlib/python-xlib
.. _Releases: https://github.com/python-xlib/python-xlib/releases
.. _Changelog: https://github.com/python-xlib/python-xlib/tree/master/CHANGELOG.md
.. _Contributors: https://github.com/python-xlib/python-xlib/graphs/contributors
.. _Examples: https://github.com/python-xlib/python-xlib/tree/master/examples
.. |Build Status| image:: https://travis-ci.org/python-xlib/python-xlib.svg?branch=master
:target: https://travis-ci.org/python-xlib/python-xlib
.. |codecov.io| image:: https://codecov.io/github/python-xlib/python-xlib/coverage.svg?branch=master
:target: https://codecov.io/github/python-xlib/python-xlib?branch=master
.. |Code Health| image:: https://landscape.io/github/python-xlib/python-xlib/master/landscape.svg?style=flat
:target: https://landscape.io/github/python-xlib/python-xlib/master
Keywords: windows,x,x11,xlib
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: X11 Applications
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: User Interfaces

View File

@ -1,137 +0,0 @@
.gitignore
.landscape.yml
.travis.yml
CHANGELOG.md
LICENSE
README.rst
TODO
codecov.yml
dev-requirements.txt
requirements.txt
runtests.py
setup.cfg
setup.py
test.sh
tox.ini
Xlib/ChangeLog
Xlib/X.py
Xlib/XK.py
Xlib/Xatom.py
Xlib/Xcursorfont.py
Xlib/Xutil.py
Xlib/__init__.py
Xlib/display.py
Xlib/error.py
Xlib/rdb.py
Xlib/threaded.py
Xlib/xauth.py
Xlib/ext/__init__.py
Xlib/ext/composite.py
Xlib/ext/ge.py
Xlib/ext/randr.py
Xlib/ext/record.py
Xlib/ext/security.py
Xlib/ext/shape.py
Xlib/ext/xfixes.py
Xlib/ext/xinerama.py
Xlib/ext/xinput.py
Xlib/ext/xtest.py
Xlib/keysymdef/__init__.py
Xlib/keysymdef/apl.py
Xlib/keysymdef/arabic.py
Xlib/keysymdef/cyrillic.py
Xlib/keysymdef/greek.py
Xlib/keysymdef/hebrew.py
Xlib/keysymdef/katakana.py
Xlib/keysymdef/korean.py
Xlib/keysymdef/latin1.py
Xlib/keysymdef/latin2.py
Xlib/keysymdef/latin3.py
Xlib/keysymdef/latin4.py
Xlib/keysymdef/miscellany.py
Xlib/keysymdef/publishing.py
Xlib/keysymdef/special.py
Xlib/keysymdef/technical.py
Xlib/keysymdef/thai.py
Xlib/keysymdef/xf86.py
Xlib/keysymdef/xk3270.py
Xlib/keysymdef/xkb.py
Xlib/protocol/ChangeLog
Xlib/protocol/__init__.py
Xlib/protocol/display.py
Xlib/protocol/event.py
Xlib/protocol/request.py
Xlib/protocol/rq.py
Xlib/protocol/structs.py
Xlib/support/__init__.py
Xlib/support/connect.py
Xlib/support/lock.py
Xlib/support/unix_connect.py
Xlib/support/vms_connect.py
Xlib/xobject/__init__.py
Xlib/xobject/colormap.py
Xlib/xobject/cursor.py
Xlib/xobject/drawable.py
Xlib/xobject/fontable.py
Xlib/xobject/icccm.py
Xlib/xobject/resource.py
debian/changelog
debian/control
debian/copyright
debian/dirs
debian/postinst
debian/prerm
debian/rules
doc/Makefile
doc/html/Makefile
doc/info/Makefile
doc/ps/Makefile
doc/src/Makefile
doc/src/concepts.texi
doc/src/connect.texi
doc/src/defs
doc/src/errors.texi
doc/src/events.texi
doc/src/objects.texi
doc/src/package.texi
doc/src/python-xlib.texi
examples/childwin.py
examples/draw-proto.py
examples/draw.py
examples/eventthread.py
examples/get_selection.py
examples/profilex.py
examples/put_selection.py
examples/record_demo.py
examples/run_examples.py
examples/security.py
examples/shapewin.py
examples/threadtest.py
examples/xfixes.py
examples/xinerama.py
examples/xinput.py
examples/xlsatoms.py
examples/xrandr.py
python_xlib.egg-info/PKG-INFO
python_xlib.egg-info/SOURCES.txt
python_xlib.egg-info/dependency_links.txt
python_xlib.egg-info/requires.txt
python_xlib.egg-info/top_level.txt
test/__init__.py
test/test_bytesview.py
test/test_events_be.py
test/test_events_le.py
test/test_manual.py
test/test_rdb.py
test/test_requests_be.py
test/test_requests_le.py
test/test_struct.py
test/test_unix_connect.py
test/test_xlib_display.py
test/gen/.gitignore
test/gen/eventdef
test/gen/genprotocol.awk
test/gen/genprottest.py
test/gen/protdef
utils/parsexbug.py
utils/tcpbug.py

View File

@ -1 +0,0 @@

View File

@ -1 +0,0 @@
six>=1.10.0

View File

@ -1 +0,0 @@
Xlib

View File

@ -8,12 +8,12 @@ url = https://github.com/python-xlib/python-xlib
license = LGPLv2+
author = Peter Liljenberg
author_email = petli@ctrl-c.liu.se
keywords =
keywords =
windows
x
x11
xlib
classifiers =
classifiers =
Development Status :: 5 - Production/Stable
Environment :: X11 Applications
Intended Audience :: Developers
@ -26,6 +26,8 @@ classifiers =
Programming Language :: Python :: 3.5
Programming Language :: Python :: 3.5
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: Implementation :: CPython
Topic :: Software Development :: Libraries :: Python Modules
Topic :: Software Development :: Libraries
@ -34,7 +36,4 @@ classifiers =
[bdist_wheel]
universal = 1
[egg_info]
tag_build =
tag_date = 0
# vim: list

View File

@ -72,8 +72,8 @@ class TestUnixConnect(unittest.TestCase):
def path_exists(returns, path):
calls.append(('os.path.exists', path))
return returns
def fcntl(*args):
calls.append(('fcntl',) + args)
def ensure_not_inheritable(*args):
calls.append(('ensure_not_inheritable',) + args)
for params, allow_unix, unix_addr_exists, allow_tcp, expect_connection_error, expected_calls in (
# Successful explicit TCP socket connection.
(('tcp/host:6', None, 'host', 6), False, False, True, False, [
@ -141,7 +141,7 @@ class TestUnixConnect(unittest.TestCase):
partial(_get_socket, 'tcp', not allow_tcp)), \
patch('os.path.exists',
partial(path_exists, unix_addr_exists)), \
patch('fcntl.fcntl', fcntl):
patch('Xlib.support.unix_connect._ensure_not_inheritable', ensure_not_inheritable):
del calls[:]
if expect_connection_error:
with self.assertRaises(DisplayConnectionError):
@ -149,9 +149,7 @@ class TestUnixConnect(unittest.TestCase):
else:
s = unix_connect.get_socket(*params)
self.assertIsInstance(s, FakeSocket)
expected_calls.append(('fcntl', 42,
unix_connect.F_SETFD,
unix_connect.FD_CLOEXEC))
expected_calls.append(('ensure_not_inheritable', s))
self.assertEqual(calls, expected_calls)

View File

@ -87,7 +87,7 @@ class TestXlibDisplay(unittest.TestCase):
self.assertRaises(AssertionError, self.display.extension_add_method, "font", "__init__", lambda x: x)
def test_can_add_extension_error(self):
self.display.add_extension_error(1, Xlib.error.XError)
self.display.extension_add_error(1, Xlib.error.XError)
self.assertEqual(self.display.display.error_classes[1], Xlib.error.XError)
def test_keycode_to_keysym_for_invalid_index(self):