Skip to content

Commit 4d74aab

Browse files
committed
Revert "cffi api mode"
This reverts commit fb83a36. This fanciness unfortunately does not work transparently to library consumers like cairocffi, so they will need some patches to understand this before we can release with it. This "fixes" github issue #179, but I'm going to leave it open so we can have the discussion about how to fix it there.
1 parent 32209df commit 4d74aab

File tree

8 files changed

+266
-372
lines changed

8 files changed

+266
-372
lines changed

.github/workflows/ci.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,6 @@ jobs:
2525
with:
2626
ghc-version: '9.6'
2727
cabal-version: latest
28-
- run: sudo apt install x11-apps libxcb1-dev libxcb-render0-dev
28+
- run: sudo apt install x11-apps
2929
- run: git clone https://gitlab.freedesktop.org/xorg/proto/xcbproto.git proto && cd proto && git checkout ${{ matrix.xcbver }}
3030
- run: make -j XCBDIR=./proto/src check

Makefile

+6-11
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,16 @@ ifneq ($(XCBDIR),$(shell pkg-config --variable=xcbincludedir xcb-proto))
66
else
77
XCBVER=$(shell pkg-config --modversion xcb-proto)
88
endif
9-
NCPUS=$(shell nproc)
9+
NCPUS=$(shell grep -c processor /proc/cpuinfo)
1010
PARALLEL=$(shell which parallel)
1111
CABAL=flock xcffib.cabal cabal
1212
GEN=$(CABAL) new-run --minimize-conflict-set -j$(NCPUS) exe:xcffibgen --
1313
VENV=xcffib_venv
1414
PYTHON=$(VENV)/bin/python3
1515
FLAKE=$(VENV)/bin/flake8
1616

17-
GENERATOR_FILES=$(shell find . -path ./test -prune -false -o -name \*.hs)
18-
HANDWRITTEN_MODULE_FILES=$(shell find ./module -name \*.py)
19-
2017
# you should have xcb-proto installed to run this
21-
xcffib: xcffib.cabal $(GENERATOR_FILES) $(HANDWRITTEN_MODULE_FILES)
18+
xcffib: module/*.py xcffib.cabal $(shell find . -path ./test -prune -false -o -name \*.hs)
2219
$(GEN) --input $(XCBDIR) --output ./xcffib
2320
cp ./module/*py ./xcffib/
2421
touch ./xcffib/py.typed
@@ -49,7 +46,7 @@ clean:
4946
-rm -rf .pc cabal.project.local*
5047

5148
valgrind: xcffib
52-
valgrind --leak-check=full --show-leak-kinds=definite $(PYTHON) -m pytest -v
49+
valgrind --leak-check=full --show-leak-kinds=definite pytest-3 -v
5350

5451
newtests:
5552
$(GEN) --input ./test/generator/ --output ./test/generator/
@@ -67,15 +64,13 @@ htests:
6764
$(VENV): requirements.txt
6865
# the python in $PATH in CI is the python from the matrix, so it is the
6966
# "right" python to start with
70-
python -m venv $(VENV)
67+
python3 -m venv $(VENV)
7168
$(PYTHON) -m pip install -r requirements.txt
7269

73-
check-mode-%: xcffib requirements.txt
74-
./test/test_mode.sh $*
75-
76-
check: xcffib htests lint check-mode-api check-mode-abi
70+
check: xcffib htests $(VENV) lint
7771
$(CABAL) check
7872
$(PYTHON) -m compileall xcffib
73+
$(PYTHON) -m pytest -v --durations=3 -n $(NCPUS)
7974

8075
# make release ver=0.99.99
8176
release: xcffib

module/__init__.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,24 @@
1515

1616
from __future__ import absolute_import, division
1717

18+
import ctypes.util
1819
import functools
1920
import io
21+
import platform
2022
import struct
2123
import weakref
2224

23-
from .ffi import ffi, lib, cffi_mode # noqa: F401
25+
from .ffi import ffi
26+
27+
if platform.system() == "Darwin":
28+
soname = "libxcb.dylib"
29+
elif platform.system() == "Windows":
30+
soname = "libxcb.dll"
31+
else:
32+
soname = ctypes.util.find_library("xcb")
33+
if soname is None:
34+
soname = "libxcb.so"
35+
lib = ffi.dlopen(soname)
2436

2537
__xcb_proto_version__ = 'placeholder'
2638
__version__ = 'placeholder'

module/ffi.py

+246-34
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,246 @@
1-
import ctypes.util
2-
import platform
3-
4-
# Attempt api mode, then precompiled abi mode, then import time abi
5-
cffi_mode = "(unknown)"
6-
try:
7-
# Note in ABI mode lib is already available, no dlopen() needed
8-
from ._xcffib import ffi, lib
9-
cffi_mode = "api"
10-
except ImportError:
11-
try:
12-
# Note in ABI mode lib will be missing
13-
from ._xcffib import ffi
14-
cffi_mode = "abi"
15-
except ImportError:
16-
# This means that someone is trying to import the module *without*
17-
# having run ffi_build.py. We could "just" build it for them via:
18-
# ffi = ffi_for_mode("abi")
19-
# but this is not an expected configuration, and it's hard to test, so
20-
# let's not support it for now.
21-
raise
22-
23-
# Fall back to non api mode, inline at load time
24-
# this would only happen if the precompiled _xcffib was missing
25-
if cffi_mode != "api":
26-
if platform.system() == "Darwin":
27-
soname = "libxcb.dylib"
28-
elif platform.system() == "Windows":
29-
soname = "libxcb.dll"
30-
else:
31-
soname = ctypes.util.find_library("xcb")
32-
if soname is None:
33-
soname = "libxcb.so"
34-
lib = ffi.dlopen(soname) # noqa
1+
# Copyright 2014 Tycho Andersen
2+
# Copyright 2014 Sean Vig
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
from cffi import FFI
17+
18+
CONSTANTS = [
19+
("X_PROTOCOL", 11),
20+
("X_PROTOCOL_REVISION", 0),
21+
("X_TCP_PORT", 6000),
22+
23+
("XCB_NONE", 0),
24+
("XCB_COPY_FROM_PARENT", 0),
25+
("XCB_CURRENT_TIME", 0),
26+
("XCB_NO_SYMBOL", 0),
27+
28+
("XCB_CONN_ERROR", 1),
29+
("XCB_CONN_CLOSED_EXT_NOTSUPPORTED", 2),
30+
("XCB_CONN_CLOSED_MEM_INSUFFICIENT", 3),
31+
("XCB_CONN_CLOSED_REQ_LEN_EXCEED", 4),
32+
("XCB_CONN_CLOSED_PARSE_ERR", 5),
33+
("XCB_CONN_CLOSED_INVALID_SCREEN", 6),
34+
("XCB_CONN_CLOSED_FDPASSING_FAILED", 7),
35+
36+
("XCB_REQUEST_CHECKED", 1 << 0)
37+
]
38+
39+
40+
# constants
41+
CDEF = '\n'.join("#define %s %d" % (c, v) for c, v in CONSTANTS)
42+
43+
# types
44+
CDEF += """
45+
// xcb.h
46+
typedef struct {
47+
uint8_t response_type; /**< Type of the response */
48+
uint8_t pad0; /**< Padding */
49+
uint16_t sequence; /**< Sequence number */
50+
uint32_t length; /**< Length of the response */
51+
} xcb_generic_reply_t;
52+
53+
typedef struct {
54+
uint8_t response_type; /**< Type of the response */
55+
uint8_t pad0; /**< Padding */
56+
uint16_t sequence; /**< Sequence number */
57+
uint32_t pad[7]; /**< Padding */
58+
uint32_t full_sequence; /**< full sequence */
59+
} xcb_generic_event_t;
60+
61+
typedef struct {
62+
uint8_t response_type; /**< Type of the response */
63+
uint8_t error_code; /**< Error code */
64+
uint16_t sequence; /**< Sequence number */
65+
uint32_t resource_id; /** < Resource ID for requests with side effects only */
66+
uint16_t minor_code; /** < Minor opcode of the failed request */
67+
uint8_t major_code; /** < Major opcode of the failed request */
68+
uint8_t pad0;
69+
uint32_t pad[5]; /**< Padding */
70+
uint32_t full_sequence; /**< full sequence */
71+
} xcb_generic_error_t;
72+
73+
typedef struct {
74+
unsigned int sequence; /**< Sequence number */
75+
} xcb_void_cookie_t;
76+
77+
typedef struct xcb_auth_info_t {
78+
int namelen;
79+
char *name;
80+
int datalen;
81+
char *data;
82+
} xcb_auth_info_t;
83+
84+
typedef ... xcb_connection_t;
85+
86+
// xproto.h
87+
typedef uint32_t xcb_colormap_t;
88+
typedef uint32_t xcb_drawable_t;
89+
typedef uint32_t xcb_pixmap_t;
90+
typedef uint32_t xcb_visualid_t;
91+
typedef uint32_t xcb_window_t;
92+
93+
typedef struct xcb_query_extension_reply_t {
94+
uint8_t response_type;
95+
uint8_t pad0;
96+
uint16_t sequence;
97+
uint32_t length;
98+
uint8_t present;
99+
uint8_t major_opcode;
100+
uint8_t first_event;
101+
uint8_t first_error;
102+
} xcb_query_extension_reply_t;
103+
104+
typedef struct xcb_setup_t {
105+
uint8_t status; /**< */
106+
uint8_t pad0; /**< */
107+
uint16_t protocol_major_version; /**< */
108+
uint16_t protocol_minor_version; /**< */
109+
uint16_t length; /**< */
110+
uint32_t release_number; /**< */
111+
uint32_t resource_id_base; /**< */
112+
uint32_t resource_id_mask; /**< */
113+
uint32_t motion_buffer_size; /**< */
114+
uint16_t vendor_len; /**< */
115+
uint16_t maximum_request_length; /**< */
116+
uint8_t roots_len; /**< */
117+
uint8_t pixmap_formats_len; /**< */
118+
uint8_t image_byte_order; /**< */
119+
uint8_t bitmap_format_bit_order; /**< */
120+
uint8_t bitmap_format_scanline_unit; /**< */
121+
uint8_t bitmap_format_scanline_pad; /**< */
122+
uint8_t min_keycode; /**< */
123+
uint8_t max_keycode; /**< */
124+
uint8_t pad1[4]; /**< */
125+
} xcb_setup_t;
126+
127+
typedef struct xcb_visualtype_t {
128+
xcb_visualid_t visual_id; /**< */
129+
uint8_t _class; /**< */
130+
uint8_t bits_per_rgb_value; /**< */
131+
uint16_t colormap_entries; /**< */
132+
uint32_t red_mask; /**< */
133+
uint32_t green_mask; /**< */
134+
uint32_t blue_mask; /**< */
135+
uint8_t pad0[4]; /**< */
136+
} xcb_visualtype_t;
137+
138+
typedef struct xcb_screen_t {
139+
xcb_window_t root; /**< */
140+
xcb_colormap_t default_colormap; /**< */
141+
uint32_t white_pixel; /**< */
142+
uint32_t black_pixel; /**< */
143+
uint32_t current_input_masks; /**< */
144+
uint16_t width_in_pixels; /**< */
145+
uint16_t height_in_pixels; /**< */
146+
uint16_t width_in_millimeters; /**< */
147+
uint16_t height_in_millimeters; /**< */
148+
uint16_t min_installed_maps; /**< */
149+
uint16_t max_installed_maps; /**< */
150+
xcb_visualid_t root_visual; /**< */
151+
uint8_t backing_stores; /**< */
152+
uint8_t save_unders; /**< */
153+
uint8_t root_depth; /**< */
154+
uint8_t allowed_depths_len; /**< */
155+
} xcb_screen_t;
156+
157+
typedef struct xcb_screen_iterator_t {
158+
xcb_screen_t *data; /**< */
159+
int rem; /**< */
160+
int index; /**< */
161+
} xcb_screen_iterator_t;
162+
163+
xcb_screen_iterator_t
164+
xcb_setup_roots_iterator (const xcb_setup_t *R /**< */);
165+
166+
void
167+
xcb_screen_next (xcb_screen_iterator_t *i /**< */);
168+
169+
// render.h
170+
typedef uint32_t xcb_render_pictformat_t;
171+
172+
typedef struct xcb_render_directformat_t {
173+
uint16_t red_shift; /**< */
174+
uint16_t red_mask; /**< */
175+
uint16_t green_shift; /**< */
176+
uint16_t green_mask; /**< */
177+
uint16_t blue_shift; /**< */
178+
uint16_t blue_mask; /**< */
179+
uint16_t alpha_shift; /**< */
180+
uint16_t alpha_mask; /**< */
181+
} xcb_render_directformat_t;
182+
183+
typedef struct xcb_render_pictforminfo_t {
184+
xcb_render_pictformat_t id; /**< */
185+
uint8_t type; /**< */
186+
uint8_t depth; /**< */
187+
uint8_t pad0[2]; /**< */
188+
xcb_render_directformat_t direct; /**< */
189+
xcb_colormap_t colormap; /**< */
190+
} xcb_render_pictforminfo_t;
191+
192+
// xcbext.h
193+
typedef struct xcb_extension_t {
194+
const char *name;
195+
int global_id;
196+
} xcb_extension_t;
197+
198+
typedef struct {
199+
size_t count;
200+
xcb_extension_t *ext;
201+
uint8_t opcode;
202+
uint8_t isvoid;
203+
} xcb_protocol_request_t;
204+
205+
// sys/uio.h
206+
struct iovec
207+
{
208+
void *iov_base; /* BSD uses caddr_t (1003.1g requires void *) */
209+
size_t iov_len; /* Must be size_t (1003.1g) */
210+
};
211+
212+
// need to manually free some things that XCB allocates
213+
void free(void *ptr);
214+
"""
215+
216+
# connection manipulation, mostly generated with:
217+
# grep -v '^[ \/\}#]' xcb.h | grep -v '^typedef' | grep -v '^extern'
218+
CDEF += """
219+
int xcb_flush(xcb_connection_t *c);
220+
uint32_t xcb_get_maximum_request_length(xcb_connection_t *c);
221+
void xcb_prefetch_maximum_request_length(xcb_connection_t *c);
222+
xcb_generic_event_t *xcb_wait_for_event(xcb_connection_t *c);
223+
xcb_generic_event_t *xcb_poll_for_event(xcb_connection_t *c);
224+
const xcb_query_extension_reply_t *xcb_get_extension_data(xcb_connection_t *c, xcb_extension_t *ext);
225+
const xcb_setup_t *xcb_get_setup(xcb_connection_t *c);
226+
int xcb_get_file_descriptor(xcb_connection_t *c);
227+
int xcb_connection_has_error(xcb_connection_t *c);
228+
xcb_connection_t *xcb_connect_to_fd(int fd, xcb_auth_info_t *auth_info);
229+
void xcb_disconnect(xcb_connection_t *c);
230+
int xcb_parse_display(const char *name, char **host, int *display, int *screen);
231+
xcb_connection_t *xcb_connect(const char *displayname, int *screenp);
232+
xcb_connection_t *xcb_connect_to_display_with_auth_info(const char *display, xcb_auth_info_t *auth, int *screen);
233+
uint32_t xcb_generate_id(xcb_connection_t *c);
234+
xcb_generic_error_t *xcb_request_check(xcb_connection_t *c, xcb_void_cookie_t cookie);
235+
"""
236+
237+
CDEF += """
238+
unsigned int xcb_send_request(xcb_connection_t *c, int flags, struct iovec *vector, const xcb_protocol_request_t *request);
239+
void *xcb_wait_for_reply(xcb_connection_t *c, unsigned int request, xcb_generic_error_t **e);
240+
int xcb_poll_for_reply(xcb_connection_t *c, unsigned int request, void **reply, xcb_generic_error_t **error);
241+
void xcb_discard_reply(xcb_connection_t *c, unsigned int sequence);
242+
"""
243+
244+
245+
ffi = FFI()
246+
ffi.cdef(CDEF)

0 commit comments

Comments
 (0)