pax_global_header 0000666 0000000 0000000 00000000064 12565733531 0014524 g ustar 00root root 0000000 0000000 52 comment=1a48b2430ed281eb08a8c4bebf60aaa815405a5f
xcffib-0.3.6/ 0000775 0000000 0000000 00000000000 12565733531 0012773 5 ustar 00root root 0000000 0000000 xcffib-0.3.6/.gitignore 0000664 0000000 0000000 00000000252 12565733531 0014762 0 ustar 00root root 0000000 0000000 build
dist
*.swp
*.swo
*.pyc
*__pycache__*
*.egg-info
xcffib
build/
*egg*
*deb
debian/*.log
debian/files
debian/tmp
debian/python-xcffib*
debian/python3-xcffib*
.pybuild
xcffib-0.3.6/.travis.yml 0000664 0000000 0000000 00000000743 12565733531 0015110 0 ustar 00root root 0000000 0000000 language: python
python:
- 2.6
- 2.7
- 3.2
- 3.3
- 3.4
- pypy
- pypy3
cache:
directories:
- $HOME/.cache/pip
- $HOME/.cabal/lib
addons:
apt:
packages:
- xcb-proto
- ghc
- cabal-install
- happy
- alex
- x11-apps
- xvfb
install:
- cabal update
- cabal install --only-dependencies --enable-tests
- cabal configure --enable-tests
- pip install -r requirements.txt
script: "make -j3 check"
sudo: false
xcffib-0.3.6/LICENSE 0000664 0000000 0000000 00000023676 12565733531 0014016 0 ustar 00root root 0000000 0000000
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
xcffib-0.3.6/MANIFEST.in 0000664 0000000 0000000 00000000071 12565733531 0014527 0 ustar 00root root 0000000 0000000 include README.md
include LICENSE
exclude xcffib/_ffi.py
xcffib-0.3.6/Makefile 0000664 0000000 0000000 00000004533 12565733531 0014440 0 ustar 00root root 0000000 0000000 GEN=./dist/build/xcffibgen/xcffibgen
AUTOPEP8=autopep8 --in-place --aggressive --aggressive
XCBVER=$(shell pkg-config --modversion xcb-proto)
XCBDIR=$(shell pkg-config --variable=xcbincludedir xcb-proto)
NCPUS=$(shell grep -c processor /proc/cpuinfo)
PARALLEL=$(shell which parallel)
CABAL=cabal --config-file=/dev/null
# you should have xcb-proto installed to run this
xcffib: $(GEN) module/*.py
$(GEN) --input $(XCBDIR) --output ./xcffib
cp ./module/*py ./xcffib/
sed -i "s/__xcb_proto_version__ = .*/__xcb_proto_version__ = \"${XCBVER}\"/" xcffib/__init__.py
python xcffib/ffi_build.py
.PHONY: xcffib-fmt
xcffib-fmt: $(GEN) module/*.py
ifeq (${PARALLEL},)
$(AUTOPEP8) ./xcffib/*.py
else
find ./xcffib/*.py | parallel -j $(NCPUS) $(AUTOPEP8) '{}'
endif
dist:
$(CABAL) configure --enable-tests
.PHONY: $(GEN)
$(GEN): dist
$(CABAL) build
.PHONY: clean
clean:
-$(CABAL) clean
-rm -rf xcffib
-rm -rf module/*pyc module/__pycache__
-rm -rf tests/*pyc tests/__pycache__
-rm -rf build *egg* *deb .pybuild
-rm -rf .pc
# A target for just running nosetests. Travis will run 'check', which does
# everything. (Additionally, travis uses separate environments where nosetests
# points to The Right Thing for each, so we don't need to do nosetests3.)
pycheck: xcffib
nosetests -d
nosetests3 -d
valgrind: xcffib
valgrind --leak-check=full --show-leak-kinds=definite nosetests -d
newtests: $(GEN)
$(GEN) --input ./tests/generator/ --output ./tests/generator/
git diff tests
# These are all split out so make -j3 check goes as fast as possible.
.PHONY: lint
lint:
flake8 --config=./tests/flake8.cfg ./module
.PHONY: htests
htests: $(GEN)
$(CABAL) test
check: xcffib lint htests
nosetests -d -v
deb:
git buildpackage --git-upstream-tree=master
lintian
deb-src:
git buildpackage --git-upstream-tree=master -S
# make release ver=0.99.99
release: xcffib
ifeq (${ver},)
@echo "no version (ver=) specified, not releasing."
else ifneq ($(wildcard ./xcffib.egg-info*),)
@echo "xcffib.egg-info exists, not releasing."
else
sed -i "s/version = .*/version = \"${ver}\"/" setup.py
sed -r -i -e "s/(^version = \s*)[\"0-9\.]*/\1\"${ver}\"/" setup.py
sed -r -i -e "s/(^version:\s*)[0-9\.]*/\1${ver}/" xcffib.cabal
git commit -a -m "Release v${ver}"
git tag v${ver}
python setup.py sdist
python setup.py sdist upload
cabal sdist
cabal upload dist/xcffib-${ver}.tar.gz
endif
xcffib-0.3.6/README.md 0000664 0000000 0000000 00000011751 12565733531 0014257 0 ustar 00root root 0000000 0000000 # xcffib [](https://travis-ci.org/tych0/xcffib)
`xcffib` is intended to be a (mostly) drop-in replacement for `xpyb`. `xpyb`
has an inactive upstream, several memory leaks, is python2 only and doesn't
have pypy support. `xcffib` is a binding which uses
[cffi](https://cffi.readthedocs.org/), which mitigates some of the issues
described above. `xcffib` also builds bindings for 27 of the 29 (xprint and xkb
are missing) X extensions in 1.10.
## Installation
For most end users of software that depends on xcffib or developers writing
code against xcffib, you can use the version of xcffib on pypi. To install it,
you'll need libxcb's headers and libxcb-render's headers (these are available
via `sudo apt-get install libxcb-render0-dev` on Ubuntu). Once you have the C
headers installed, you can just `pip install xcffib`.
If you're interested in doing development, read on...
## Development dependencies
You should be able to install all the language deps from hackage or pip. The
[.travis.yaml](https://github.com/tych0/xcffib/blob/master/.travis.yml) has an
example of how to install the dependencies on Ubuntu flavors.
## Hacking
See the [Makefile](https://github.com/tych0/xcffib/blob/master/Makefile) for
examples on how to run the tests. Your contribution should at pass `make check`
before it can be merged. The `newtests` make target can be used to regenerate
expected haskell test data if the tests are failing because you made a change
to the generated python code.
## Differences
In general, you should `s/xcb/xcffib/g`. Explicit differences are listed below,
however I don't think these will prevent any porting, because these were either
not public APIs, or not actually generated (in the case of the exceptions) by
`xpyb`. I think most porting should Just Work via the regex above.
* `xcb.Exception` is spelled `xcffib.XcffibException` and is also a parent of
all exceptions generated by xcffib.
* `xcb.ConnectException` is gone, it was unused
* `xcffib.ConnectionException` is raised on connection errors
* `xcb.Iterator` is gone; similar functionality is implemented by
`xcffib.pack_list`.
* `xcb.Request` is gone. It was an entirely internal and unnecessary interface.
* `xcffib.Connection.send_request` takes slightly different (but more sensible)
arguments.
* Everywhere `xcb-proto` says `char`, `xcffib` uses a char. That means on input
for a `
`, you can use a python string literal. `xcffib`
also gives you a string of length 1 out for each element in such a list,
instead of an `int`. Finally, there is a helper method called `to_string` on
`xcffib.List`, to convert these string-like things into native strings. In
both python2 and python3 you get a native `str`. This means that for things
like `xproto.STR`, you can just do `the_str.name.to_string()` instead of
`''.join(map(chr, the_str.name))`.
* As above, `void` is also packed/unpacked as `char`s, since the convention is
to use it as string data, e.g. in `xproto.ChangeProperty`.
* The submodule `xcb` is gone. The top module re-exported all these constants
anyway, so they live there now. i.e. `xcb.xcb.CurrentTime` is now just
`xcffib.CurrentTime`.
## Enhancements
* When sending requests with nested structs you no longer have to pack the
contents yourself. For example, when calling `xproto.FillPoly`, you used to
have to convert the `POINT`s you were passing in to some sort of buffer which
had them `struct.pack`'d. Now, you can just pass an iterable (or
`xcffib.List`) of `POINT`s and it will be automatically packed for you.
* Most of the lower level XCB connection primitives that were previously not
exposed are now available via `xcffib.{ffi,C}`, assuming you want to go out
of band of the binding.
* Checked vs. Unchecked requests are still supported (via Checked and Unchecked
function calls). However, there is also an additional optional parameter
`is_checked` to each request function, to allow you to set the checked status
that way. Additionally, requests that are (un)checked by default, e.g.
`QueryTree` (`CreateWindow`), have a `QueryTreeChecked`
(`CreateWindowUnchecked`) version which just has the same default behavior.
* The `FooError` `BadFoo` duality is gone; it was difficult to understand what
to actually catch if you wanted to handle an error. Instead, `FooError` and
`BadFoo` are aliases, and both implement the X error object description and
python Exception (via inheriting from `XcffibException`).
* You can now create synthtic events. This makes it much easier to work with
`ClientMessageEvent`s. For example:
```python
e = xcffib.xproto.ClientMessageEvent.synthetic(format=..., window=..., ...)
conn.core.SendEvent(..., e.pack())
```
## Why haskell?
Why is the binding generator written in haskell? Because haskell is awesome.
## TODO
* XGE support? (xpyb doesn't implement this either)
* xprint and xkb support. These will require some non-trivial work in
xcb-types, since it won't parse them correctly.
xcffib-0.3.6/debian/ 0000775 0000000 0000000 00000000000 12565733531 0014215 5 ustar 00root root 0000000 0000000 xcffib-0.3.6/debian/changelog 0000664 0000000 0000000 00000001220 12565733531 0016062 0 ustar 00root root 0000000 0000000 xcffib (0.3.6-1) unstable; urgency=medium
* Fix cffi/cairocffi dependency versions
* Use a .so name that exists in the non-dev packages
* Don't have a top level attribute called 'setup' so as to avoid confusing
nose.
* Closes: #796417
-- Tycho Andersen Fri, 21 Aug 2015 23:39:38 +0000
xcffib (0.3.4-1) unstable; urgency=medium
* Version bump for cffi 1.0 and upstream release.
* Closes: #790864
-- Tycho Andersen Mon, 20 Jul 2015 00:28:04 +0000
xcffib (0.2.0-1) unstable; urgency=low
* Initial release.
* Closes: #776178
-- Tycho Andersen Sun, 15 Feb 2015 07:41:13 -0700
xcffib-0.3.6/debian/compat 0000664 0000000 0000000 00000000002 12565733531 0015413 0 ustar 00root root 0000000 0000000 9
xcffib-0.3.6/debian/control 0000664 0000000 0000000 00000004655 12565733531 0015632 0 ustar 00root root 0000000 0000000 Source: xcffib
Section: python
Priority: optional
Maintainer: Tycho Andersen
Build-Depends: debhelper (>= 9)
, dh-python
, pkg-config
, ghc
, xcb-proto
, libxcb-render0-dev
, libxcb1-dev
, cabal-install
, libghc-xcb-types-dev (>= 0.7.0)
, libghc-language-python-dev (>= 0.4.0)
, libghc-split-dev
, libghc-optparse-applicative-dev (>= 0.5)
, libghc-filemanip-dev
, libghc-mtl-dev (>= 2.1)
, libghc-test-framework-hunit-dev
, libghc-attoparsec-dev
, python-setuptools
, python3-setuptools
, python-autopep8
, python-all
, python3-all
, python-all-dev
, python3-all-dev
# testing
, python-nose
, xvfb
, x11-apps
, python-flake8
# Because xcffib imports itself in setup.py to do the cffi extension magic, all
# Depends: are also Build-depends:
, python-six
, python3-six
, python-cffi (>= 1.1.0)
, python3-cffi (>= 1.1.0)
, libxcb1
X-Python-Version: >= 2.6
X-Python3-Version: >= 3.2
Standards-Version: 3.9.6
Homepage: https://github.com/tych0/xcffib
Vcs-Git: https://github.com/tych0/xcffib
Vcs-Browser: https://github.com/tych0/xcffib
Package: python-xcffib
Architecture: any
Depends: python-six
, python-cffi (>= 1.1.0)
, libxcb1
, ${misc:Depends}
, ${shlibs:Depends}
, ${python:Depends}
Provides: ${python:Provides}
Description: This package is a python binding for XCB (Python 2)
This package is intended to be a (mostly) drop-in replacement for xpyb. xpyb
has an inactive upstream, several memory leaks, is python2 only and doesn't
have pypy support. xcffib is a binding which uses python-cffi, which mitigates
some of the issues described above. xcffib also builds bindings for 27 of the
29 (xprint and xkb are missing) X extensions in 1.10.
.
This package installs the library for Python 2.
Package: python3-xcffib
Architecture: any
Depends: python3-six,
, python3-cffi (>= 1.1.0)
, libxcb1
, ${misc:Depends}
, ${shlibs:Depends}
, ${python3:Depends}
Provides: ${python3:Provides}
Description: This package is a python binding for XCB (Python 3)
This package is intended to be a (mostly) drop-in replacement for xpyb. xpyb
has an inactive upstream, several memory leaks, is python2 only and doesn't
have pypy support. xcffib is a binding which uses python-cffi, which mitigates
some of the issues described above. xcffib also builds bindings for 27 of the
29 (xprint and xkb are missing) X extensions in 1.10.
.
This package installs the library for Python 3.
xcffib-0.3.6/debian/copyright 0000664 0000000 0000000 00000004221 12565733531 0016147 0 ustar 00root root 0000000 0000000 Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: xcffib
Source: http://github.com/tych0/xcffib
Files: *
Copyright: 2014-2015 Tycho Andersen
2014-2015 Sean Vig
License: Apache-2.0
Files: debian/*
Copyright: 2014 Tycho Andersen
License: Apache-2.0
Files: tests/test_crazy_window_script.py
Copyright: 2012 Florian Mounier
2014 Sean Vig
2014 Tycho Andersen
License: Expat
License: Expat
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
License: Apache-2.0
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
.
http://www.apache.org/licenses/LICENSE-2.0
.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
.
On Debian systems, the complete text of the Apache License 2.0
can be found in '/usr/share/common-licenses/Apache-2.0'.
xcffib-0.3.6/debian/gbp.conf 0000664 0000000 0000000 00000000044 12565733531 0015632 0 ustar 00root root 0000000 0000000 [DEFAULT]
upstream-tag=v%(version)s
xcffib-0.3.6/debian/license-reconcile.yml 0000664 0000000 0000000 00000000243 12565733531 0020322 0 ustar 00root root 0000000 0000000 Rules:
rules:
-
Glob: debian/*
License: Apache-2.0
Copyright: 2014 Tycho Andersen
-
Glob: tests/test_crazy_window_script.py
License: Expat
xcffib-0.3.6/debian/patches/ 0000775 0000000 0000000 00000000000 12565733531 0015644 5 ustar 00root root 0000000 0000000 xcffib-0.3.6/debian/patches/language-python.patch 0000664 0000000 0000000 00000007621 12565733531 0021775 0 ustar 00root root 0000000 0000000 A patch to be carried until debian updates to langauge-python 0.5.1 or so.
Index: xcffib/xcffib.cabal
===================================================================
--- xcffib.orig/xcffib.cabal
+++ xcffib/xcffib.cabal
@@ -26,7 +26,7 @@ source-repository head
library
build-depends: base ==4.*,
xcb-types >= 0.7.0,
- language-python >= 0.5.0,
+ language-python >= 0.4.0,
filepath,
filemanip,
split,
@@ -44,7 +44,7 @@ executable xcffibgen
hs-source-dirs: generator
build-depends: base ==4.*,
xcffib >= 0.1.0,
- language-python >= 0.5.0,
+ language-python >= 0.4.0,
split,
xcb-types >= 0.7.0,
optparse-applicative >= 0.5,
@@ -63,7 +63,7 @@ test-suite PyHelpersTests
type: exitcode-stdio-1.0
build-depends: base ==4.*,
xcffib >= 0.1.0,
- language-python >= 0.5.0,
+ language-python >= 0.4.0,
HUnit,
test-framework,
test-framework-hunit
@@ -75,7 +75,7 @@ test-suite GeneratorTests.hs
build-depends: base ==4.*,
xcffib >= 0.1.0,
xcb-types >= 0.7.0,
- language-python >= 0.5.0,
+ language-python >= 0.4.0,
HUnit,
test-framework,
test-framework-hunit,
Index: xcffib/generator/Data/XCB/Python/Parse.hs
===================================================================
--- xcffib.orig/generator/Data/XCB/Python/Parse.hs
+++ xcffib/generator/Data/XCB/Python/Parse.hs
@@ -363,7 +363,7 @@ structElemToPyPack _ m accessor (ExprFie
, e
])]
CompositeType _ _ -> Right $ [(name',
- mkCall (mkDot e "pack") noArgs)]
+ mkCall (mkDot e (mkName "pack")) noArgs)]
-- As near as I can tell here the padding param is unused.
structElemToPyPack _ m accessor (ValueParam typ mask _ list) =
Index: xcffib/generator/Data/XCB/Python/PyHelpers.hs
===================================================================
--- xcffib.orig/generator/Data/XCB/Python/PyHelpers.hs
+++ xcffib/generator/Data/XCB/Python/PyHelpers.hs
@@ -83,11 +83,11 @@ mkVar name = Var (ident name) ()
-- | Make an Expr out of a string like "foo.bar" describing the name.
mkName :: String -> Expr ()
mkName s =
- let strings = splitOn "." s
- in foldl mkDot (mkVar $ head strings) (tail strings)
+ let strings = map mkVar $ reverse $ splitOn "." s
+ in foldr mkDot (head strings) (reverse $ tail strings)
-mkDot :: PseudoExpr a => a -> String -> Expr ()
-mkDot e1 attr = Dot (getExpr e1) (ident attr) ()
+mkDot :: (PseudoExpr a, PseudoExpr b) => a -> b -> Expr ()
+mkDot e1 e2 = BinaryOp (Dot ()) (getExpr e1) (getExpr e2) ()
-- | Make an attribute access, i.e. self..
mkAttr :: String -> Expr ()
Index: xcffib/tests/PyHelpersTests.hs
===================================================================
--- xcffib.orig/tests/PyHelpersTests.hs
+++ xcffib/tests/PyHelpersTests.hs
@@ -29,9 +29,13 @@ mkTest name t1 t2 = testCase name (asser
testMkName :: Test
testMkName =
let result = mkName "self.foo.bar"
- expected = (Dot (Dot (Var (Ident "self" ()) ())
- (Ident "foo" ()) ())
- (Ident "bar" ()) ())
+ expected = BinaryOp (Dot ())
+ (Var (Ident "self" ()) ())
+ (BinaryOp (Dot ())
+ (Var (Ident "foo" ()) ())
+ (Var (Ident "bar" ()) ())
+ ())
+ ()
in mkTest "testMkName" expected result
testReserves :: Test
xcffib-0.3.6/debian/patches/series 0000664 0000000 0000000 00000000026 12565733531 0017057 0 ustar 00root root 0000000 0000000 language-python.patch
xcffib-0.3.6/debian/python-xcffib.install 0000664 0000000 0000000 00000000034 12565733531 0020362 0 ustar 00root root 0000000 0000000 debian/tmp/usr/lib/python2*
xcffib-0.3.6/debian/python3-xcffib.install 0000664 0000000 0000000 00000000034 12565733531 0020445 0 ustar 00root root 0000000 0000000 debian/tmp/usr/lib/python3*
xcffib-0.3.6/debian/rules 0000775 0000000 0000000 00000000426 12565733531 0015277 0 ustar 00root root 0000000 0000000 #!/usr/bin/make -f
DEB_ENABLE_TESTS = yes
override_dh_auto_configure:
make xcffib
dh_auto_configure
# we can't use setup.py clean here, since it checks for the existence of xcffib/
override_dh_auto_clean:
make clean
%:
dh $@ --with python2,python3 --buildsystem=pybuild
xcffib-0.3.6/debian/source/ 0000775 0000000 0000000 00000000000 12565733531 0015515 5 ustar 00root root 0000000 0000000 xcffib-0.3.6/debian/source/format 0000664 0000000 0000000 00000000014 12565733531 0016723 0 ustar 00root root 0000000 0000000 3.0 (quilt)
xcffib-0.3.6/debian/watch 0000664 0000000 0000000 00000000212 12565733531 0015241 0 ustar 00root root 0000000 0000000 version=3
opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/xcffib-$1\.tar\.gz/ \
https://github.com/tych0/xcffib/tags .*/v?(\d\S*)\.tar\.gz
xcffib-0.3.6/generator/ 0000775 0000000 0000000 00000000000 12565733531 0014761 5 ustar 00root root 0000000 0000000 xcffib-0.3.6/generator/Data/ 0000775 0000000 0000000 00000000000 12565733531 0015632 5 ustar 00root root 0000000 0000000 xcffib-0.3.6/generator/Data/XCB/ 0000775 0000000 0000000 00000000000 12565733531 0016246 5 ustar 00root root 0000000 0000000 xcffib-0.3.6/generator/Data/XCB/Python/ 0000775 0000000 0000000 00000000000 12565733531 0017527 5 ustar 00root root 0000000 0000000 xcffib-0.3.6/generator/Data/XCB/Python/Parse.hs 0000664 0000000 0000000 00000065400 12565733531 0021142 0 ustar 00root root 0000000 0000000 {-
- Copyright 2014 Tycho Andersen
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-}
{-# LANGUAGE ViewPatterns #-}
module Data.XCB.Python.Parse (
parseXHeaders,
xform,
renderPy,
calcsize
) where
import Control.Applicative hiding (getConst)
import Control.Monad.State.Strict
import Data.Attoparsec.ByteString.Char8
import Data.Bits
import qualified Data.ByteString.Char8 as BS
import Data.Either
import Data.List
import qualified Data.Map as M
import Data.Tree
import Data.Maybe
import Data.XCB.FromXML
import Data.XCB.Types as X
import Data.XCB.Python.PyHelpers
import Language.Python.Common as P
import System.FilePath
import System.FilePath.Glob
import Text.Printf
data TypeInfo =
-- | A "base" X type, i.e. one described in baseTypeInfo; first arg is the
-- struct.unpack string, second is the size.
BaseType String |
-- | A composite type, i.e. a Struct or Union created by XCB. First arg is
-- the extension that defined it, second is the name of the type, third arg
-- is the size if it is known.
CompositeType String String
deriving (Eq, Ord, Show)
type TypeInfoMap = M.Map X.Type TypeInfo
data BindingPart =
Request (Statement ()) (Suite ()) |
Declaration (Suite ()) |
Noop
deriving (Show)
collectBindings :: [BindingPart] -> (Suite (), Suite ())
collectBindings = foldr collectR ([], [])
where
collectR :: BindingPart -> (Suite (), Suite ()) -> (Suite (), Suite ())
collectR (Request def decl) (defs, decls) = (def : defs, decl ++ decls)
collectR (Declaration decl) (defs, decls) = (defs, decl ++ decls)
collectR Noop x = x
parseXHeaders :: FilePath -> IO [XHeader]
parseXHeaders fp = do
files <- namesMatching $ fp > "*.xml"
fromFiles files
renderPy :: Suite () -> String
renderPy s = ((intercalate "\n") $ map prettyText s) ++ "\n"
-- | Generate the code for a set of X headers. Note that the code is generated
-- in dependency order, NOT in the order you pass them in. Thus, you get a
-- string (a suggested filename) along with the python code for that XHeader
-- back.
xform :: [XHeader] -> [(String, Suite ())]
xform = map buildPython . dependencyOrder
where
buildPython :: Tree XHeader -> (String, Suite ())
buildPython forest =
let forest' = (mapM processXHeader $ postOrder forest)
results = evalState forest' baseTypeInfo
in last results
processXHeader :: XHeader
-> State TypeInfoMap (String, Suite ())
processXHeader header = do
let imports = [mkImport "xcffib", mkImport "struct", mkImport "six"]
version = mkVersion header
key = maybeToList $ mkKey header
globals = [mkDict "_events", mkDict "_errors"]
name = xheader_header header
add = [mkAddExt header]
parts <- mapM (processXDecl name) $ xheader_decls header
let (requests, decls) = collectBindings parts
ext = if length requests > 0
then [mkClass (name ++ "Extension") "xcffib.Extension" requests]
else []
return $ (name, concat [imports, version, key, globals, decls, ext, add])
-- Rearrange the headers in dependency order for processing (i.e. put
-- modules which import others after the modules they import, so typedefs
-- are propogated appropriately).
dependencyOrder :: [XHeader] -> Forest XHeader
dependencyOrder headers = unfoldForest unfold $ map xheader_header headers
where
headerM = M.fromList $ map (\h -> (xheader_header h, h)) headers
unfold s = let h = headerM M.! s in (h, deps h)
deps :: XHeader -> [String]
deps = catMaybes . map matchImport . xheader_decls
matchImport :: XDecl -> Maybe String
matchImport (XImport n) = Just n
matchImport _ = Nothing
postOrder :: Tree a -> [a]
postOrder (Node e cs) = (concat $ map postOrder cs) ++ [e]
mkAddExt :: XHeader -> Statement ()
mkAddExt (xheader_header -> "xproto") =
flip StmtExpr () $ mkCall "xcffib._add_core" [ mkName "xprotoExtension"
, mkName "Setup"
, mkName "_events"
, mkName "_errors"
]
mkAddExt header =
let name = xheader_header header
in flip StmtExpr () $ mkCall "xcffib._add_ext" [ mkName "key"
, mkName (name ++ "Extension")
, mkName "_events"
, mkName "_errors"
]
-- | Information on basic X types.
baseTypeInfo :: TypeInfoMap
baseTypeInfo = M.fromList $
[ (UnQualType "CARD8", BaseType "B")
, (UnQualType "uint8_t", BaseType "B")
, (UnQualType "CARD16", BaseType "H")
, (UnQualType "uint16_t", BaseType "H")
, (UnQualType "CARD32", BaseType "I")
, (UnQualType "uint32_t", BaseType "I")
, (UnQualType "CARD64", BaseType "Q")
, (UnQualType "uint64_t", BaseType "Q")
, (UnQualType "INT8", BaseType "b")
, (UnQualType "int8_t", BaseType "b")
, (UnQualType "INT16", BaseType "h")
, (UnQualType "int16_t", BaseType "h")
, (UnQualType "INT32", BaseType "i")
, (UnQualType "int32_t", BaseType "i")
, (UnQualType "INT64", BaseType "q")
, (UnQualType "uint64_t", BaseType "q")
, (UnQualType "BYTE", BaseType "B")
, (UnQualType "BOOL", BaseType "B")
, (UnQualType "char", BaseType "c")
, (UnQualType "void", BaseType "c")
, (UnQualType "float", BaseType "f")
, (UnQualType "double", BaseType "d")
]
-- | Clone of python's struct.calcsize.
calcsize :: String -> Int
calcsize str = sum [fromMaybe 1 i * getSize c | (i, c) <- parseMembers str]
where
sizeM :: M.Map Char Int
sizeM = M.fromList [ ('c', 1)
, ('B', 1)
, ('b', 1)
, ('H', 2)
, ('h', 2)
, ('I', 4)
, ('i', 4)
, ('Q', 8)
, ('q', 8)
, ('f', 4)
, ('d', 8)
, ('x', 1)
]
getSize = (M.!) sizeM
parseMembers :: String -> [(Maybe Int, Char)]
parseMembers s = case parseOnly lang (BS.pack s) of
Left err -> error ("can't calcsize " ++ s ++ " " ++ err)
Right xs -> xs
lang = many $ (,) <$> optional decimal <*> (satisfy $ inClass $ M.keys sizeM)
xBinopToPyOp :: X.Binop -> P.Op ()
xBinopToPyOp X.Add = P.Plus ()
xBinopToPyOp X.Sub = P.Minus ()
xBinopToPyOp X.Mult = P.Multiply ()
xBinopToPyOp X.Div = P.FloorDivide ()
xBinopToPyOp X.And = P.BinaryAnd ()
xBinopToPyOp X.RShift = P.ShiftRight ()
xUnopToPyOp :: X.Unop -> P.Op ()
xUnopToPyOp X.Complement = P.Invert ()
xExpressionToNestedPyExpr :: (String -> String) -> XExpression -> Expr ()
xExpressionToNestedPyExpr acc (Op o e1 e2) =
Paren (xExpressionToPyExpr acc (Op o e1 e2)) ()
xExpressionToNestedPyExpr acc xexpr =
xExpressionToPyExpr acc xexpr
xExpressionToPyExpr :: (String -> String) -> XExpression -> Expr ()
xExpressionToPyExpr _ (Value i) = mkInt i
xExpressionToPyExpr _ (Bit i) = BinaryOp (ShiftLeft ()) (mkInt 1) (mkInt i) ()
xExpressionToPyExpr acc (FieldRef n) = mkName $ acc n
xExpressionToPyExpr _ (EnumRef _ n) = mkName n
xExpressionToPyExpr acc (PopCount e) =
mkCall "xcffib.popcount" [xExpressionToPyExpr acc e]
-- http://cgit.freedesktop.org/xcb/proto/tree/doc/xml-xcb.txt#n290
xExpressionToPyExpr acc (SumOf n) = mkCall "sum" [mkName $ acc n]
xExpressionToPyExpr acc (Op o e1 e2) =
let o' = xBinopToPyOp o
e1' = xExpressionToNestedPyExpr acc e1
e2' = xExpressionToNestedPyExpr acc e2
in BinaryOp o' e1' e2' ()
xExpressionToPyExpr acc (Unop o e) =
let o' = xUnopToPyOp o
e' = xExpressionToNestedPyExpr acc e
in Paren (UnaryOp o' e' ()) ()
getConst :: XExpression -> Maybe Int
getConst (Value i) = Just i
getConst (Bit i) = Just $ bit i
getConst (Op o e1 e2) = do
c1 <- getConst e1
c2 <- getConst e2
return $ case o of
X.Add -> c1 + c2
X.Sub -> c1 - c2
X.Mult -> c1 * c2
X.Div -> c1 `quot` c2
X.And -> c1 .&. c2
X.RShift -> c1 `shift` c2
getConst (Unop o e) = do
c <- getConst e
return $ case o of
X.Complement -> complement c
getConst (PopCount e) = fmap popCount $ getConst e
getConst _ = Nothing
xEnumElemsToPyEnum :: (String -> String) -> [XEnumElem] -> [(String, Expr ())]
xEnumElemsToPyEnum accessor membs = reverse $ conv membs [] [0..]
where
exprConv = xExpressionToPyExpr accessor
conv :: [XEnumElem] -> [(String, Expr ())] -> [Int] -> [(String, Expr ())]
conv ((EnumElem name expr) : els) acc is =
let expr' = fromMaybe (mkInt (head is)) $ fmap exprConv expr
is' = dropWhile (<= (fromIntegral (int_value expr'))) is
acc' = (name, expr') : acc
in conv els acc' is'
conv [] acc _ = acc
-- Add the xcb_generic_{request,reply}_t structure data to the beginning of a
-- pack string. This is a little weird because both structs contain a one byte
-- pad which isn't at the end. If the first element of the request or reply is
-- a byte long, it takes that spot instead, and there is one less offset
addStructData :: String -> String -> String
addStructData prefix (c : cs) | c `elem` "Bbx" =
let result = maybePrintChar prefix c
in if result == prefix then result ++ (c : cs) else result ++ cs
addStructData prefix s = (maybePrintChar prefix 'x') ++ s
maybePrintChar :: String -> Char -> String
maybePrintChar s c | "%c" `isInfixOf` s = printf s c
maybePrintChar s _ = s
-- Don't prefix a single pad byte with a '1'. This is simpler to parse
-- visually, and also simplifies addStructData above.
mkPad :: Int -> String
mkPad 1 = "x"
mkPad i = (show i) ++ "x"
structElemToPyUnpack :: Expr ()
-> String
-> TypeInfoMap
-> GenStructElem Type
-> Either (Maybe String, String)
(String, Expr (), Expr (), Maybe Int)
structElemToPyUnpack _ _ _ (Pad i) = Left (Nothing, mkPad i)
-- XXX: This is a cheap hack for noop, we should really do better.
structElemToPyUnpack _ _ _ (Doc _ _ _) = Left (Nothing, "")
-- XXX: What does fd/switch mean? we should implement it correctly
structElemToPyUnpack _ _ _ (Fd _) = Left (Nothing, "")
structElemToPyUnpack _ _ _ (Switch _ _ _) = Left (Nothing, "")
-- The enum field is mostly for user information, so we ignore it.
structElemToPyUnpack unpacker ext m (X.List n typ len _) =
let attr = ((++) "self.")
len' = fromMaybe pyNone $ fmap (xExpressionToPyExpr attr) len
cons = case m M.! typ of
BaseType c -> mkStr c
CompositeType tExt c | ext /= tExt -> mkName $ tExt ++ "." ++ c
CompositeType _ c -> mkName c
list = mkCall "xcffib.List" [ unpacker
, cons
, len'
]
constLen = do
l <- len
getConst l
in Right (n, list, cons, constLen)
-- The mask and enum fields are for user information, we can ignore them here.
structElemToPyUnpack unpacker ext m (SField n typ _ _) =
case m M.! typ of
BaseType c -> Left (Just n, c)
CompositeType tExt c ->
let c' = if tExt == ext then c else tExt ++ "." ++ c
field = mkCall c' [unpacker]
-- TODO: Ugh. Nothing here is wrong. Do we really need to carry the
-- length of these things around?
in Right (n, field, mkName c', Nothing)
structElemToPyUnpack _ _ _ (ExprField _ _ _) = error "Only valid for requests"
structElemToPyUnpack _ _ _ (ValueParam _ _ _ _) = error "Only valid for requests"
structElemToPyPack :: String
-> TypeInfoMap
-> (String -> String)
-> GenStructElem Type
-> Either (Maybe String, String) [(String, Expr ())]
structElemToPyPack _ _ _ (Pad i) = Left (Nothing, mkPad i)
-- TODO: implement doc, switch, and fd?
structElemToPyPack _ _ _ (Doc _ _ _) = Left (Nothing, "")
structElemToPyPack _ _ _ (Switch _ _ _) = Left (Nothing, "")
structElemToPyPack _ _ _ (Fd _) = Left (Nothing, "")
structElemToPyPack _ m accessor (SField n typ _ _) =
let name = accessor n
in case m M.! typ of
BaseType c -> Left (Just name, c)
-- XXX: be a little smarter here? we should really make sure that things
-- have a .pack(); if users are calling us via the old style api, we need
-- to support that as well. This isn't super necessary, though, because
-- currently (xcb-proto 1.10) there are no direct packs of raw structs, so
-- this is really only necessary if xpyb gets forward ported in the future if
-- there are actually calls of this type.
CompositeType _ _ -> Right $ [(name, mkCall (name ++ ".pack") noArgs)]
-- TODO: assert values are in enum?
structElemToPyPack ext m accessor (X.List n typ _ _) =
let name = accessor n
in case m M.! typ of
BaseType c -> Right $ [(name, mkCall "xcffib.pack_list" [ mkName $ name
, mkStr c
])]
CompositeType tExt c ->
let c' = if tExt == ext then c else (tExt ++ "." ++ c)
in Right $ [(name, mkCall "xcffib.pack_list" ([ mkName $ name
, mkName c'
]))]
structElemToPyPack _ m accessor (ExprField name typ expr) =
let e = (xExpressionToPyExpr accessor) expr
name' = accessor name
in case m M.! typ of
BaseType c -> Right $ [(name', mkCall "struct.pack" [ mkStr ('=' : c)
, e
])]
CompositeType _ _ -> Right $ [(name',
mkCall (mkDot e "pack") noArgs)]
-- As near as I can tell here the padding param is unused.
structElemToPyPack _ m accessor (ValueParam typ mask _ list) =
case m M.! typ of
BaseType c ->
let mask' = mkCall "struct.pack" [mkStr ('=' : c), mkName $ accessor mask]
list' = mkCall "xcffib.pack_list" [ mkName $ accessor list
, mkStr "I"
]
in Right $ [(mask, mask'), (list, list')]
CompositeType _ _ -> error (
"ValueParams other than CARD{16,32} not allowed.")
buf :: Suite ()
buf = [mkAssign "buf" (mkCall "six.BytesIO" noArgs)]
mkPackStmts :: String
-> String
-> TypeInfoMap
-> (String -> String)
-> String
-> [GenStructElem Type]
-> ([String], Suite ())
mkPackStmts ext name m accessor prefix membs =
let packF = structElemToPyPack ext m accessor
(toPack, stmts) = partitionEithers $ map packF membs
listWrites = map (flip StmtExpr () . mkCall "buf.write" . (: [])) lists
(args, keys) = let (as, ks) = unzip toPack in (catMaybes as, ks)
-- In some cases (e.g. xproto.ConfigureWindow) there is padding after
-- value_mask. The way the xml specification deals with this is by
-- specifying value_mask in both the regular pack location as well as
-- implying it implicitly. Thus, we want to make sure that if we've already
-- been told to pack something explcitly, that we don't also pack it
-- implicitly.
(listNames, lists) = unzip $ filter (flip notElem args . fst) (concat stmts)
listNames' = case (ext, name) of
-- XXX: QueryTextExtents has a field named "odd_length" with a
-- fieldref of "string_len", so we fix it up here to match.
("xproto", "QueryTextExtents") ->
let replacer "odd_length" = "string_len"
replacer s = s
in map replacer listNames
_ -> listNames
packStr = addStructData prefix $ intercalate "" keys
write = mkCall "buf.write" [mkCall "struct.pack"
(mkStr ('=' : packStr) : (map mkName args))]
writeStmt = if length packStr > 0 then [StmtExpr write ()] else []
in (args ++ listNames', writeStmt ++ listWrites)
mkPackMethod :: String
-> String
-> TypeInfoMap
-> Maybe (String, Int)
-> [GenStructElem Type]
-> Maybe Int
-> Statement ()
mkPackMethod ext name m prefixAndOp structElems minLen =
let accessor = ((++) "self.")
(prefix, op) = case prefixAndOp of
Just ('x' : rest, i) ->
let packOpcode = mkCall "struct.pack" [mkStr "=B", mkInt i]
write = mkCall "buf.write" [packOpcode]
in (rest, [StmtExpr write ()])
Just (rest, _) -> error ("internal API error: " ++ show rest)
Nothing -> ("", [])
(_, packStmts) = mkPackStmts ext name m accessor prefix structElems
extend = concat $ do
len <- maybeToList minLen
let bufLen = mkName "buf_len"
bufLenAssign = mkAssign bufLen $ mkCall "len" [mkCall "buf.getvalue" noArgs]
test = (BinaryOp (LessThan ()) bufLen (mkInt len)) ()
bufWriteLen = Paren (BinaryOp (Minus ()) (mkInt 32) bufLen ()) ()
extra = mkCall "struct.pack" [repeatStr "x" bufWriteLen]
writeExtra = [StmtExpr (mkCall "buf.write" [extra]) ()]
return $ [bufLenAssign, mkIf test writeExtra]
ret = [mkReturn $ mkCall "buf.getvalue" noArgs]
in mkMethod "pack" (mkParams ["self"]) $ buf ++ op ++ packStmts ++ extend ++ ret
data StructUnpackState = StructUnpackState {
-- | stNeedsPad is whether or not a type_pad() is needed. As near
-- as I can tell the conditions are:
-- 1. a list was unpacked
-- 2. a struct was unpacked
-- ListFontsWithInfoReply is an example of a struct which has lots of
-- this type of thing.
stNeedsPad :: Bool,
-- The list of names the struct.pack accumulator has, and the
stNames :: [String],
-- The list of pack directives (potentially with a "%c" in it for
-- the prefix byte).
stPacks :: String
}
-- | Make a struct style (i.e. not union style) unpack.
mkStructStyleUnpack :: String
-> String
-> TypeInfoMap
-> [GenStructElem Type]
-> (Suite (), Maybe Int)
mkStructStyleUnpack prefix ext m membs =
let unpacked = map (structElemToPyUnpack (mkName "unpacker") ext m) membs
initial = StructUnpackState False [] prefix
(_, unpackStmts, size) = evalState (mkUnpackStmtsR unpacked) initial
base = [mkAssign "base" $ mkName "unpacker.offset"]
bufsize =
let rhs = BinaryOp (Minus ()) (mkName "unpacker.offset") (mkName "base") ()
in [mkAssign (mkAttr "bufsize") rhs]
statements = base ++ unpackStmts ++ bufsize
in (statements, size)
where
-- Apparently you only type_pad before unpacking Structs or Lists, never
-- base types.
mkUnpackStmtsR :: [Either (Maybe String, String)
(String, Expr (), Expr (), Maybe Int)]
-> State StructUnpackState ([String], Suite (), Maybe Int)
mkUnpackStmtsR [] = flushAcc
mkUnpackStmtsR (Left (name, pack) : xs) = do
st <- get
let packs = if "%c" `isInfixOf` (stPacks st)
then addStructData (stPacks st) pack
else (stPacks st) ++ pack
put $ st { stNames = stNames st ++ maybeToList name
, stPacks = packs
}
mkUnpackStmtsR xs
mkUnpackStmtsR (Right (listName, list, cons, listSz) : xs) = do
(packNames, packStmt, packSz) <- flushAcc
st <- get
put $ st { stNeedsPad = True }
let pad = if stNeedsPad st
then [typePad cons]
else []
(restNames, restStmts, restSz) <- mkUnpackStmtsR xs
let totalSize = do
before <- packSz
rest <- restSz
listSz' <- listSz
return $ before + rest + listSz'
listStmt = mkAssign (mkAttr listName) list
return ( packNames ++ [listName] ++ restNames
, packStmt ++ pad ++ listStmt : restStmts
, totalSize
)
flushAcc :: State StructUnpackState ([String], Suite (), Maybe Int)
flushAcc = do
StructUnpackState needsPad args keys <- get
let size = calcsize keys
assign = mkUnpackFrom "unpacker" args keys
put $ StructUnpackState needsPad [] ""
return (args, assign, Just size)
typePad e = StmtExpr (mkCall "unpacker.pad" [e]) ()
-- | Given a (qualified) type name and a target type, generate a TypeInfoMap
-- updater.
mkModify :: String -> String -> TypeInfo -> TypeInfoMap -> TypeInfoMap
mkModify ext name ti m =
let m' = M.fromList [ (UnQualType name, ti)
, (QualType ext name, ti)
]
in M.union m m'
processXDecl :: String
-> XDecl
-> State TypeInfoMap BindingPart
processXDecl ext (XTypeDef name typ) =
do modify $ \m -> mkModify ext name (m M.! typ) m
return Noop
processXDecl ext (XidType name) =
-- http://www.markwitmer.com/guile-xcb/doc/guile-xcb/XIDs.html
do modify $ mkModify ext name (BaseType "I")
return Noop
processXDecl _ (XImport n) =
return $ Declaration [ mkRelImport n]
processXDecl _ (XEnum name membs) =
return $ Declaration [mkEnum name $ xEnumElemsToPyEnum id membs]
processXDecl ext (XStruct n membs) = do
m <- get
let (statements, len) = mkStructStyleUnpack "" ext m membs
pack = mkPackMethod ext n m Nothing membs Nothing
fixedLength = maybeToList $ do
theLen <- len
let rhs = mkInt theLen
return $ mkAssign "fixed_size" rhs
modify $ mkModify ext n (CompositeType ext n)
return $ Declaration [mkXClass n "xcffib.Struct" statements (pack : fixedLength)]
processXDecl ext (XEvent name opcode membs noSequence) = do
m <- get
let cname = name ++ "Event"
prefix = if fromMaybe False noSequence then "x" else "x%c2x"
pack = mkPackMethod ext name m (Just (prefix, opcode)) membs (Just 32)
(statements, _) = mkStructStyleUnpack prefix ext m membs
eventsUpd = mkDictUpdate "_events" opcode cname
return $ Declaration [ mkXClass cname "xcffib.Event" statements [pack]
, eventsUpd
]
processXDecl ext (XError name opcode membs) = do
m <- get
let cname = name ++ "Error"
prefix = "xx2x"
pack = mkPackMethod ext name m (Just (prefix, opcode)) membs Nothing
(statements, _) = mkStructStyleUnpack prefix ext m membs
errorsUpd = mkDictUpdate "_errors" opcode cname
alias = mkAssign ("Bad" ++ name) (mkName cname)
return $ Declaration [ mkXClass cname "xcffib.Error" statements [pack]
, alias
, errorsUpd
]
processXDecl ext (XRequest name opcode membs reply) = do
m <- get
let
-- xtest doesn't seem to use the same packing strategy as everyone else,
-- but there is no clear indication in the XML as to why that is. yay.
prefix = if ext == "xtest" then "xx2x" else "x%c2x"
(args, packStmts) = mkPackStmts ext name m id prefix membs
cookieName = (name ++ "Cookie")
replyDecl = concat $ maybeToList $ do
reply' <- reply
let (replyStmts, _) = mkStructStyleUnpack "x%c2x4x" ext m reply'
replyName = name ++ "Reply"
theReply = mkXClass replyName "xcffib.Reply" replyStmts []
replyType = mkAssign "reply_type" $ mkName replyName
cookie = mkClass cookieName "xcffib.Cookie" [replyType]
return [theReply, cookie]
hasReply = if length replyDecl > 0
then [ArgExpr (mkName cookieName) ()]
else []
isChecked = pyTruth $ isJust reply
argChecked = ArgKeyword (ident "is_checked") (mkName "is_checked") ()
checkedParam = Param (ident "is_checked") Nothing (Just isChecked) ()
allArgs = (mkParams $ "self" : args) ++ [checkedParam]
mkArg = flip ArgExpr ()
ret = mkReturn $ mkCall "self.send_request" ((map mkArg [ mkInt opcode
, mkName "buf"
])
++ hasReply
++ [argChecked])
requestBody = buf ++ packStmts ++ [ret]
request = mkMethod name allArgs requestBody
return $ Request request replyDecl
processXDecl ext (XUnion name membs) = do
m <- get
let unpackF = structElemToPyUnpack unpackerCopy ext m
(fields, listInfo) = partitionEithers $ map unpackF membs
toUnpack = concat $ map mkUnionUnpack fields
(names, exprs, _, _) = unzip4 listInfo
lists = map (uncurry mkAssign) $ zip (map mkAttr names) exprs
initMethod = lists ++ toUnpack
-- Here, we only want to pack the first member of the union, since every
-- member is the same data and we don't want to repeatedly pack it.
pack = mkPackMethod ext name m Nothing [head membs] Nothing
decl = [mkXClass name "xcffib.Union" initMethod [pack]]
modify $ mkModify ext name (CompositeType ext name)
return $ Declaration decl
where
unpackerCopy = mkCall "unpacker.copy" noArgs
mkUnionUnpack :: (Maybe String, String)
-> Suite ()
mkUnionUnpack (n, typ) =
mkUnpackFrom unpackerCopy (maybeToList n) typ
processXDecl ext (XidUnion name _) =
-- These are always unions of only XIDs.
do modify $ mkModify ext name (BaseType "I")
return Noop
mkVersion :: XHeader -> Suite ()
mkVersion header =
let major = ver "MAJOR_VERSION" (xheader_major_version header)
minor = ver "MINOR_VERSION" (xheader_minor_version header)
in major ++ minor
where
ver :: String -> Maybe Int -> Suite ()
ver target i = maybeToList $ fmap (\x -> mkAssign target (mkInt x)) i
mkKey :: XHeader -> Maybe (Statement ())
mkKey header = do
name <- xheader_xname header
let call = mkCall "xcffib.ExtensionKey" [mkStr name]
return $ mkAssign "key" call
xcffib-0.3.6/generator/Data/XCB/Python/PyHelpers.hs 0000664 0000000 0000000 00000014052 12565733531 0022000 0 ustar 00root root 0000000 0000000 {-
- Copyright 2014 Tycho Andersen
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-}
{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
module Data.XCB.Python.PyHelpers (
mkImport,
mkRelImport,
mkInt,
mkAssign,
mkCall,
noArgs,
mkEnum,
mkName,
mkDot,
mkAttr,
mkIncr,
mkClass,
mkEmptyClass,
mkXClass,
mkStr,
mkUnpackFrom,
mkDict,
mkDictUpdate,
mkMethod,
mkReturn,
pyTruth,
mkParams,
ident,
pyNone,
mkIf,
repeatStr
) where
import Data.List.Split
import Data.Maybe
import Language.Python.Common
_reserved :: [String]
_reserved = [ "None"
, "def"
, "class"
, "and"
, "or"
]
class PseudoExpr a where
getExpr :: a -> Expr ()
instance PseudoExpr String where
getExpr s = mkName s
instance PseudoExpr (Expr ()) where
getExpr = id
-- | Create and sanatize a python identifier.
ident :: String -> Ident ()
ident s | s `elem` _reserved = Ident ("_" ++ s) ()
ident s | isInt s = Ident ("_" ++ s) ()
where
isInt str = isJust $ ((maybeRead str) :: Maybe Int)
maybeRead = fmap fst . listToMaybe . reads
ident s = Ident s ()
-- Make a DottedName out of a string like "foo.bar" for use in imports.
mkDottedName :: String -> DottedName ()
mkDottedName = map ident . splitOn "."
mkVar :: String -> Expr ()
mkVar name = Var (ident name) ()
-- | Make an Expr out of a string like "foo.bar" describing the name.
mkName :: String -> Expr ()
mkName s =
let strings = splitOn "." s
in foldl mkDot (mkVar $ head strings) (tail strings)
mkDot :: PseudoExpr a => a -> String -> Expr ()
mkDot e1 attr = Dot (getExpr e1) (ident attr) ()
-- | Make an attribute access, i.e. self..
mkAttr :: String -> Expr ()
mkAttr s = mkName ("self." ++ s)
mkImport :: String -> Statement ()
mkImport name = Import [ImportItem (mkDottedName name) Nothing ()] ()
mkRelImport :: String -> Statement ()
mkRelImport name = FromImport (ImportRelative 1 Nothing ()) (FromItems [FromItem (ident name) Nothing ()] ()) ()
mkInt :: Int -> Expr ()
mkInt i = Int (toInteger i) (show i) ()
mkAssign :: PseudoExpr a => a -> Expr () -> Statement ()
mkAssign name expr = Assign [getExpr name] expr ()
mkIncr :: String -> Expr () -> Statement ()
mkIncr name expr = AugmentedAssign (mkName name) (PlusAssign ()) expr ()
class PseudoArgument a where
getArgument :: a -> Argument ()
instance PseudoArgument (Expr ()) where
getArgument p = ArgExpr p ()
instance PseudoArgument (Argument ()) where
getArgument = id
mkCall :: (PseudoExpr a, PseudoArgument b) => a -> [b] -> Expr ()
mkCall name args = Call (getExpr name) (map getArgument args) ()
noArgs :: [Argument ()]
noArgs = []
mkEnum :: String -> [(String, Expr ())] -> Statement ()
mkEnum cname values =
let body = map (uncurry mkAssign) values
in Class (Ident cname ()) [] body ()
mkParams :: [String] -> [Parameter ()]
mkParams = map (\x -> Param (ident x) Nothing Nothing ())
mkArg :: String -> Argument ()
mkArg n = ArgExpr (mkName n) ()
mkXClass :: String -> String -> Suite () -> Suite () -> Statement ()
mkXClass clazz superclazz [] [] = mkEmptyClass clazz superclazz
mkXClass clazz superclazz constructor methods =
let args = [ "self", "unpacker" ]
super = mkCall (superclazz ++ ".__init__") $ map mkName args
body = eventToUnpacker : (StmtExpr super ()) : constructor
initParams = mkParams args
initMethod = Fun (ident "__init__") initParams Nothing body ()
in mkClass clazz superclazz $ initMethod : methods
where
-- In some cases (e.g. when creating ClientMessageEvents), our events are
-- passed directly to __init__. Since we don't keep track of the
-- underlying buffers after the event is created, we have to re-pack
-- things so they can be unpacked again.
eventToUnpacker :: Statement ()
eventToUnpacker = let newUnpacker = mkAssign "unpacker" (mkCall "xcffib.MemoryUnpacker"
[mkCall "unpacker.pack" noArgs])
cond = mkCall "isinstance" [mkName "unpacker", mkName "xcffib.Protobj"]
in mkIf cond [newUnpacker]
mkEmptyClass :: String -> String -> Statement ()
mkEmptyClass clazz superclazz = mkClass clazz superclazz [Pass ()]
mkClass :: String -> String -> Suite () -> Statement ()
mkClass clazz superclazz body = Class (ident clazz) [mkArg superclazz] body ()
mkStr :: String -> Expr ()
mkStr s = Strings ["\"", s, "\""] ()
mkTuple :: [Expr ()] -> Expr ()
mkTuple = flip Tuple ()
mkUnpackFrom :: PseudoExpr a => a -> [String] -> String -> Suite ()
mkUnpackFrom unpacker names packs =
let lhs = mkTuple $ map mkAttr names
-- Don't spam with this default arg unless it is really necessary.
unpackF = mkDot unpacker "unpack"
rhs = mkCall unpackF [mkStr packs]
stmt = if length names > 0 then mkAssign lhs rhs else StmtExpr rhs ()
in if length packs > 0 then [stmt] else []
mkDict :: String -> Statement ()
mkDict name = mkAssign name (Dictionary [] ())
mkDictUpdate :: String -> Int -> String -> Statement ()
mkDictUpdate dict key value =
mkAssign (Subscript (mkName dict) (mkInt key) ()) (mkName value)
mkMethod :: String -> [Parameter ()] -> Suite () -> Statement ()
mkMethod name args body = Fun (ident name) args Nothing body ()
mkReturn :: Expr () -> Statement ()
mkReturn = flip Return () . Just
pyTruth :: Bool -> Expr ()
pyTruth = flip Bool ()
pyNone :: Expr ()
pyNone = None ()
mkIf :: Expr () -> Suite () -> Statement ()
mkIf e s = Conditional [(e, s)] [] ()
repeatStr :: String -> Expr () -> Expr ()
repeatStr s i = BinaryOp (Multiply ()) (mkStr s) i ()
xcffib-0.3.6/generator/xcffibgen.hs 0000664 0000000 0000000 00000003647 12565733531 0017262 0 ustar 00root root 0000000 0000000 {-
- Copyright 2014 Tycho Andersen
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-}
module Main where
import Data.XCB.Types
import Data.XCB.Python.Parse
import Options.Applicative
import System.Directory
import System.FilePath
data Xcffibgen = Xcffibgen { input :: String
, output :: String
}
options :: Parser Xcffibgen
options = Xcffibgen
<$> strOption
( long "input"
<> metavar "DIR"
<> help "Input directory containing xcb xml files.")
<*> strOption
( long "output"
<> metavar "DIR"
<> help "Output directory for generated python.")
-- Headers we can't emit right now. Obviously we want to get rid of this :-)
badHeaders :: [String]
badHeaders = [ "xkb"
, "xprint"
]
run :: Xcffibgen -> IO ()
run (Xcffibgen inp out) = do
headers <- parseXHeaders inp
let headers' = filter (flip notElem badHeaders . xheader_header) headers
createDirectoryIfMissing True out
sequence_ $ map processFile $ xform headers'
where
processFile (fname, suite) = do
putStrLn fname
let fname' = out > fname ++ ".py"
contents = renderPy suite
writeFile fname' contents
main :: IO ()
main = execParser opts >>= run
where
opts = info (helper <*> options)
( fullDesc
<> progDesc "Generate XCB bindings for python."
<> header "xcffib - the cffi-based XCB generator")
xcffib-0.3.6/module/ 0000775 0000000 0000000 00000000000 12565733531 0014260 5 ustar 00root root 0000000 0000000 xcffib-0.3.6/module/__init__.py 0000664 0000000 0000000 00000056045 12565733531 0016403 0 ustar 00root root 0000000 0000000 # Copyright 2014 Tycho Andersen
# Copyright 2014 Sean Vig
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import division, absolute_import
import functools
import six
import struct
import weakref
try:
from xcffib._ffi import ffi
except ImportError:
from xcffib.ffi_build import ffi
lib = ffi.dlopen('libxcb.so.1')
__xcb_proto_version__ = 'placeholder'
X_PROTOCOL = lib.X_PROTOCOL
X_PROTOCOL_REVISION = lib.X_PROTOCOL_REVISION
XCB_NONE = lib.XCB_NONE
XCB_COPY_FROM_PARENT = lib.XCB_COPY_FROM_PARENT
XCB_CURRENT_TIME = lib.XCB_CURRENT_TIME
XCB_NO_SYMBOL = lib.XCB_NO_SYMBOL
# For xpyb compatibility
NONE = XCB_NONE
CopyFromParent = XCB_COPY_FROM_PARENT
CurrentTime = XCB_CURRENT_TIME
NoSymbol = XCB_NO_SYMBOL
XCB_CONN_ERROR = lib.XCB_CONN_ERROR
XCB_CONN_CLOSED_EXT_NOTSUPPORTED = lib.XCB_CONN_CLOSED_EXT_NOTSUPPORTED
XCB_CONN_CLOSED_MEM_INSUFFICIENT = lib.XCB_CONN_CLOSED_MEM_INSUFFICIENT
XCB_CONN_CLOSED_REQ_LEN_EXCEED = lib.XCB_CONN_CLOSED_REQ_LEN_EXCEED
XCB_CONN_CLOSED_PARSE_ERR = lib.XCB_CONN_CLOSED_PARSE_ERR
# XCB_CONN_CLOSED_INVALID_SCREEN = lib.XCB_CONN_CLOSED_INVALID_SCREEN
# XCB_CONN_CLOSED_FDPASSING_FAILED = lib.XCB_CONN_CLOSED_FDPASSING_FAILED
cffi_explicit_lifetimes = weakref.WeakKeyDictionary()
def type_pad(t, i):
return -i & (3 if t > 4 else t - 1)
def visualtype_to_c_struct(vt):
# let ffi be a kwarg so cairocffi can pass in its ffi
# cfficairo needs an xcb_visualtype_t
s = ffi.new("struct xcb_visualtype_t *")
s.visual_id = vt.visual_id
s._class = vt._class
s.bits_per_rgb_value = vt.bits_per_rgb_value
s.colormap_entries = vt.colormap_entries
s.red_mask = vt.red_mask
s.green_mask = vt.green_mask
s.blue_mask = vt.blue_mask
return s
class Unpacker(object):
def __init__(self, known_max=None):
self.size = 0
self.offset = 0
self.known_max = known_max
if self.known_max is not None:
self._resize(known_max)
def pad(self, thing):
if isinstance(thing, type) and any(
[issubclass(thing, c) for c in [Struct, Union]]):
if hasattr(thing, "fixed_size"):
size = thing.fixed_size
else:
size = 4
else:
size = struct.calcsize(thing)
self.offset += type_pad(size, self.offset)
def unpack(self, fmt, increment=True):
size = struct.calcsize(fmt)
if size > self.size - self.offset:
self._resize(size)
ret = struct.unpack_from("=" + fmt, self.buf, self.offset)
if increment:
self.offset += size
return ret
def cast(self, typ):
assert self.offset == 0
return ffi.cast(typ, self.cdata)
def copy(self):
raise NotImplementedError
@classmethod
def synthetic(cls, data, format):
self = cls.__new__(cls)
self.buf = data
self.offset = 0
self.size = len(data)
self.size
class CffiUnpacker(Unpacker):
def __init__(self, cdata, known_max=None):
self.cdata = cdata
Unpacker.__init__(self, known_max)
def _resize(self, increment):
if self.offset + increment > self.size:
if self.known_max is not None:
assert self.size + increment <= self.known_max
self.size = self.offset + increment
self.buf = ffi.buffer(self.cdata, self.size)
def copy(self):
new = CffiUnpacker(self.cdata, self.known_max)
new.offset = self.offset
new.size = self.size
return new
class MemoryUnpacker(Unpacker):
def __init__(self, buf):
self.buf = buf
Unpacker.__init__(self, len(self.buf))
def _resize(self, increment):
if self.size + increment > self.known_max:
raise XcffibException("resizing memory buffer to be too big")
self.size += increment
def copy(self):
new = MemoryUnpacker(self.buf)
new.offset = self.offset
new.size = self.size
return new
def popcount(n):
return bin(n).count('1')
class XcffibException(Exception):
""" Generic XcbException; replaces xcb.Exception. """
pass
class ConnectionException(XcffibException):
REASONS = {
lib.XCB_CONN_ERROR: (
'xcb connection errors because of socket, '
'pipe and other stream errors.'),
lib.XCB_CONN_CLOSED_EXT_NOTSUPPORTED: (
'xcb connection shutdown because extension not supported'),
lib.XCB_CONN_CLOSED_MEM_INSUFFICIENT: (
'malloc(), calloc() and realloc() error upon failure, '
'for eg ENOMEM'),
lib.XCB_CONN_CLOSED_REQ_LEN_EXCEED: (
'Connection closed, exceeding request length that server '
'accepts.'),
lib.XCB_CONN_CLOSED_PARSE_ERR: (
'Connection closed, error during parsing display string.'),
# lib.XCB_CONN_CLOSED_INVALID_SCREEN: (
# 'Connection closed because the server does not have a screen '
# 'matching the display.'),
# lib.XCB_CONN_CLOSED_FDPASSING_FAILED: (
# 'Connection closed because some FD passing operation failed'),
}
def __init__(self, err):
XcffibException.__init__(
self, self.REASONS.get(err, "Unknown connection error."))
class ProtocolException(XcffibException):
pass
core = None
core_events = None
core_errors = None
# we use _setup here instead of just setup because of a nose bug that triggers
# when doing the packaging builds in debian:
# https://code.google.com/p/python-nose/issues/detail?id=326
_setup = None
extensions = {}
# This seems a bit over engineered to me; it seems unlikely there will ever be
# a core besides xproto, so why not just hardcode that?
def _add_core(value, __setup, events, errors):
if not issubclass(value, Extension):
raise XcffibException(
"Extension type not derived from xcffib.Extension")
if not issubclass(__setup, Struct):
raise XcffibException("Setup type not derived from xcffib.Struct")
global core
global core_events
global core_errors
global _setup
core = value
core_events = events
core_errors = errors
_setup = __setup
def _add_ext(key, value, events, errors):
if not issubclass(value, Extension):
raise XcffibException(
"Extension type not derived from xcffib.Extension")
extensions[key] = (value, events, errors)
class ExtensionKey(object):
""" This definitely isn't needed, but we keep it around for compatibilty
with xpyb.
"""
def __init__(self, name):
self.name = name
def __hash__(self):
return hash(self.name)
def __eq__(self, o):
return self.name == o.name
def __ne__(self, o):
return self.name != o.name
def to_cffi(self):
c_key = ffi.new("struct xcb_extension_t *")
c_key.name = name = ffi.new('char[]', self.name.encode())
cffi_explicit_lifetimes[c_key] = name
# xpyb doesn't ever set global_id, which seems wrong, but whatever.
c_key.global_id = 0
return c_key
class Protobj(object):
""" Note: Unlike xcb.Protobj, this does NOT implement the sequence
protocol. I found this behavior confusing: Protobj would implement the
sequence protocol on self.buf, and then List would go and implement it on
List.
Instead, when we need to create a new event from an existing event, we
repack that event into a MemoryUnpacker and use that instead (see
eventToUnpacker in the generator for more info.)
"""
def __init__(self, unpacker):
"""
Params:
- unpacker: an Unpacker object
"""
# if we don't know the size right now, we expect it to be calculated
# based on stuff in the structure, so we don't save it right now.
if unpacker.known_max is not None:
self.bufsize = unpacker.known_max
@classmethod
def synthetic(cls, **kwargs):
self = cls.__new__(cls)
for k, v in kwargs.items():
setattr(self, k, v)
return self
class Struct(Protobj):
pass
class Union(Protobj):
@classmethod
def synthetic(cls, data=[], fmt=""):
self = cls.__new__(cls)
self.__init__(MemoryUnpacker(struct.pack(fmt, *data)))
return self
class Cookie(object):
reply_type = None
def __init__(self, conn, sequence, is_checked):
self.conn = conn
self.sequence = sequence
self.is_checked = is_checked
def reply(self):
data = self.conn.wait_for_reply(self.sequence)
return self.reply_type(data)
def check(self):
# Request is not void and checked.
assert self.is_checked and self.reply_type is None, (
"Request is not void and checked")
self.conn.request_check(self.sequence)
class VoidCookie(Cookie):
def reply(self):
raise XcffibException("No reply for this message type")
class Extension(object):
def __init__(self, conn, key=None):
self.conn = conn
if key is None:
self.c_key = ffi.NULL
else:
c_key = key.to_cffi()
cffi_explicit_lifetimes[self] = c_key
self.c_key = c_key
def send_request(self, opcode, data, cookie=VoidCookie, reply=None,
is_checked=False):
data = data.getvalue()
assert len(data) > 3, "xcb_send_request data must be ast least 4 bytes"
xcb_req = ffi.new("xcb_protocol_request_t *")
xcb_req.count = 2
xcb_req.ext = self.c_key
xcb_req.opcode = opcode
xcb_req.isvoid = issubclass(cookie, VoidCookie)
# XXX: send_request here will use the memory *before* the passed in
# xcb_parts pointer in some cases, so we need to allocate some for it
# to use, although we don't use it ourselves.
#
# http://lists.freedesktop.org/archives/xcb/2014-February/009307.html
xcb_parts = ffi.new("struct iovec[4]")
# Here we need this iov_base to keep this memory alive until the end of
# the function.
xcb_parts[2].iov_base = iov_base = ffi.new('char[]', data) # noqa
xcb_parts[2].iov_len = len(data)
xcb_parts[3].iov_base = ffi.NULL
xcb_parts[3].iov_len = -len(data) & 3 # is this really necessary?
flags = lib.XCB_REQUEST_CHECKED if is_checked else 0
seq = self.conn.send_request(flags, xcb_parts + 2, xcb_req)
return cookie(self.conn, seq, is_checked)
def __getattr__(self, name):
if name.endswith("Checked"):
real = name[:-len("Checked")]
is_checked = True
elif name.endswith("Unchecked"):
real = name[:-len("Unchecked")]
is_checked = False
else:
raise AttributeError(name)
real = getattr(self, real)
return functools.partial(real, is_checked=is_checked)
class List(Protobj):
def __init__(self, unpacker, typ, count=None):
Protobj.__init__(self, unpacker)
self.list = []
old = unpacker.offset
if isinstance(typ, str):
self.list = list(unpacker.unpack(typ * count))
elif count is not None:
for _ in range(count):
item = typ(unpacker)
self.list.append(item)
else:
assert unpacker.known_max is not None
while unpacker.offset < unpacker.known_max:
item = typ(unpacker)
self.list.append(item)
self.bufsize = unpacker.offset - old
assert count is None or count == len(self.list)
def __str__(self):
return str(self.list)
def __len__(self):
return len(self.list)
def __iter__(self):
return iter(self.list)
def __getitem__(self, key):
return self.list[key]
def __setitem__(self, key, value):
self.list[key] = value
def __delitem__(self, key):
del self.list[key]
def to_string(self):
""" A helper for converting a List of chars to a native string. Dies if
the list contents are not something that could be reasonably converted
to a string. """
return ''.join(chr(six.byte2int(i)) for i in self)
def to_utf8(self):
return six.b('').join(self).decode('utf-8')
def to_atoms(self):
""" A helper for converting a List of chars to an array of atoms """
return struct.unpack("=" + "I" * (len(self) // 4), b''.join(self))
def buf(self):
return b''.join(self.list)
class OffsetMap(object):
def __init__(self, core):
self.offsets = [(0, core)]
def add(self, offset, things):
self.offsets.append((offset, things))
self.offsets.sort(key=lambda x: x[0], reverse=True)
def __getitem__(self, item):
try:
offset, things = next((k, v) for k, v in self.offsets if item >= k)
return things[item - offset]
except StopIteration:
raise IndexError(item)
class Connection(object):
""" `auth` here should be ':', a format bequeathed to us from
xpyb. """
def __init__(self, display=None, fd=-1, auth=None):
if auth is not None:
[name, data] = auth.split(six.b(':'))
c_auth = ffi.new("xcb_auth_info_t *")
c_auth.name = ffi.new('char[]', name)
c_auth.namelen = len(name)
c_auth.data = ffi.new('char[]', data)
c_auth.datalen = len(data)
else:
c_auth = ffi.NULL
if display is None:
display = ffi.NULL
else:
display = display.encode('latin1')
i = ffi.new("int *")
if fd > 0:
self._conn = lib.xcb_connect_to_fd(fd, c_auth)
elif c_auth != ffi.NULL:
self._conn = lib.xcb_connect_to_display_with_auth_info(display, c_auth, i)
else:
self._conn = lib.xcb_connect(display, i)
self.pref_screen = i[0]
self.invalid()
self._init_x()
def _init_x(self):
if core is None:
raise XcffibException("No core protocol object has been set. "
"Did you import xcffib.xproto?")
self.core = core(self)
self.setup = self.get_setup()
self._event_offsets = OffsetMap(core_events)
self._error_offsets = OffsetMap(core_errors)
self._setup_extensions()
def _setup_extensions(self):
for key, (_, events, errors) in extensions.items():
# We're explicitly not putting this as an argument to the next call
# as a hack for lifetime management.
c_ext = key.to_cffi()
reply = lib.xcb_get_extension_data(self._conn, c_ext)
self._event_offsets.add(reply.first_event, events)
self._error_offsets.add(reply.first_error, errors)
def __call__(self, key):
return extensions[key][0](self, key)
def invalid(self):
if self._conn is None:
raise XcffibException("Invalid connection.")
err = lib.xcb_connection_has_error(self._conn)
if err > 0:
raise ConnectionException(err)
def ensure_connected(f):
"""
Check that the connection is valid both before and
after the function is invoked.
"""
@functools.wraps(f)
def wrapper(*args):
self = args[0]
self.invalid()
try:
return f(*args)
finally:
self.invalid()
return wrapper
@ensure_connected
def get_setup(self):
self._setup = lib.xcb_get_setup(self._conn)
# No idea where this 8 comes from either, similar complate to the
# sizeof(xcb_generic_reply_t) below.
buf = CffiUnpacker(self._setup, known_max=8 + self._setup.length * 4)
return _setup(buf)
@ensure_connected
def get_screen_pointers(self):
"""
Returns the xcb_screen_t for every screen
useful for other bindings
"""
root_iter = lib.xcb_setup_roots_iterator(self._setup)
screens = [root_iter.data]
for i in range(self._setup.roots_len - 1):
lib.xcb_screen_next(ffi.addressof((root_iter)))
screens.append(root_iter.data)
return screens
@ensure_connected
def wait_for_event(self):
e = lib.xcb_wait_for_event(self._conn)
e = ffi.gc(e, lib.free)
self.invalid()
return self.hoist_event(e)
@ensure_connected
def poll_for_event(self):
e = lib.xcb_poll_for_event(self._conn)
self.invalid()
if e != ffi.NULL:
return self.hoist_event(e)
else:
return None
def has_error(self):
return lib.xcb_connection_has_error(self._conn)
@ensure_connected
def get_file_descriptor(self):
return lib.xcb_get_file_descriptor(self._conn)
@ensure_connected
def get_maximum_request_length(self):
return lib.xcb_get_maximum_request_length(self._conn)
@ensure_connected
def prefetch_maximum_request_length(self):
return lib.xcb_prefetch_maximum_request_length(self._conn)
@ensure_connected
def flush(self):
return lib.xcb_flush(self._conn)
@ensure_connected
def generate_id(self):
return lib.xcb_generate_id(self._conn)
def disconnect(self):
self.invalid()
return lib.xcb_disconnect(self._conn)
def _process_error(self, c_error):
self.invalid()
if c_error != ffi.NULL:
error = self._error_offsets[c_error.error_code]
buf = CffiUnpacker(c_error)
raise error(buf)
@ensure_connected
def wait_for_reply(self, sequence):
error_p = ffi.new("xcb_generic_error_t **")
data = lib.xcb_wait_for_reply(self._conn, sequence, error_p)
data = ffi.gc(data, lib.free)
try:
self._process_error(error_p[0])
finally:
if error_p[0] != ffi.NULL:
lib.free(error_p[0])
if data == ffi.NULL:
# No data and no error => bad sequence number
raise XcffibException("Bad sequence number %d" % sequence)
reply = ffi.cast("xcb_generic_reply_t *", data)
# why is this 32 and not sizeof(xcb_generic_reply_t) == 8?
return CffiUnpacker(data, known_max=32 + reply.length * 4)
@ensure_connected
def request_check(self, sequence):
cookie = ffi.new("xcb_void_cookie_t [1]")
cookie[0].sequence = sequence
err = lib.xcb_request_check(self._conn, cookie[0])
self._process_error(err)
def hoist_event(self, e):
""" Hoist an xcb_generic_event_t to the right xcffib structure. """
if e.response_type == 0:
return self._process_error(ffi.cast("xcb_generic_error_t *", e))
# We mask off the high bit here because events sent with SendEvent have
# this bit set. We don't actually care where the event came from, so we
# just throw this away. Maybe we could expose this, if anyone actually
# cares about it.
event = self._event_offsets[e.response_type & 0x7f]
buf = CffiUnpacker(e)
return event(buf)
@ensure_connected
def send_request(self, flags, xcb_parts, xcb_req):
return lib.xcb_send_request(self._conn, flags, xcb_parts, xcb_req)
# More backwards compatibility
connect = Connection
class Response(Protobj):
def __init__(self, unpacker):
Protobj.__init__(self, unpacker)
# These (and the ones in Reply) aren't used internally and I suspect
# they're not used by anyone else, but they're here for xpyb
# compatibility.
#
# In some cases (e.g. creating synthetic events from memory), we don't
# have the sequence number (since the event was fake), so only try to
# get these attributes if we are really using a cffi buffer.
if isinstance(unpacker, CffiUnpacker):
resp = unpacker.cast("xcb_generic_event_t *")
self.response_type = resp.response_type
self.sequence = resp.sequence
else:
self.response_type = None
self.sequence = None
class Reply(Response):
def __init__(self, unpacker):
Response.__init__(self, unpacker)
# also for compat
resp = unpacker.cast("xcb_generic_reply_t *")
self.length = resp.length
class Event(Response):
pass
class Error(Response, XcffibException):
def __init__(self, unpacker):
Response.__init__(self, unpacker)
XcffibException.__init__(self)
self.code = unpacker.unpack('B', increment=False)
def pack_list(from_, pack_type):
""" Return the wire packed version of `from_`. `pack_type` should be some
subclass of `xcffib.Struct`, or a string that can be passed to
`struct.pack`. You must pass `size` if `pack_type` is a struct.pack string.
"""
# We need from_ to not be empty
if len(from_) == 0:
return bytes()
if pack_type == 'c':
if isinstance(from_, bytes):
# Catch Python 3 bytes and Python 2 strings
# PY3 is "helpful" in that when you do tuple(b'foo') you get
# (102, 111, 111) instead of something more reasonable like
# (b'f', b'o', b'o'), so we rebuild from_ as a tuple of bytes
from_ = [six.int2byte(b) for b in six.iterbytes(from_)]
elif isinstance(from_, six.string_types):
# Catch Python 3 strings and Python 2 unicode strings, both of
# which we encode to bytes as utf-8
# Here we create the tuple of bytes from the encoded string
from_ = [six.int2byte(b) for b in bytearray(from_, 'utf-8')]
elif isinstance(from_[0], six.integer_types):
# Pack from_ as char array, where from_ may be an array of ints
# possibly greater than 256
def to_bytes(v):
for _ in range(4):
v, r = divmod(v, 256)
yield r
from_ = [six.int2byte(b) for i in from_ for b in to_bytes(i)]
if isinstance(pack_type, six.string_types):
return struct.pack("=" + pack_type * len(from_), *from_)
else:
buf = six.BytesIO()
for item in from_:
# If we can't pack it, you'd better have packed it yourself...
if isinstance(item, Struct):
buf.write(item.pack())
else:
buf.write(item)
return buf.getvalue()
def wrap(ptr):
c_conn = ffi.cast('xcb_connection_t *', ptr)
conn = Connection.__new__(Connection)
conn._conn = c_conn
conn._init_x()
conn.invalid()
# ptr owns the memory for c_conn, even after the cast
# we should keep it alive
cffi_explicit_lifetimes[conn] = ptr
return conn
xcffib-0.3.6/module/ffi_build.py 0000664 0000000 0000000 00000021633 12565733531 0016562 0 ustar 00root root 0000000 0000000 # Copyright 2014 Tycho Andersen
# Copyright 2014 Sean Vig
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from cffi import FFI
CONSTANTS = [
("X_PROTOCOL", 11),
("X_PROTOCOL_REVISION", 0),
("X_TCP_PORT", 6000),
("XCB_NONE", 0),
("XCB_COPY_FROM_PARENT", 0),
("XCB_CURRENT_TIME", 0),
("XCB_NO_SYMBOL", 0),
("XCB_CONN_ERROR", 1),
("XCB_CONN_CLOSED_EXT_NOTSUPPORTED", 2),
("XCB_CONN_CLOSED_MEM_INSUFFICIENT", 3),
("XCB_CONN_CLOSED_REQ_LEN_EXCEED", 4),
("XCB_CONN_CLOSED_PARSE_ERR", 5),
("XCB_CONN_CLOSED_INVALID_SCREEN", 6),
("XCB_CONN_CLOSED_FDPASSING_FAILED", 7),
("XCB_REQUEST_CHECKED", 1 << 0)
]
# constants
CDEF = '\n'.join("#define %s %d" % (c, v) for c, v in CONSTANTS)
# types
CDEF += """
// xcb.h
typedef struct {
uint8_t response_type; /**< Type of the response */
uint8_t pad0; /**< Padding */
uint16_t sequence; /**< Sequence number */
uint32_t length; /**< Length of the response */
} xcb_generic_reply_t;
typedef struct {
uint8_t response_type; /**< Type of the response */
uint8_t pad0; /**< Padding */
uint16_t sequence; /**< Sequence number */
uint32_t pad[7]; /**< Padding */
uint32_t full_sequence; /**< full sequence */
} xcb_generic_event_t;
typedef struct {
uint8_t response_type; /**< Type of the response */
uint8_t error_code; /**< Error code */
uint16_t sequence; /**< Sequence number */
uint32_t resource_id; /** < Resource ID for requests with side effects only */
uint16_t minor_code; /** < Minor opcode of the failed request */
uint8_t major_code; /** < Major opcode of the failed request */
uint8_t pad0;
uint32_t pad[5]; /**< Padding */
uint32_t full_sequence; /**< full sequence */
} xcb_generic_error_t;
typedef struct {
unsigned int sequence; /**< Sequence number */
} xcb_void_cookie_t;
typedef struct xcb_auth_info_t {
int namelen;
char *name;
int datalen;
char *data;
} xcb_auth_info_t;
typedef ... xcb_connection_t;
// xproto.h
typedef uint32_t xcb_colormap_t;
typedef uint32_t xcb_drawable_t;
typedef uint32_t xcb_pixmap_t;
typedef uint32_t xcb_visualid_t;
typedef uint32_t xcb_window_t;
typedef struct xcb_query_extension_reply_t {
uint8_t response_type;
uint8_t pad0;
uint16_t sequence;
uint32_t length;
uint8_t present;
uint8_t major_opcode;
uint8_t first_event;
uint8_t first_error;
} xcb_query_extension_reply_t;
typedef struct xcb_setup_t {
uint8_t status; /**< */
uint8_t pad0; /**< */
uint16_t protocol_major_version; /**< */
uint16_t protocol_minor_version; /**< */
uint16_t length; /**< */
uint32_t release_number; /**< */
uint32_t resource_id_base; /**< */
uint32_t resource_id_mask; /**< */
uint32_t motion_buffer_size; /**< */
uint16_t vendor_len; /**< */
uint16_t maximum_request_length; /**< */
uint8_t roots_len; /**< */
uint8_t pixmap_formats_len; /**< */
uint8_t image_byte_order; /**< */
uint8_t bitmap_format_bit_order; /**< */
uint8_t bitmap_format_scanline_unit; /**< */
uint8_t bitmap_format_scanline_pad; /**< */
uint8_t min_keycode; /**< */
uint8_t max_keycode; /**< */
uint8_t pad1[4]; /**< */
} xcb_setup_t;
typedef struct xcb_visualtype_t {
xcb_visualid_t visual_id; /**< */
uint8_t _class; /**< */
uint8_t bits_per_rgb_value; /**< */
uint16_t colormap_entries; /**< */
uint32_t red_mask; /**< */
uint32_t green_mask; /**< */
uint32_t blue_mask; /**< */
uint8_t pad0[4]; /**< */
} xcb_visualtype_t;
typedef struct xcb_screen_t {
xcb_window_t root; /**< */
xcb_colormap_t default_colormap; /**< */
uint32_t white_pixel; /**< */
uint32_t black_pixel; /**< */
uint32_t current_input_masks; /**< */
uint16_t width_in_pixels; /**< */
uint16_t height_in_pixels; /**< */
uint16_t width_in_millimeters; /**< */
uint16_t height_in_millimeters; /**< */
uint16_t min_installed_maps; /**< */
uint16_t max_installed_maps; /**< */
xcb_visualid_t root_visual; /**< */
uint8_t backing_stores; /**< */
uint8_t save_unders; /**< */
uint8_t root_depth; /**< */
uint8_t allowed_depths_len; /**< */
} xcb_screen_t;
typedef struct xcb_screen_iterator_t {
xcb_screen_t *data; /**< */
int rem; /**< */
int index; /**< */
} xcb_screen_iterator_t;
xcb_screen_iterator_t
xcb_setup_roots_iterator (const xcb_setup_t *R /**< */);
void
xcb_screen_next (xcb_screen_iterator_t *i /**< */);
// render.h
typedef uint32_t xcb_render_pictformat_t;
typedef struct xcb_render_directformat_t {
uint16_t red_shift; /**< */
uint16_t red_mask; /**< */
uint16_t green_shift; /**< */
uint16_t green_mask; /**< */
uint16_t blue_shift; /**< */
uint16_t blue_mask; /**< */
uint16_t alpha_shift; /**< */
uint16_t alpha_mask; /**< */
} xcb_render_directformat_t;
typedef struct xcb_render_pictforminfo_t {
xcb_render_pictformat_t id; /**< */
uint8_t type; /**< */
uint8_t depth; /**< */
uint8_t pad0[2]; /**< */
xcb_render_directformat_t direct; /**< */
xcb_colormap_t colormap; /**< */
} xcb_render_pictforminfo_t;
// xcbext.h
typedef struct xcb_extension_t {
const char *name;
int global_id;
} xcb_extension_t;
typedef struct {
size_t count;
xcb_extension_t *ext;
uint8_t opcode;
uint8_t isvoid;
} xcb_protocol_request_t;
// sys/uio.h
struct iovec
{
void *iov_base; /* BSD uses caddr_t (1003.1g requires void *) */
size_t iov_len; /* Must be size_t (1003.1g) */
};
// need to manually free some things that XCB allocates
void free(void *ptr);
"""
# connection manipulation, mostly generated with:
# grep -v '^[ \/\}#]' xcb.h | grep -v '^typedef' | grep -v '^extern'
CDEF += """
int xcb_flush(xcb_connection_t *c);
uint32_t xcb_get_maximum_request_length(xcb_connection_t *c);
void xcb_prefetch_maximum_request_length(xcb_connection_t *c);
xcb_generic_event_t *xcb_wait_for_event(xcb_connection_t *c);
xcb_generic_event_t *xcb_poll_for_event(xcb_connection_t *c);
const xcb_query_extension_reply_t *xcb_get_extension_data(xcb_connection_t *c, xcb_extension_t *ext);
const xcb_setup_t *xcb_get_setup(xcb_connection_t *c);
int xcb_get_file_descriptor(xcb_connection_t *c);
int xcb_connection_has_error(xcb_connection_t *c);
xcb_connection_t *xcb_connect_to_fd(int fd, xcb_auth_info_t *auth_info);
void xcb_disconnect(xcb_connection_t *c);
int xcb_parse_display(const char *name, char **host, int *display, int *screen);
xcb_connection_t *xcb_connect(const char *displayname, int *screenp);
xcb_connection_t *xcb_connect_to_display_with_auth_info(const char *display, xcb_auth_info_t *auth, int *screen);
uint32_t xcb_generate_id(xcb_connection_t *c);
xcb_generic_error_t *xcb_request_check(xcb_connection_t *c, xcb_void_cookie_t cookie);
"""
CDEF += """
unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vector, const xcb_protocol_request_t *request);
void *xcb_wait_for_reply(xcb_connection_t *c, unsigned int request, xcb_generic_error_t **e);
int xcb_poll_for_reply(xcb_connection_t *c, unsigned int request, void **reply, xcb_generic_error_t **error);
"""
ffi = FFI()
if hasattr(ffi, 'set_source'): # PyPy < 2.6 compatibility hack
ffi.set_source("xcffib._ffi", None, libraries=['xcb'])
do_compile = True
else:
do_compile = False
ffi.cdef(CDEF)
if __name__ == "__main__" and do_compile:
ffi.compile()
xcffib-0.3.6/module/testing.py 0000664 0000000 0000000 00000007323 12565733531 0016314 0 ustar 00root root 0000000 0000000 # Copyright 2014 Tycho Andersen
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Not strictly necessary to be included with the binding, but may be useful for
# others who want to test things using xcffib.
import os
import time
import errno
import subprocess
from . import Connection, ConnectionException
def lock_path(display):
return '/tmp/.X%d-lock' % display
class XvfbTest(object):
""" A helper class for testing things with nosetests. This class will run
each test in its own fresh xvfb, leaving you with an xcffib connection to
that X session as `self.conn` for use in testing. """
# Set this to true if you'd like to get xtrace output to stdout of each
# test.
xtrace = False
def spawn(self, cmd):
""" Spawn a command but swallow its output. """
discard = open(os.devnull)
return subprocess.Popen(cmd, stdout=discard, stderr=discard)
def setUp(self):
self.width = 800
self.height = 600
self.depth = 16
self._old_display = os.environ.get('DISPLAY')
os.environ['DISPLAY'] = ':%d' % self._find_display()
self._xvfb = self.spawn(self._xvfb_command())
if self.xtrace:
subprocess.Popen(['xtrace', '-n'])
# xtrace's default display is :9
os.environ['DISPLAY'] = ':9'
self.conn = self._connect_to_xvfb()
def tearDown(self):
try:
self.conn.disconnect()
except ConnectionException:
# We don't care if the connection was in an invalid state, maybe
# the test failed.
pass
finally:
self.conn = None
self._xvfb.kill()
self._xvfb.wait()
self._xvfb = None
# Delete our X lock file too, since we .kill() the process so it won't
# clean up after itself.
try:
os.remove(lock_path(self._display))
except OSError as e:
# we don't care if it doesn't exist, maybe something crashed and
# cleaned it up during a test.
if e.errno != errno.ENOENT:
raise
if self._old_display is None:
del os.environ['DISPLAY']
else:
os.environ['DISPLAY'] = self._old_display
def _xvfb_command(self):
""" You can override this if you have some extra args for Xvfb or
whatever. At this point, os.environ['DISPLAY'] is set to something Xvfb
can use. """
screen = '%sx%sx%s' % (self.width, self.height, self.depth)
return ['Xvfb', os.environ['DISPLAY'], '-screen', '0', screen]
def _connect_to_xvfb(self):
# sometimes it takes a while for Xvfb to start
for _ in range(100):
try:
conn = Connection(os.environ['DISPLAY'])
conn.invalid()
return conn
except ConnectionException:
time.sleep(0.2)
assert False, "couldn't connect to xvfb"
def _find_display(self):
# Don't do this for every test.
if hasattr(self, '_display'):
return self._display
self._display = 10
while True:
if not os.path.exists(lock_path(self._display)):
return self._display
self._display += 1
xcffib-0.3.6/requirements.txt 0000664 0000000 0000000 00000000040 12565733531 0016251 0 ustar 00root root 0000000 0000000 flake8
autopep8
six
cffi>=0.8.2
xcffib-0.3.6/setup.py 0000664 0000000 0000000 00000006316 12565733531 0014513 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python
#
# Copyright 2014 Tycho Andersen
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
from setuptools import setup
from setuptools.command.install import install
from distutils.command.build import build
class binding_build(build):
"""This is a check to ensure that the bindings have been generated, and
print a helpful message if they have not been generated yet. We only need
to check this when we are actually building or installing.
"""
def finalize_options(self):
if not os.path.exists('./xcffib'):
print("It looks like you need to generate the binding.")
print("please run 'make xcffib' or 'make check'.")
sys.exit(1)
build.finalize_options(self)
class binding_install(install):
def finalize_options(self):
if not os.path.exists('./xcffib'):
print("It looks like you need to generate the binding.")
print("please run 'make xcffib' or 'make check'.")
sys.exit(1)
install.finalize_options(self)
# Check if we're running PyPy, cffi can't be updated
if '_cffi_backend' in sys.builtin_module_names:
import _cffi_backend
requires_cffi = "cffi==" + _cffi_backend.__version__
else:
requires_cffi = "cffi>=1.1.0"
# PyPy < 2.6 hack, can be dropped when PyPy3 2.6 is released
if requires_cffi.startswith("cffi==0."):
cffi_args = dict(
ext_package="xcffib"
)
else:
cffi_args = dict(
cffi_modules=["xcffib/ffi_build.py:ffi"]
)
version = "0.3.6"
dependencies = ['six', requires_cffi]
setup(
name="xcffib",
version=version,
description="A drop in replacement for xpyb, an XCB python binding",
keywords="xcb xpyb cffi x11 x windows",
license="Apache License 2.0",
url="http://github.com/tych0/xcffib",
author="Tycho Andersen",
author_email="tycho@tycho.ws",
install_requires=dependencies,
setup_requires=dependencies,
packages=['xcffib'],
zip_safe=False,
cmdclass={
'build': binding_build,
'install': binding_install
},
classifiers=[
'Development Status :: 4 - Beta',
'License :: OSI Approved :: Apache Software License',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'Topic :: Software Development :: Libraries'
],
**cffi_args
)
xcffib-0.3.6/tests/ 0000775 0000000 0000000 00000000000 12565733531 0014135 5 ustar 00root root 0000000 0000000 xcffib-0.3.6/tests/GeneratorTests.hs 0000664 0000000 0000000 00000004010 12565733531 0017435 0 ustar 00root root 0000000 0000000 {-
- Copyright 2014 Tycho Andersen
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-}
module Main (main) where
import Language.Python.Common
import Data.XCB.Python.Parse
import Data.XCB.FromXML
import Data.XCB.Types
import Test.Framework ( defaultMain, Test )
import Test.Framework.Providers.HUnit
import Test.HUnit hiding ( Test )
import System.FilePath
pyTests :: [String]
pyTests = [ "event"
, "error"
, "request"
, "union"
, "struct"
, "enum"
, "request_reply"
, "no_sequence"
, "type_pad"
, "render_1.7"
, "xproto_1.7"
]
mkFname :: String -> FilePath
mkFname = (>) $ "tests" > "generator"
mkTest :: String -> IO Test
mkTest name = do
header <- fromFiles [mkFname $ name <.> ".xml"]
rawExpected <- readFile . mkFname $ name <.> ".py"
let [(fname, outPy)] = xform header
rawOut = renderPy outPy
return $ testCase name $ do assertEqual "names equal" name fname
-- TODO: we should really parse and compare ASTs
assertEqual "rendering equal" rawExpected rawOut
calcsizeTests :: [Test]
calcsizeTests =
let tests = [ ("x2xBx", 5)
, ("24xHhII", 24 + 2 * 2 + 2 * 4)
]
in map mkTest tests
where
mkTest (str, expected) =
let result = calcsize str
in testCase "calcsize" (assertEqual str expected result)
main :: IO ()
main = do
genTests <- mapM mkTest pyTests
defaultMain $ calcsizeTests ++ genTests
xcffib-0.3.6/tests/PyHelpersTests.hs 0000664 0000000 0000000 00000002560 12565733531 0017432 0 ustar 00root root 0000000 0000000 {-
- Copyright 2014 Tycho Andersen
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-}
module Main (main) where
import Language.Python.Common
import Data.XCB.Python.PyHelpers
import Test.Framework ( defaultMain, Test )
import Test.Framework.Providers.HUnit
import Test.HUnit hiding ( Test )
mkTest :: (Show a, Eq a) => String -> a -> a -> Test
mkTest name t1 t2 = testCase name (assertEqual name t1 t2)
testMkName :: Test
testMkName =
let result = mkName "self.foo.bar"
expected = (Dot (Dot (Var (Ident "self" ()) ())
(Ident "foo" ()) ())
(Ident "bar" ()) ())
in mkTest "testMkName" expected result
testReserves :: Test
testReserves =
let result = mkName "None"
expected = (Var (Ident "_None" ()) ())
in mkTest "testReserves" expected result
main :: IO ()
main = do
defaultMain [testMkName, testReserves]
xcffib-0.3.6/tests/__init__.py 0000664 0000000 0000000 00000000000 12565733531 0016234 0 ustar 00root root 0000000 0000000 xcffib-0.3.6/tests/flake8.cfg 0000664 0000000 0000000 00000000460 12565733531 0015770 0 ustar 00root root 0000000 0000000 # F401: unused imports. xcb actually does some internal state changing on
# imports, so in fact these /are/ used, just not directly.
#
# E501: line too long. This is from the copy and pasted function definitons
# from cairo headers, which I think are best left as one liners.
[flake8]
ignore = F401,E501
xcffib-0.3.6/tests/generator/ 0000775 0000000 0000000 00000000000 12565733531 0016123 5 ustar 00root root 0000000 0000000 xcffib-0.3.6/tests/generator/enum.py 0000664 0000000 0000000 00000001730 12565733531 0017442 0 ustar 00root root 0000000 0000000 import xcffib
import struct
import six
_events = {}
_errors = {}
class DeviceUse:
IsXPointer = 0
IsXKeyboard = 1
IsXExtensionDevice = 2
IsXExtensionKeyboard = 3
IsXExtensionPointer = 4
class EventMask:
NoEvent = 0
KeyPress = 1 << 0
KeyRelease = 1 << 1
ButtonPress = 1 << 2
ButtonRelease = 1 << 3
EnterWindow = 1 << 4
LeaveWindow = 1 << 5
PointerMotion = 1 << 6
PointerMotionHint = 1 << 7
Button1Motion = 1 << 8
Button2Motion = 1 << 9
Button3Motion = 1 << 10
Button4Motion = 1 << 11
Button5Motion = 1 << 12
ButtonMotion = 1 << 13
KeymapState = 1 << 14
Exposure = 1 << 15
VisibilityChange = 1 << 16
StructureNotify = 1 << 17
ResizeRedirect = 1 << 18
SubstructureNotify = 1 << 19
SubstructureRedirect = 1 << 20
FocusChange = 1 << 21
PropertyChange = 1 << 22
ColorMapChange = 1 << 23
OwnerGrabButton = 1 << 24
xcffib._add_ext(key, enumExtension, _events, _errors)
xcffib-0.3.6/tests/generator/enum.xml 0000664 0000000 0000000 00000003714 12565733531 0017616 0 ustar 00root root 0000000 0000000
- 0
- 1
- 2
- 3
- 4
- 0
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
xcffib-0.3.6/tests/generator/error.py 0000664 0000000 0000000 00000001523 12565733531 0017627 0 ustar 00root root 0000000 0000000 import xcffib
import struct
import six
MAJOR_VERSION = 2
MINOR_VERSION = 2
key = xcffib.ExtensionKey("ERROR")
_events = {}
_errors = {}
class RequestError(xcffib.Error):
def __init__(self, unpacker):
if isinstance(unpacker, xcffib.Protobj):
unpacker = xcffib.MemoryUnpacker(unpacker.pack())
xcffib.Error.__init__(self, unpacker)
base = unpacker.offset
self.bad_value, self.minor_opcode, self.major_opcode = unpacker.unpack("xx2xIHBx")
self.bufsize = unpacker.offset - base
def pack(self):
buf = six.BytesIO()
buf.write(struct.pack("=B", 1))
buf.write(struct.pack("=x2xIHBx", self.bad_value, self.minor_opcode, self.major_opcode))
return buf.getvalue()
BadRequest = RequestError
_errors[1] = RequestError
xcffib._add_ext(key, errorExtension, _events, _errors)
xcffib-0.3.6/tests/generator/error.xml 0000664 0000000 0000000 00000000535 12565733531 0020001 0 ustar 00root root 0000000 0000000
xcffib-0.3.6/tests/generator/event.py 0000664 0000000 0000000 00000002277 12565733531 0017626 0 ustar 00root root 0000000 0000000 import xcffib
import struct
import six
MAJOR_VERSION = 1
MINOR_VERSION = 4
key = xcffib.ExtensionKey("EVENT")
_events = {}
_errors = {}
class ScreenChangeNotifyEvent(xcffib.Event):
def __init__(self, unpacker):
if isinstance(unpacker, xcffib.Protobj):
unpacker = xcffib.MemoryUnpacker(unpacker.pack())
xcffib.Event.__init__(self, unpacker)
base = unpacker.offset
self.rotation, self.timestamp, self.config_timestamp, self.root, self.request_window, self.sizeID, self.subpixel_order, self.width, self.height, self.mwidth, self.mheight = unpacker.unpack("xB2xIIIIHHHHHH")
self.bufsize = unpacker.offset - base
def pack(self):
buf = six.BytesIO()
buf.write(struct.pack("=B", 0))
buf.write(struct.pack("=B2xIIIIHHHHHH", self.rotation, self.timestamp, self.config_timestamp, self.root, self.request_window, self.sizeID, self.subpixel_order, self.width, self.height, self.mwidth, self.mheight))
buf_len = len(buf.getvalue())
if buf_len < 32:
buf.write(struct.pack("x" * (32 - buf_len)))
return buf.getvalue()
_events[0] = ScreenChangeNotifyEvent
xcffib._add_ext(key, eventExtension, _events, _errors)
xcffib-0.3.6/tests/generator/event.xml 0000664 0000000 0000000 00000001451 12565733531 0017767 0 ustar 00root root 0000000 0000000
xcffib-0.3.6/tests/generator/no_sequence.py 0000664 0000000 0000000 00000001504 12565733531 0021001 0 ustar 00root root 0000000 0000000 import xcffib
import struct
import six
_events = {}
_errors = {}
class KeymapNotifyEvent(xcffib.Event):
def __init__(self, unpacker):
if isinstance(unpacker, xcffib.Protobj):
unpacker = xcffib.MemoryUnpacker(unpacker.pack())
xcffib.Event.__init__(self, unpacker)
base = unpacker.offset
unpacker.unpack("x")
self.keys = xcffib.List(unpacker, "B", 31)
self.bufsize = unpacker.offset - base
def pack(self):
buf = six.BytesIO()
buf.write(struct.pack("=B", 11))
buf.write(xcffib.pack_list(self.keys, "B"))
buf_len = len(buf.getvalue())
if buf_len < 32:
buf.write(struct.pack("x" * (32 - buf_len)))
return buf.getvalue()
_events[11] = KeymapNotifyEvent
xcffib._add_ext(key, no_sequenceExtension, _events, _errors)
xcffib-0.3.6/tests/generator/no_sequence.xml 0000664 0000000 0000000 00000000255 12565733531 0021153 0 ustar 00root root 0000000 0000000
31
xcffib-0.3.6/tests/generator/render_1.7.py 0000664 0000000 0000000 00000002366 12565733531 0020350 0 ustar 00root root 0000000 0000000 import xcffib
import struct
import six
MAJOR_VERSION = 0
MINOR_VERSION = 11
key = xcffib.ExtensionKey("RENDER")
_events = {}
_errors = {}
class PictOp:
Clear = 0
Src = 1
Dst = 2
Over = 3
OverReverse = 4
In = 5
InReverse = 6
Out = 7
OutReverse = 8
Atop = 9
AtopReverse = 10
Xor = 11
Add = 12
Saturate = 13
DisjointClear = 16
DisjointSrc = 17
DisjointDst = 18
DisjointOver = 19
DisjointOverReverse = 20
DisjointIn = 21
DisjointInReverse = 22
DisjointOut = 23
DisjointOutReverse = 24
DisjointAtop = 25
DisjointAtopReverse = 26
DisjointXor = 27
ConjointClear = 32
ConjointSrc = 33
ConjointDst = 34
ConjointOver = 35
ConjointOverReverse = 36
ConjointIn = 37
ConjointInReverse = 38
ConjointOut = 39
ConjointOutReverse = 40
ConjointAtop = 41
ConjointAtopReverse = 42
ConjointXor = 43
Multiply = 48
Screen = 49
Overlay = 50
Darken = 51
Lighten = 52
ColorDodge = 53
ColorBurn = 54
HardLight = 55
SoftLight = 56
Difference = 57
Exclusion = 58
HSLHue = 59
HSLSaturation = 60
HSLColor = 61
HSLLuminosity = 62
xcffib._add_ext(key, render_1._7Extension, _events, _errors)
xcffib-0.3.6/tests/generator/render_1.7.xml 0000664 0000000 0000000 00000004342 12565733531 0020514 0 ustar 00root root 0000000 0000000
- 16
- 32
- 48
xcffib-0.3.6/tests/generator/request.py 0000664 0000000 0000000 00000001153 12565733531 0020165 0 ustar 00root root 0000000 0000000 import xcffib
import struct
import six
_events = {}
_errors = {}
class requestExtension(xcffib.Extension):
def CreateWindow(self, depth, wid, parent, x, y, width, height, border_width, _class, visual, value_mask, value_list, is_checked=False):
buf = six.BytesIO()
buf.write(struct.pack("=xB2xIIhhHHHHI", depth, wid, parent, x, y, width, height, border_width, _class, visual))
buf.write(struct.pack("=I", value_mask))
buf.write(xcffib.pack_list(value_list, "I"))
return self.send_request(1, buf, is_checked=is_checked)
xcffib._add_ext(key, requestExtension, _events, _errors)
xcffib-0.3.6/tests/generator/request.xml 0000664 0000000 0000000 00000006324 12565733531 0020342 0 ustar 00root root 0000000 0000000
Creates a window
xcffib-0.3.6/tests/generator/request_reply.py 0000664 0000000 0000000 00000002677 12565733531 0021414 0 ustar 00root root 0000000 0000000 import xcffib
import struct
import six
_events = {}
_errors = {}
class STR(xcffib.Struct):
def __init__(self, unpacker):
if isinstance(unpacker, xcffib.Protobj):
unpacker = xcffib.MemoryUnpacker(unpacker.pack())
xcffib.Struct.__init__(self, unpacker)
base = unpacker.offset
self.name_len, = unpacker.unpack("B")
self.name = xcffib.List(unpacker, "c", self.name_len)
self.bufsize = unpacker.offset - base
def pack(self):
buf = six.BytesIO()
buf.write(struct.pack("=B", self.name_len))
buf.write(xcffib.pack_list(self.name, "c"))
return buf.getvalue()
class ListExtensionsReply(xcffib.Reply):
def __init__(self, unpacker):
if isinstance(unpacker, xcffib.Protobj):
unpacker = xcffib.MemoryUnpacker(unpacker.pack())
xcffib.Reply.__init__(self, unpacker)
base = unpacker.offset
self.names_len, = unpacker.unpack("xB2x4x24x")
self.names = xcffib.List(unpacker, STR, self.names_len)
self.bufsize = unpacker.offset - base
class ListExtensionsCookie(xcffib.Cookie):
reply_type = ListExtensionsReply
class request_replyExtension(xcffib.Extension):
def ListExtensions(self, is_checked=True):
buf = six.BytesIO()
buf.write(struct.pack("=xx2x"))
return self.send_request(99, buf, ListExtensionsCookie, is_checked=is_checked)
xcffib._add_ext(key, request_replyExtension, _events, _errors)
xcffib-0.3.6/tests/generator/request_reply.xml 0000664 0000000 0000000 00000000725 12565733531 0021554 0 ustar 00root root 0000000 0000000
name_len
names_len
xcffib-0.3.6/tests/generator/struct.py 0000664 0000000 0000000 00000002567 12565733531 0020033 0 ustar 00root root 0000000 0000000 import xcffib
import struct
import six
_events = {}
_errors = {}
class AxisInfo(xcffib.Struct):
def __init__(self, unpacker):
if isinstance(unpacker, xcffib.Protobj):
unpacker = xcffib.MemoryUnpacker(unpacker.pack())
xcffib.Struct.__init__(self, unpacker)
base = unpacker.offset
self.resolution, self.minimum, self.maximum = unpacker.unpack("Iii")
self.bufsize = unpacker.offset - base
def pack(self):
buf = six.BytesIO()
buf.write(struct.pack("=Iii", self.resolution, self.minimum, self.maximum))
return buf.getvalue()
fixed_size = 12
class ValuatorInfo(xcffib.Struct):
def __init__(self, unpacker):
if isinstance(unpacker, xcffib.Protobj):
unpacker = xcffib.MemoryUnpacker(unpacker.pack())
xcffib.Struct.__init__(self, unpacker)
base = unpacker.offset
self.class_id, self.len, self.axes_len, self.mode, self.motion_size = unpacker.unpack("BBBBI")
self.axes = xcffib.List(unpacker, AxisInfo, self.axes_len)
self.bufsize = unpacker.offset - base
def pack(self):
buf = six.BytesIO()
buf.write(struct.pack("=BBBBI", self.class_id, self.len, self.axes_len, self.mode, self.motion_size))
buf.write(xcffib.pack_list(self.axes, AxisInfo))
return buf.getvalue()
xcffib._add_ext(key, structExtension, _events, _errors)
xcffib-0.3.6/tests/generator/struct.xml 0000664 0000000 0000000 00000001235 12565733531 0020172 0 ustar 00root root 0000000 0000000
axes_len
xcffib-0.3.6/tests/generator/type_pad.py 0000664 0000000 0000000 00000005307 12565733531 0020307 0 ustar 00root root 0000000 0000000 import xcffib
import struct
import six
_events = {}
_errors = {}
class CHARINFO(xcffib.Struct):
def __init__(self, unpacker):
if isinstance(unpacker, xcffib.Protobj):
unpacker = xcffib.MemoryUnpacker(unpacker.pack())
xcffib.Struct.__init__(self, unpacker)
base = unpacker.offset
self.left_side_bearing, self.right_side_bearing, self.character_width, self.ascent, self.descent, self.attributes = unpacker.unpack("hhhhhH")
self.bufsize = unpacker.offset - base
def pack(self):
buf = six.BytesIO()
buf.write(struct.pack("=hhhhhH", self.left_side_bearing, self.right_side_bearing, self.character_width, self.ascent, self.descent, self.attributes))
return buf.getvalue()
fixed_size = 12
class FONTPROP(xcffib.Struct):
def __init__(self, unpacker):
if isinstance(unpacker, xcffib.Protobj):
unpacker = xcffib.MemoryUnpacker(unpacker.pack())
xcffib.Struct.__init__(self, unpacker)
base = unpacker.offset
self.name, self.value = unpacker.unpack("II")
self.bufsize = unpacker.offset - base
def pack(self):
buf = six.BytesIO()
buf.write(struct.pack("=II", self.name, self.value))
return buf.getvalue()
fixed_size = 8
class ListFontsWithInfoReply(xcffib.Reply):
def __init__(self, unpacker):
if isinstance(unpacker, xcffib.Protobj):
unpacker = xcffib.MemoryUnpacker(unpacker.pack())
xcffib.Reply.__init__(self, unpacker)
base = unpacker.offset
self.name_len, = unpacker.unpack("xB2x4x")
self.min_bounds = CHARINFO(unpacker)
unpacker.unpack("4x")
unpacker.pad(CHARINFO)
self.max_bounds = CHARINFO(unpacker)
self.min_char_or_byte2, self.max_char_or_byte2, self.default_char, self.properties_len, self.draw_direction, self.min_byte1, self.max_byte1, self.all_chars_exist, self.font_ascent, self.font_descent, self.replies_hint = unpacker.unpack("4xHHHHBBBBhhI")
unpacker.pad(FONTPROP)
self.properties = xcffib.List(unpacker, FONTPROP, self.properties_len)
unpacker.pad("c")
self.name = xcffib.List(unpacker, "c", self.name_len)
self.bufsize = unpacker.offset - base
class ListFontsWithInfoCookie(xcffib.Cookie):
reply_type = ListFontsWithInfoReply
class type_padExtension(xcffib.Extension):
def ListFontsWithInfo(self, max_names, pattern_len, pattern, is_checked=True):
buf = six.BytesIO()
buf.write(struct.pack("=xx2xHH", max_names, pattern_len))
buf.write(xcffib.pack_list(pattern, "c"))
return self.send_request(50, buf, ListFontsWithInfoCookie, is_checked=is_checked)
xcffib._add_ext(key, type_padExtension, _events, _errors)
xcffib-0.3.6/tests/generator/type_pad.xml 0000664 0000000 0000000 00000007303 12565733531 0020455 0 ustar 00root root 0000000 0000000
pattern_len
properties_len
name_len
get matching font names and information
xcffib-0.3.6/tests/generator/union.py 0000664 0000000 0000000 00000001223 12565733531 0017623 0 ustar 00root root 0000000 0000000 import xcffib
import struct
import six
_events = {}
_errors = {}
class ClientMessageData(xcffib.Union):
def __init__(self, unpacker):
if isinstance(unpacker, xcffib.Protobj):
unpacker = xcffib.MemoryUnpacker(unpacker.pack())
xcffib.Union.__init__(self, unpacker)
self.data8 = xcffib.List(unpacker.copy(), "B", 20)
self.data16 = xcffib.List(unpacker.copy(), "H", 10)
self.data32 = xcffib.List(unpacker.copy(), "I", 5)
def pack(self):
buf = six.BytesIO()
buf.write(xcffib.pack_list(self.data8, "B"))
return buf.getvalue()
xcffib._add_ext(key, unionExtension, _events, _errors)
xcffib-0.3.6/tests/generator/union.xml 0000664 0000000 0000000 00000000650 12565733531 0017776 0 ustar 00root root 0000000 0000000
20
10
5
xcffib-0.3.6/tests/generator/xproto_1.7.py 0000664 0000000 0000000 00000003106 12565733531 0020415 0 ustar 00root root 0000000 0000000 import xcffib
import struct
import six
MAJOR_VERSION = 0
MINOR_VERSION = 11
key = xcffib.ExtensionKey("XPROTO")
_events = {}
_errors = {}
class Atom:
_None = 0
Any = 0
PRIMARY = 1
SECONDARY = 2
ARC = 3
ATOM = 4
BITMAP = 5
CARDINAL = 6
COLORMAP = 7
CURSOR = 8
CUT_BUFFER0 = 9
CUT_BUFFER1 = 10
CUT_BUFFER2 = 11
CUT_BUFFER3 = 12
CUT_BUFFER4 = 13
CUT_BUFFER5 = 14
CUT_BUFFER6 = 15
CUT_BUFFER7 = 16
DRAWABLE = 17
FONT = 18
INTEGER = 19
PIXMAP = 20
POINT = 21
RECTANGLE = 22
RESOURCE_MANAGER = 23
RGB_COLOR_MAP = 24
RGB_BEST_MAP = 25
RGB_BLUE_MAP = 26
RGB_DEFAULT_MAP = 27
RGB_GRAY_MAP = 28
RGB_GREEN_MAP = 29
RGB_RED_MAP = 30
STRING = 31
VISUALID = 32
WINDOW = 33
WM_COMMAND = 34
WM_HINTS = 35
WM_CLIENT_MACHINE = 36
WM_ICON_NAME = 37
WM_ICON_SIZE = 38
WM_NAME = 39
WM_NORMAL_HINTS = 40
WM_SIZE_HINTS = 41
WM_ZOOM_HINTS = 42
MIN_SPACE = 43
NORM_SPACE = 44
MAX_SPACE = 45
END_SPACE = 46
SUPERSCRIPT_X = 47
SUPERSCRIPT_Y = 48
SUBSCRIPT_X = 49
SUBSCRIPT_Y = 50
UNDERLINE_POSITION = 51
UNDERLINE_THICKNESS = 52
STRIKEOUT_ASCENT = 53
STRIKEOUT_DESCENT = 54
ITALIC_ANGLE = 55
X_HEIGHT = 56
QUAD_WIDTH = 57
WEIGHT = 58
POINT_SIZE = 59
RESOLUTION = 60
COPYRIGHT = 61
NOTICE = 62
FONT_NAME = 63
FAMILY_NAME = 64
FULL_NAME = 65
CAP_HEIGHT = 66
WM_CLASS = 67
WM_TRANSIENT_FOR = 68
xcffib._add_ext(key, xproto_1._7Extension, _events, _errors)
xcffib-0.3.6/tests/generator/xproto_1.7.xml 0000664 0000000 0000000 00000005054 12565733531 0020571 0 ustar 00root root 0000000 0000000
- 0
- 0
xcffib-0.3.6/tests/test_connection.py 0000664 0000000 0000000 00000024673 12565733531 0017721 0 ustar 00root root 0000000 0000000 # Copyright 2014 Tycho Andersen
# Copyright 2014 Sean Vig
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import six
import xcffib
import xcffib.xproto
from xcffib import ffi
from xcffib.testing import XvfbTest
from .testing import XcffibTest
from nose.tools import raises
from nose import SkipTest
import struct
class TestConnection(XcffibTest):
def setUp(self):
XvfbTest.setUp(self)
self.xproto = xcffib.xproto.xprotoExtension(self.conn)
def tearDown(self):
self.xproto = None
XvfbTest.tearDown(self)
@raises(xcffib.ConnectionException)
def test_invalid_display(self):
self.conn = xcffib.Connection('notvalid')
self.conn.invalid()
def test_get_setup(self):
setup = self.conn.get_setup()
# When X upgrades, we can probably manage to change this test :-)
assert setup.protocol_major_version == 11
assert setup.protocol_minor_version == 0
def test_get_screen_pointers(self):
screens = self.conn.get_screen_pointers()
assert len(screens) == 1
screen = screens[0]
assert ffi.typeof(screen) is ffi.typeof("xcb_screen_t *")
assert screen.root == self.default_screen.root
assert screen.width_in_pixels == self.width
assert screen.height_in_pixels == self.height
assert screen.root_depth == self.depth
def test_seq_increases(self):
# If this test starts failing because the sequence numbers don't mach,
# that's probably because you added a new test that imports a new X
# extension. When that happens, every new connection automatically does
# a QueryExtention for each new ext that has been imported, so the
# squence numbers go up by one.
#
# i.e:
# xproto setup query = seqno 0
# xtest setup query = seqno 1
raise SkipTest
assert self.xproto.GetInputFocus().sequence == 2
assert self.xproto.GetInputFocus().sequence == 3
@raises(xcffib.ConnectionException)
def test_invalid(self):
conn = xcffib.Connection('notadisplay')
conn.invalid()
def test_list_extensions(self):
reply = self.conn.core.ListExtensions().reply()
exts = [ext.name.to_string() for ext in reply.names]
assert "XVideo" in exts
def test_create_window(self):
wid = self.conn.generate_id()
cookie = self.create_window(wid=wid)
cookie = self.xproto.GetGeometry(wid)
reply = cookie.reply()
assert reply.x == 0
assert reply.y == 0
assert reply.width == 1
assert reply.height == 1
@raises(xcffib.XcffibException)
def test_wait_for_nonexistent_request(self):
self.conn.wait_for_reply(10)
def test_no_windows(self):
# Make sure there aren't any windows in the root window. This mostly
# just exists to make sure people aren't somehow mistakenly running a
# test in their own X session, which could corrupt results.
reply = self.xproto.QueryTree(self.default_screen.root).reply()
assert reply.children_len == 0
assert len(reply.children) == 0
def test_create_window_creates_window(self):
wid = self.conn.generate_id()
self.create_window(wid=wid)
reply = self.xproto.QueryTree(self.default_screen.root).reply()
assert reply.children_len == 1
assert len(reply.children) == 1
assert reply.children[0] == wid
@raises(AssertionError)
def test_checking_unchecked_fails(self):
wid = self.conn.generate_id()
self.create_window(wid)
self.xproto.QueryTreeUnchecked(self.default_screen.root).check()
@raises(AssertionError)
def test_checking_default_checked_fails(self):
wid = self.conn.generate_id()
self.create_window(wid)
cookie = self.xproto.QueryTree(self.default_screen.root)
cookie.check()
def test_checking_foreced_checked_succeeds(self):
wid = self.conn.generate_id()
cookie = self.create_window(wid, is_checked=True)
cookie.check()
def test_create_window_generates_event(self):
self.xeyes()
self.conn.flush()
e = self.conn.wait_for_event()
assert isinstance(e, xcffib.xproto.CreateNotifyEvent)
@raises(xcffib.xproto.WindowError)
def test_query_invalid_wid_generates_error(self):
# query a bad WINDOW
self.xproto.QueryTree(0xf00).reply()
def test_OpenFont(self):
fid = self.conn.generate_id()
self.xproto.OpenFont(fid, len("cursor"), "cursor")
def test_ConfigureWindow(self):
wid = self.conn.generate_id()
self.create_window(wid=wid)
self.xproto.ConfigureWindowChecked(wid, 0, []).check()
def test_external_ConfigureWindow(self):
self.xeyes()
self.conn.flush()
e = self.conn.wait_for_event()
r = self.xproto.ConfigureWindowChecked(e.window, 0, []).check()
r = self.xproto.DestroyWindowChecked(e.window).check()
def test_ChangeProperty_WM_NAME(self):
wid = self.conn.generate_id()
self.create_window(wid=wid)
title = "test"
self.xproto.ChangeProperty(xcffib.xproto.PropMode.Replace, wid,
xcffib.xproto.Atom.WM_NAME, xcffib.xproto.Atom.STRING, 8,
len(title), title)
reply = self.xproto.GetProperty(False, wid,
xcffib.xproto.Atom.WM_NAME, xcffib.xproto.GetPropertyType.Any, 0, 1).reply()
assert reply.value.to_string() == title
def test_ChangeProperty_NET_WM_NAME(self):
wid = self.conn.generate_id()
self.create_window(wid=wid)
net_wm_name = self.intern("_NET_WM_NAME")
utf8_string = self.intern("UTF8_STRING")
title_bytes = b"test\xc2\xb7"
title_string = six.u("test\u00B7")
# First check with an object already encoded as bytes
self.xproto.ChangeProperty(xcffib.xproto.PropMode.Replace, wid,
net_wm_name, utf8_string, 8,
len(title_bytes), title_bytes)
reply = self.xproto.GetProperty(False, wid,
net_wm_name, xcffib.xproto.GetPropertyType.Any, 0, (2 ** 32) - 1).reply()
assert reply.value.buf() == title_bytes
assert reply.value.to_utf8() == title_string
# Also check with a unicode string
self.xproto.ChangeProperty(xcffib.xproto.PropMode.Replace, wid,
net_wm_name, utf8_string, 8,
len(title_string.encode('utf-8')), title_string)
reply = self.xproto.GetProperty(False, wid,
net_wm_name, xcffib.xproto.GetPropertyType.Any, 0, (2 ** 32) - 1).reply()
assert reply.value.buf() == title_bytes
assert reply.value.to_utf8() == title_string
def test_ChangeProperty_WM_PROTOCOLS(self):
wid = self.conn.generate_id()
self.create_window(wid=wid)
wm_protocols = self.intern("WM_PROTOCOLS")
wm_delete_window = self.intern("WM_DELETE_WINDOW")
self.xproto.ChangeProperty(xcffib.xproto.PropMode.Replace, wid,
wm_protocols, xcffib.xproto.Atom.ATOM, 32,
1, (wm_delete_window,))
# For Python 2 only, make sure packing can handle both ints and longs
if six.PY2:
self.xproto.ChangeProperty(xcffib.xproto.PropMode.Replace, wid,
wm_protocols, xcffib.xproto.Atom.ATOM, 32,
1, (long(wm_delete_window),))
reply = self.xproto.GetProperty(False, wid, wm_protocols, xcffib.xproto.Atom.ATOM, 0, 1).reply()
assert reply.value.to_atoms() == (wm_delete_window,)
wm_take_focus = self.intern("WM_TAKE_FOCUS")
self.xproto.ChangeProperty(xcffib.xproto.PropMode.Replace, wid,
wm_protocols, xcffib.xproto.Atom.ATOM, 32,
1, struct.pack("=I", wm_take_focus))
reply = self.xproto.GetProperty(False, wid, wm_protocols, xcffib.xproto.Atom.ATOM, 0, 1).reply()
assert reply.value.to_atoms() == (wm_take_focus,)
def test_GetAtomName(self):
wm_protocols = "WM_PROTOCOLS"
atom = self.intern(wm_protocols)
atom_name = self.xproto.GetAtomName(atom).reply().name
assert atom_name.to_string() == wm_protocols
def test_KillClient(self):
self.xeyes()
self.conn.flush()
e1 = self.conn.wait_for_event()
self.xproto.KillClient(e1.window)
# one is MapRequest and the other is DestroyNotify, they may be in
# either order
for _ in range(2):
self.conn.flush()
k1 = self.conn.wait_for_event()
if isinstance(k1, xcffib.xproto.DestroyNotifyEvent):
assert e1.window == k1.window
return
assert False, "no DestroyNotifyEvent"
def test_connect(self):
c = xcffib.connect()
c.invalid()
assert c.has_error() == 0
c.disconnect()
def test_auth_connect(self):
authname = six.b("MIT-MAGIC-COOKIE-1")
authdata = six.b("\xa5\xcf\x95\xfa\x19\x49\x03\x60\xaf\xe4\x1e\xcd\xa3\xe2\xad\x47")
authstr = authname + six.b(':') + authdata
conn = xcffib.connect(display=os.environ['DISPLAY'], auth=authstr)
assert conn.get_setup().roots[0].root > 0
# This is an adaptation of the test from #27
def test_build_atom_cache(self):
# This will hold the forward *and* reverse lookups for any given atom
atoms = {}
cookies = []
# Batch the replies by creating a list of cookies first:
for i in range(1, 10000):
c = self.conn.core.GetAtomName(i)
cookies.append((i, c))
for i, c in cookies:
try:
name = c.reply().name.to_string()
except xcffib.xproto.BadAtom:
continue
atoms.update({i: name}) # Lookup by number
atoms.update({name: i}) # Lookup by name
def test_wrap(self):
c = xcffib.connect()
c.invalid()
c2 = xcffib.wrap(xcffib.ffi.cast("long", c._conn))
c2.invalid()
c2.disconnect()
xcffib-0.3.6/tests/test_crazy_window_script.py 0000664 0000000 0000000 00000011644 12565733531 0021657 0 ustar 00root root 0000000 0000000 # Copyright 2012 Florian Mounier
# Copyright 2014 Sean Vig
# Copyright 2014 Tycho Andersen
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
"""
This is mostly stolen from qtile's tests/scripts/window.py
"""
from __future__ import print_function
import os
import sys
import struct
import time
import xcffib
import xcffib.xproto
from xcffib.xproto import EventMask
from xcffib.testing import XvfbTest
class TestWindow(XvfbTest):
def test_the_script(self):
NAME = "one"
for i in range(20):
try:
conn = xcffib.connect(os.environ['DISPLAY'])
except xcffib.ConnectionException:
time.sleep(0.1)
continue
except Exception as v:
print("Error opening test window: ", type(v), v, file=sys.stderr)
sys.exit(1)
break
else:
print("Could not open window on display %s" % (sys.argv[1]), file=sys.stderr)
sys.exit(1)
screen = conn.get_setup().roots[conn.pref_screen]
window = conn.generate_id()
background = conn.core.AllocColor(screen.default_colormap, 0x2828, 0x8383, 0xCECE).reply().pixel # Color "#2883ce"
conn.core.CreateWindow(xcffib.CopyFromParent, window, screen.root,
100, 100, 100, 100, 1,
xcffib.xproto.WindowClass.InputOutput, screen.root_visual,
xcffib.xproto.CW.BackPixel | xcffib.xproto.CW.EventMask,
[background, xcffib.xproto.EventMask.StructureNotify | xcffib.xproto.EventMask.Exposure])
conn.core.ChangeProperty(xcffib.xproto.PropMode.Replace,
window, xcffib.xproto.Atom.WM_NAME,
xcffib.xproto.Atom.STRING, 8, len(NAME),
NAME)
wm_protocols = "WM_PROTOCOLS"
wm_protocols = conn.core.InternAtom(0, len(wm_protocols), wm_protocols).reply().atom
wm_delete_window = "WM_DELETE_WINDOW"
wm_delete_window = conn.core.InternAtom(0, len(wm_delete_window), wm_delete_window).reply().atom
conn.core.ChangeProperty(xcffib.xproto.PropMode.Replace,
window, wm_protocols,
xcffib.xproto.Atom.ATOM, 32, 1,
[wm_delete_window])
conn.core.ConfigureWindow(window,
xcffib.xproto.ConfigWindow.X | xcffib.xproto.ConfigWindow.Y |
xcffib.xproto.ConfigWindow.Width | xcffib.xproto.ConfigWindow.Height |
xcffib.xproto.ConfigWindow.BorderWidth,
[0, 0, 100, 100, 1])
conn.core.MapWindow(window)
conn.flush()
conn.core.ConfigureWindow(window,
xcffib.xproto.ConfigWindow.X | xcffib.xproto.ConfigWindow.Y |
xcffib.xproto.ConfigWindow.Width | xcffib.xproto.ConfigWindow.Height |
xcffib.xproto.ConfigWindow.BorderWidth,
[0, 0, 100, 100, 1])
# now kill the window from the "wm" side via WM_DELETE_WINDOW protocol
WM_PROTOCOLS = self.conn.core.InternAtom(False, len("WM_PROTOCOLS"), "WM_PROTOCOLS").reply().atom
WM_DELETE_WINDOW = self.conn.core.InternAtom(False, len("WM_DELETE_WINDOW"), "WM_DELETE_WINDOW").reply().atom
vals = [
33, # ClientMessageEvent
32, # Format
0,
window,
WM_PROTOCOLS,
WM_DELETE_WINDOW,
xcffib.xproto.Time.CurrentTime,
0,
0,
0,
]
e = struct.pack('BBHII5I', *vals)
self.conn.core.SendEvent(False, window, EventMask.NoEvent, e)
self.conn.flush()
while 1:
conn.flush()
event = conn.wait_for_event()
if event.__class__ == xcffib.xproto.ClientMessageEvent:
atom = conn.core.GetAtomName(event.type).reply().name.to_string()
print(atom)
if atom == "WM_PROTOCOLS":
break
# This test passes if it gets all the way here without dying :-)
xcffib-0.3.6/tests/test_fakeinput.py 0000664 0000000 0000000 00000002075 12565733531 0017540 0 ustar 00root root 0000000 0000000 import xcffib
import xcffib.xproto
import xcffib.xtest
from .testing import XcffibTest
class TestConnection(XcffibTest):
def test_fakeinput(self):
xtest = self.conn(xcffib.xtest.key)
setup = self.conn.get_setup()
screen = setup.roots[0]
def test(x, y):
# motion
xtest.FakeInput(
6,
0,
xcffib.xproto.Time.CurrentTime,
screen.root,
x,
y,
0)
# press
xtest.FakeInput(
4,
1,
xcffib.xproto.Time.CurrentTime,
screen.root,
0,
0,
0)
# release
xtest.FakeInput(
5,
1,
xcffib.xproto.Time.CurrentTime,
screen.root,
2,
2,
0)
self.conn.flush()
test(50, 10)
# we shouldn't get any errors
self.conn.poll_for_event()
xcffib-0.3.6/tests/test_python_code.py 0000664 0000000 0000000 00000007050 12565733531 0020063 0 ustar 00root root 0000000 0000000 # Copyright 2014 Tycho Andersen
# Copyright 2014 Sean Vig
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import xcffib
import xcffib.xproto
import struct
from xcffib.xproto import EventMask
from .testing import XcffibTest
class TestPythonCode(XcffibTest):
def test_struct_pack_uses_List(self):
# suppose we have a list of ints...
ints = struct.pack("=IIII", *range(4))
# Unpacker wants a cffi.cdata
cffi_ints = xcffib.ffi.new('char[]', ints)
l = xcffib.List(xcffib.CffiUnpacker(cffi_ints), "I", count=4)
ints2 = struct.pack("=IIII", *l)
# after packing and unpacking, we should still have those ints
assert ints == ints2
def test_union_pack(self):
data = struct.pack("=" + ("b" * 20), *range(20))
cffi_data = xcffib.ffi.new('char[]', data)
cm = xcffib.xproto.ClientMessageData(xcffib.CffiUnpacker(cffi_data))
for actual, expected in zip(range(20), cm.data8):
assert actual == expected, actual
assert cm.data32[0] == 0x03020100
assert cm.data32[1] == 0x07060504
assert cm.data32[2] == 0x0b0a0908
def test_offset_map(self):
om = xcffib.OffsetMap({0: "Event0,0"})
om.add(1, {0: "Event1,0", 1: "Event1,1"})
assert om[0] == "Event0,0"
assert om[1] == "Event1,0"
assert om[2] == "Event1,1"
def test_create_ClientMessageEvent(self):
wm_protocols = self.intern("WM_PROTOCOLS")
wm_delete_window = self.intern("WM_DELETE_WINDOW")
# should be exactly 20 bytes
data = [
wm_delete_window,
xcffib.xproto.Time.CurrentTime,
0,
0,
0,
]
union = xcffib.xproto.ClientMessageData.synthetic(data, "I" * 5)
assert list(union.data32) == data
wid = self.conn.generate_id()
self.create_window(wid=wid)
wm_protocols = self.intern("WM_PROTOCOLS")
wm_delete_window = self.intern("WM_DELETE_WINDOW")
e = xcffib.xproto.ClientMessageEvent.synthetic(
format=32,
window=wid,
type=wm_protocols,
data=union
)
self.xproto.SendEvent(False, wid, EventMask.NoEvent, e.pack())
self.conn.flush()
e = self.conn.wait_for_event()
assert isinstance(e, xcffib.xproto.ClientMessageEvent)
assert e.window == wid
assert list(e.data.data32) == data
def test_pack_from_event(self):
wm_protocols = self.intern("WM_PROTOCOLS")
wm_delete_window = self.intern("WM_DELETE_WINDOW")
wid = self.conn.generate_id()
# should be exactly 20 bytes
data = [
wm_delete_window,
xcffib.xproto.Time.CurrentTime,
0,
0,
0,
]
union = xcffib.xproto.ClientMessageData.synthetic(data, "I" * 5)
e = xcffib.xproto.ClientMessageEvent.synthetic(
format=32,
window=wid,
type=wm_protocols,
data=union
)
e2 = xcffib.xproto.ClientMessageEvent(e)
xcffib-0.3.6/tests/testing.py 0000664 0000000 0000000 00000004246 12565733531 0016172 0 ustar 00root root 0000000 0000000 # Copyright 2014 Tycho Andersen
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import xcffib
from xcffib.testing import XvfbTest
from xcffib.xproto import EventMask
class XcffibTest(XvfbTest):
""" A home for common functions needed for xcffib testing. """
def setUp(self):
XvfbTest.setUp(self)
self.xproto = xcffib.xproto.xprotoExtension(self.conn)
def tearDown(self):
self.xproto = None
XvfbTest.tearDown(self)
@property
def default_screen(self):
return self.conn.setup.roots[self.conn.pref_screen]
def create_window(self, wid=None, x=0, y=0, w=1, h=1, is_checked=False):
if wid is None:
wid = self.conn.generate_id()
return self.xproto.CreateWindow(
self.default_screen.root_depth,
wid,
self.default_screen.root,
x, y, w, h,
0,
xcffib.xproto.WindowClass.InputOutput,
self.default_screen.root_visual,
xcffib.xproto.CW.BackPixel | xcffib.xproto.CW.EventMask,
[
self.default_screen.black_pixel,
xcffib.xproto.EventMask.StructureNotify
],
is_checked=is_checked
)
def xeyes(self):
# Enable CreateNotify
self.xproto.ChangeWindowAttributes(
self.default_screen.root,
xcffib.xproto.CW.EventMask,
[
EventMask.SubstructureNotify |
EventMask.StructureNotify |
EventMask.SubstructureRedirect
]
)
self.spawn(['xeyes'])
def intern(self, name):
return self.xproto.InternAtom(False, len(name), name).reply().atom
xcffib-0.3.6/xcffib.cabal 0000664 0000000 0000000 00000005076 12565733531 0015230 0 ustar 00root root 0000000 0000000 name: xcffib
version: 0.3.6
synopsis: A cffi-based python binding for X
homepage: http://github.com/tych0/xcffib
license: OtherLicense
license-file: LICENSE
author: Tycho Andersen
maintainer: Tycho Andersen
category: X11
build-type: Simple
cabal-version: >=1.8
bug-reports: https://github.com/tych0/xcffib/issues
description: A cffi-based python binding for X, comparable to xpyb
extra-source-files: tests/generator/*.py,
tests/generator/*.xml,
-- cabal's wildcarding is broken if the filename contains
-- extra dots:
-- https://github.com/haskell/cabal/issues/784
tests/generator/*.7.py,
tests/generator/*.7.xml
source-repository head
type: git
location: git://github.com/tych0/xcffib.git
library
build-depends: base ==4.*,
xcb-types >= 0.7.0,
language-python >= 0.5.0,
filepath,
filemanip,
split,
containers,
mtl >= 2.1,
attoparsec,
bytestring
hs-source-dirs: generator
exposed-modules: Data.XCB.Python.Parse,
Data.XCB.Python.PyHelpers
ghc-options: -Wall
executable xcffibgen
main-is: xcffibgen.hs
hs-source-dirs: generator
build-depends: base ==4.*,
xcffib >= 0.1.0,
language-python >= 0.5.0,
split,
xcb-types >= 0.7.0,
optparse-applicative >= 0.5,
filepath,
filemanip,
directory >= 1.2,
containers,
mtl >= 2.1,
attoparsec,
bytestring
ghc-options: -Wall
test-suite PyHelpersTests
hs-source-dirs: tests
main-is: PyHelpersTests.hs
type: exitcode-stdio-1.0
build-depends: base ==4.*,
xcffib >= 0.1.0,
language-python >= 0.5.0,
HUnit,
test-framework,
test-framework-hunit
test-suite GeneratorTests.hs
hs-source-dirs: tests
main-is: GeneratorTests.hs
type: exitcode-stdio-1.0
build-depends: base ==4.*,
xcffib >= 0.1.0,
xcb-types >= 0.7.0,
language-python >= 0.5.0,
HUnit,
test-framework,
test-framework-hunit,
filepath