Discussion:
[Xcb] add support for using events as part of requests
Christian Linhart
2017-01-25 09:57:34 UTC
Permalink
Hi all,

I have added a new xml-element called "eventstruct".

This makes it possible to use events as part of requests.

This is, e.g., needed by the SendExtensionEvent request
of the XINPUT extension.

In this thread, I'll post the patches for that.

There is a testcase attached to this email.

Chris
Christian Linhart
2017-01-25 10:18:06 UTC
Permalink
eventstruct is a new xml element that allows to use events
as part of requests.

This is, e.g., needed by the SendExtensionEvent request
of the XINPUT extension.

Signed-off-by: Christian Linhart <***@demorecorder.com>
---
doc/xml-xcb.txt | 29 +++++++++++++++++++
src/xcb.xsd | 17 +++++++++++
xcbgen/matcher.py | 7 +++++
xcbgen/state.py | 41 ++++++++++++++++++++++++++
xcbgen/xtypes.py | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 181 insertions(+)

diff --git a/doc/xml-xcb.txt b/doc/xml-xcb.txt
index 9cef1de..f5b9aed 100644
--- a/doc/xml-xcb.txt
+++ b/doc/xml-xcb.txt
@@ -72,14 +72,20 @@ Top-Level Elements

This element represents a union of data types, which can hold one value of
any of those types. The name attribute gives the name of the union. The
content represents the fields of the union, and consists of one or more of
the field and pad elements described in the section "Structure Contents
below".

+<eventstruct name="identifier">event-type-selector list</struct>
+
+ This element represents a data structure that is the wire-representation of
+ an event. The event can be any type that's selected by the
+ event-type-selector list.
+
<xidtype name="identifier" />

This element represents an identifier for a particular type of resource.
The name attribute gives the name of the new type.

<enum name="identifier">
<item name="identifier">[optional expression]</item>
@@ -355,14 +361,37 @@ Expressions
This element represents the number of bits set in the expression.

<listelement-ref/>

This element represents the current list-element when used inside
a list-iteration expression such as <sumof>.

+
+Event-Type-Selector List
+------------------------
+
+ The event-type-selector list selects a set of eventtypes.
+ It consists of any number of the following elements:
+
+ <allowed extension="identifier" xge="boolean"
+ opcode-min="integer" opcode-max="integer" />
+
+ The extension attribute selects events from the given extension.
+
+ If the xge attribute is true, the event is an X Generic Event and
+ will be treated as such.
+
+ opcode-min and opcode-max describe the minimum and maximum opcode
+ respectively. The opcode is the same number as the number-attribute
+ of an event definition. I.e. this is the offset from the event-base
+ to the actual number used on the wire.
+
+ In the current implementation, only xge="false" is supported.
+
+
Documentation
-------------

Documentation for each request, reply or event is stored in the appropriate
element using a <doc> element. The <doc> element can contain the following
elements:

diff --git a/src/xcb.xsd b/src/xcb.xsd
index f0c5f44..dc3d7cc 100644
--- a/src/xcb.xsd
+++ b/src/xcb.xsd
@@ -236,14 +236,30 @@ authorization from the authors.
<!-- Type for a packet structure copy -->
<xsd:complexType name="packet-struct-copy">
<xsd:attribute name="name" type="xsd:string" use="required" />
<xsd:attribute name="number" type="xsd:integer" use="required" />
<xsd:attribute name="ref" type="xsd:string" use="required" />
</xsd:complexType>

+ <!-- Type for a structure that is an event
+ which can be of an event type from a set of event types -->
+ <xsd:complexType name="eventstruct">
+ <xsd:sequence>
+ <xsd:element name="allowed">
+ <xsd:complexType>
+ <xsd:attribute name="extension" type="xsd:string" use="required" />
+ <xsd:attribute name="xge" type="xsd:boolean" use="required" />
+ <xsd:attribute name="opcode-min" type="xsd:integer" use="required" />
+ <xsd:attribute name="opcode-max" type="xsd:integer" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+
<!-- Type for bit values -->
<xsd:simpleType name="bitType">
<xsd:restriction base="xsd:integer">
<xsd:minInclusive value="0" />
<xsd:maxExclusive value="32" />
</xsd:restriction>
</xsd:simpleType>
@@ -350,14 +366,15 @@ authorization from the authors.
</xsd:complexType>
</xsd:element>
<xsd:element name="eventcopy" type="packet-struct-copy" />
<xsd:element name="error" type="packet-struct" />
<xsd:element name="errorcopy" type="packet-struct-copy" />
<xsd:element name="struct" type="struct" />
<xsd:element name="union" type="struct" />
+ <xsd:element name="eventstruct" type="eventstruct" />
<xsd:element name="xidtype">
<xsd:complexType>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
<xsd:element name="xidunion">
<xsd:complexType>
diff --git a/xcbgen/matcher.py b/xcbgen/matcher.py
index bfa315e..97a8b43 100644
--- a/xcbgen/matcher.py
+++ b/xcbgen/matcher.py
@@ -53,14 +53,20 @@ def enum(node, module, namespace):

def struct(node, module, namespace):
id = node.get('name')
name = namespace.prefix + (id,)
type = Struct(name, node)
module.add_type(id, namespace.ns, name, type)

+def eventstruct(node, module, namespace):
+ id = node.get('name')
+ name = namespace.prefix + (id,)
+ type = EventStruct(name, node)
+ module.add_type(id, namespace.ns, name, type)
+
def union(node, module, namespace):
id = node.get('name')
name = namespace.prefix + (id,)
type = Union(name, node)
module.add_type(id, namespace.ns, name, type)

def request(node, module, namespace):
@@ -99,14 +105,15 @@ def errorcopy(node, module, namespace):

funcs = {'import' : import_,
'typedef' : typedef,
'xidtype' : xidtype,
'xidunion' : xidunion,
'enum' : enum,
'struct' : struct,
+ 'eventstruct' : eventstruct,
'union' : union,
'request' : request,
'event' : event,
'eventcopy' : eventcopy,
'error' : error,
'errorcopy' : errorcopy}

diff --git a/xcbgen/state.py b/xcbgen/state.py
index a6ad3a1..a8346bb 100644
--- a/xcbgen/state.py
+++ b/xcbgen/state.py
@@ -28,28 +28,42 @@ class Namespace(object):
self.dir = dirname(filename)
self.file = basename(filename)

# Parse XML
self.root = parse(filename).getroot()
self.header = self.root.get('header')
self.ns = self.header + ':'
+
+ # Events
+ self.events = {}

# Get root element attributes
if self.root.get('extension-xname', False):
self.is_ext = True
self.major_version = self.root.get('major-version')
self.minor_version = self.root.get('minor-version')
self.ext_xname = self.root.get('extension-xname')
self.ext_name = self.root.get('extension-name')
self.prefix = ('xcb', self.ext_name)
else:
self.is_ext = False
self.ext_name = ''
self.prefix = ('xcb',)

+ def add_event(self, id, name, item):
+ self.events[id] = (name, item)
+
+ def get_event_by_opcode(self, opcode, is_ge_event):
+ for id, (name, event) in self.events.items():
+ if event.is_ge_event == is_ge_event:
+ opcode_specific_name = event.get_name_for_opcode( opcode )
+ if opcode_specific_name is not None:
+ return (opcode_specific_name, event)
+ return None
+

class Module(object):
'''
This is the grand, encompassing class that represents an entire XCB specification.
Only gets instantiated once, in the main() routine.

Don't need to worry about this much except to declare it and to get the namespace.
@@ -68,14 +82,19 @@ class Module(object):
self.direct_imports = []
self.import_level = 0
self.types = {}
self.events = {}
self.errors = {}
self.all = []

+ # dict of namespaces by ext_name
+ self.namespaces = {}
+ # enter the main namespace here
+ self.namespaces[self.namespace.ext_name] = self.namespace
+
# Register some common types
self.add_type('CARD8', '', ('uint8_t',), tcard8)
self.add_type('CARD16', '', ('uint16_t',), tcard16)
self.add_type('CARD32', '', ('uint32_t',), tcard32)
self.add_type('CARD64', '', ('uint64_t',), tcard64)
self.add_type('INT8', '', ('int8_t',), tint8)
self.add_type('INT16', '', ('int16_t',), tint16)
@@ -90,14 +109,15 @@ class Module(object):

# This goes out and parses the rest of the XML
def register(self):
matcher.execute(self, self.namespace)

# Recursively resolve all types
def resolve(self):
+ self.add_events_to_namespaces()
for (name, item) in self.all:
self.pads = 0
item.resolve(self)

# Call all the output methods
def generate(self):
self.open()
@@ -108,14 +128,15 @@ class Module(object):
self.close()

# Keeps track of what's been imported so far.
def add_import(self, name, namespace):
if self.import_level == 0:
self.direct_imports.append((name, namespace.header))
self.imports.append((name, namespace.header))
+ self.namespaces[namespace.ext_name] = namespace

def has_import(self, name):
for (name_, header) in self.imports:
if name_ == name:
return True
return False

@@ -145,25 +166,45 @@ class Module(object):

def get_type(self, id):
return self.get_type_impl(id, 1)

def get_type_name(self, id):
return self.get_type_impl(id, 0)

+ def get_namespace(self, ext_name):
+ return self.namespaces[ext_name]
+
# Keeps track of request datatypes
def add_request(self, id, name, item):
if name[:-1] == self.namespace.prefix:
self.all.append((name, item))

# Keeps track of event datatypes
def add_event(self, id, name, item):
self.events[id] = (name, item)
if name[:-1] == self.namespace.prefix:
self.all.append((name, item))

+
+ def add_events_to_namespaces(self):
+ # add to its namespace object
+ for id, (name,item) in self.events.items():
+ if name[:-1] == ('xcb',):
+ # core event
+ namespace_name = ''
+ else:
+ # extension event
+ namespace_name = name[-2]
+
+ namespace = self.namespaces[namespace_name]
+
+ if namespace is not None:
+ namespace.add_event(id, name, item)
+
+
def get_event(self, id):
return self.events[id][1]

# Keeps track of error datatypes
def add_error(self, id, name, item):
self.errors[id] = (name, item)
if name[:-1] == self.namespace.prefix:
diff --git a/xcbgen/xtypes.py b/xcbgen/xtypes.py
index b83b119..c1f5986 100644
--- a/xcbgen/xtypes.py
+++ b/xcbgen/xtypes.py
@@ -32,14 +32,16 @@ class Type(object):
self.is_simple = False
self.is_list = False
self.is_expr = False
self.is_container = False
self.is_reply = False
self.is_union = False
self.is_pad = False
+ self.is_eventstruct = False
+ self.is_event = False
self.is_switch = False
self.is_case_or_bitcase = False
self.is_bitcase = False
self.is_case = False
self.required_start_align = Alignment()

# the biggest align value of an align-pad contained in this type
@@ -1160,14 +1162,90 @@ class Request(ComplexType):

if self.reply:
self.reply.resolve(module)

out = __main__.output['request']


+class EventStructAllowedRule:
+
+ def __init__(self, parent, elt):
+ self.elt = elt
+ self.extension = elt.get('extension')
+ self.ge_events = elt.get('xge') == "true"
+ self.min_opcode = int( elt.get('opcode-min') )
+ self.max_opcode = int( elt.get('opcode-max') )
+
+ def resolve(self, parent, module):
+ # get the namespace of the specified extension
+ extension_namespace = module.get_namespace( self.extension )
+ if extension_namespace is None:
+ raise Exception( "EventStructAllowedRule.resolve: cannot find extension \"" + self.extension + "\"" )
+ return
+
+ # find and add the selected events
+ for opcode in range(self.min_opcode, self.max_opcode):
+ name_and_event = extension_namespace.get_event_by_opcode( opcode, self.ge_events )
+ if name_and_event is None:
+ # could not find event -> error handling
+ if self.ge_events:
+ raise Exception("EventStructAllowedRule.resolve: cannot find xge-event with opcode " + str(opcode) + " in extension " + self.extension )
+ else:
+ raise Exception("EventStructAllowedRule.resolve: cannot find oldstyle-event with opcode " + str(opcode) + " in extension " + self.extension )
+ return
+
+ ( name, event ) = name_and_event
+ # add event to EventStruct
+ parent.add_event( module, self.extension, opcode, name, event )
+
+
+class EventStruct(Union):
+ '''
+ Derived class representing an event-use-as-struct data type.
+ '''
+
+ def __init__(self, name, elt):
+ Union.__init__(self, name, elt)
+ self.is_eventstruct = True
+ self.events = []
+ self.allowedRules = []
+ self.contains_ge_events = False
+ for item in list(elt):
+ if item.tag == 'allowed':
+ allowedRule = EventStructAllowedRule(self, item)
+ self.allowedRules.append( allowedRule )
+ if allowedRule.ge_events:
+ self.contains_ge_events = True
+
+ out = __main__.output['eventstruct']
+
+ def resolve(self, module):
+ if self.resolved:
+ return
+ for allowedRule in self.allowedRules:
+ allowedRule.resolve(self, module)
+ Union.resolve(self,module)
+ self.resolved = True
+
+ # add event. called by resolve
+ def add_event(self, module, extension, opcode, name, event_type ):
+ self.events.append( (extension, opcode, name, event_type) )
+ # Add the field to ourself
+ event_type.make_member_of(module, self, name, name[-1], True, True, False)
+ # Recursively resolve the event (could be another structure, list)
+ event_type.resolve(module)
+
+ def fixed_size(self):
+ is_fixed_size = True
+ for extension, opcode, name, event in self.events:
+ if not event.fixed_size():
+ is_fixed_size = False
+ return is_fixed_size
+
+
class Event(ComplexType):
'''
Derived class representing an event data type.

Public fields added:
opcodes is a dictionary of name -> opcode number, for eventcopies.
'''
@@ -1179,24 +1257,33 @@ class Event(ComplexType):

self.opcodes = {}

self.has_seq = not bool(elt.get('no-sequence-number'))

self.is_ge_event = bool(elt.get('xge'))

+ self.is_event = True
+
self.doc = None
for item in list(elt):
if item.tag == 'doc':
self.doc = Doc(name, item)

def add_opcode(self, opcode, name, main):
self.opcodes[name] = opcode
if main:
self.name = name

+ def get_name_for_opcode(self, opcode):
+ for name, my_opcode in self.opcodes.items():
+ if int(my_opcode) == opcode:
+ return name
+ else:
+ return None
+
def resolve(self, module):
def add_event_header():
self.fields.append(Field(tcard8, tcard8.name, 'response_type', False, True, True))
if self.has_seq:
self.fields.append(_placeholder_byte)
self.fields.append(Field(tcard16, tcard16.name, 'sequence', False, True, True))
--
2.1.4
Christian Linhart
2017-01-25 10:18:07 UTC
Permalink
Use the eventstruct element to define the SendExtensionEvent request
instead of using a byte-array.

This has the advantage that the structure of the data to be sent
is now defined in the xml definition.
This can be used by generators to make sending events safer.
Such as avoiding type-casts in C.

It can also be useful for protocol analyzers and tools like that
because the structure of the sent events is now defined in the xml-definition.

Tested-by: Christian Linhart <***@demorecorder.com>
Signed-off-by: Christian Linhart <***@demorecorder.com>
---
src/xinput.xml | 57 ++++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 38 insertions(+), 19 deletions(-)

diff --git a/src/xinput.xml b/src/xinput.xml
index c0b497e..9a35e9d 100644
--- a/src/xinput.xml
+++ b/src/xinput.xml
@@ -983,33 +983,16 @@ <request name="QueryDeviceState" opcode="30">
<pad bytes="23" />
<list type="InputState" name="classes">
<fieldref>num_classes</fieldref>
</list>
</reply>
</request>

- <!-- SendExtensionEvent -->
-
- <request name="SendExtensionEvent" opcode="31">
- <field type="WINDOW" name="destination" />
- <field type="CARD8" name="device_id" />
- <field type="BOOL" name="propagate" />
- <field type="CARD16" name="num_classes" />
- <field type="CARD8" name="num_events" />
- <pad bytes="3" />
- <list type="CARD8" name="events">
- <op op="*">
- <fieldref>num_events</fieldref>
- <value>32</value>
- </op>
- </list>
- <list type="EventClass" name="classes">
- <fieldref>num_classes</fieldref>
- </list>
- </request>
+ <!-- SendExtensionEvent (opcode 16) has to be defined after the events
+ because we do not support backward references -->

<!-- DeviceBell -->

<request name="DeviceBell" opcode="32">
<field type="CARD8" name="device_id" />
<field type="CARD8" name="feedback_id" />
<field type="CARD8" name="feedback_class" />
@@ -2638,14 +2621,50 @@ <event name="BarrierHit" number="25" xge="true">
<field type="FP1616" name="root_y" />
<field type="FP3232" name="dx" />
<field type="FP3232" name="dy" />
</event>

<eventcopy name="BarrierLeave" number="26" ref="BarrierHit" />

+ <!-- ⋅⋅⋅ Requests that depend on events ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ -->
+
+ <!-- SendExtensionEvent -->
+ <eventstruct name="EventForSend">
+ <allowed extension="Input" xge="false" opcode-min="0" opcode-max="16" />
+ <!-- We need not allow the newer events which are based on
+ the GenericEvent extension:
+ The wire-protocol-spec
+ https://cgit.freedesktop.org/xorg/lib/libXi/tree/specs/encoding.xml?idĺibXi-1.7.9#n1793
+ only allows fixed sized events, which seems
+ to rule out GenericEvent.
+
+ The xlib-implementation also assumes fixed-sized events.
+ https://cgit.freedesktop.org/xorg/lib/libXi/tree/src/XSndExEv.c?id=libXi-1.7.9#n106
+
+ The Xserver also allows only non-GE events:
+ https:g/xorg/xserver/tree/Xi/sendexev.c?id=xorg-server-1.19.1#n144
+ -->
+ </eventstruct>
+
+ <request name="SendExtensionEvent" opcode="31">
+ <field type="WINDOW" name="destination" />
+ <field type="CARD8" name="device_id" />
+ <field type="BOOL" name="propagate" />
+ <field type="CARD16" name="num_classes" />
+ <field type="CARD8" name="num_events" />
+ <pad bytes="3" />
+ <list type="EventForSend" name="events">
+ <fieldref>num_events</fieldref>
+ </list>
+ <list type="EventClass" name="classes">
+ <fieldref>num_classes</fieldref>
+ </list>
+ </request>
+
+
<!-- ⋅⋅⋅ Errors (v1.0) ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ -->

<error name="Device" number="0" />
<error name="Event" number="1" />
<error name="Mode" number="2" />
<error name="DeviceBusy" number="3" />
<error name="Class" number="4" />
--
2.1.4
Christian Linhart
2017-01-25 10:20:38 UTC
Permalink
eventstruct allows to use events as part of requests.
This is, e.g., needed by xcb_input_send_extension_event.

Signed-off-by: Christian Linhart <***@demorecorder.com>
---
src/c_client.py | 32 +++++++++++++++++++++++++++++++-
src/xcb.h | 12 ++++++++++++
2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/src/c_client.py b/src/c_client.py
index b0eb47c..0cbdf30 100644
--- a/src/c_client.py
+++ b/src/c_client.py
@@ -433,15 +433,19 @@ def _c_type_setup(self, name, postfix):

self.c_container = 'union' if self.is_union else 'struct'
prev_varsized_field = None
prev_varsized_offset = 0
first_field_after_varsized = None

for field in self.fields:
- field.c_field_type = _t(field.field_type)
+ if field.type.is_event:
+ field.c_field_type = _t(field.field_type + ('event',))
+ else:
+ field.c_field_type = _t(field.field_type)
+
field.c_field_const_type = ('' if field.type.nmemb == 1 else 'const ') + field.c_field_type
field.c_field_name = _cpp(field.field_name)
field.c_subscript = '[%d]' % field.type.nmemb if (field.type.nmemb and field.type.nmemb > 1) else ''
field.c_pointer = ' ' if field.type.nmemb == 1 else '*'

# correct the c_pointer field for variable size non-list types
if not field.type.fixed_size() and field.c_pointer == ' ':
@@ -3152,14 +3156,36 @@ def c_request(self, name):
_c_accessors_list(self, field)
elif _c_field_needs_field_accessor(field):
_c_accessors_field(self, field)
# We generate the manpage afterwards because _c_type_setup has been called.
# TODO: what about aux helpers?
_man_request(self, name, void=not self.reply, aux=False)

+
+def c_eventstruct(self, name):
+ #add fields that are needed to get the event-type in a generic way
+ self.fields.append( Field( tevent, tevent.name, 'event_header', False, True, True) )
+
+ if self.contains_ge_events:
+ #TODO: add header of ge-events as an extra field
+ raise Exception( 'eventstructs with ge-events are not yet supported' )
+
+ _c_type_setup(self, name, ())
+
+ #correct the format of the field names
+ for field in self.fields:
+ field.c_field_name = _n_item(field.c_field_name).lower()
+
+ _c_complex(self)
+ _c_iterator(self, name)
+
+ if not self.fixed_size():
+ #TODO: Create sizeof function (and maybe other accessors) for var-sized eventstructs
+ raise Exception( 'var sized eventstructs are not yet supported' )
+
def c_event(self, name):
'''
Exported function that handles event declarations.
'''

# The generic event structure xcb_ge_event_t has the full_sequence field
# at the 32byte boundary. That's why we've to inject this field into GE
@@ -3249,14 +3275,15 @@ def c_error(self, name):
output = {'open' : c_open,
'close' : c_close,
'simple' : c_simple,
'enum' : c_enum,
'struct' : c_struct,
'union' : c_union,
'request' : c_request,
+ 'eventstruct' : c_eventstruct,
'event' : c_event,
'error' : c_error,
}

# Boilerplate below this point

# Check for the argument that specifies path to the xcbgen python package.
@@ -3292,14 +3319,17 @@ Failed to load the xcbgen Python package!
Make sure that xcb/proto installed it on your Python path.
If not, you will need to create a .pth file or define $PYTHONPATH
to extend the path.
Refer to the README file in xcb/proto for more info.
''')
raise

+# predefined datatype globals.
+tevent = SimpleType(('xcb_raw_generic_event_t',), 32)
+
# Ensure the man subdirectory exists
try:
os.mkdir('man')
except OSError as e:
if e.errno != errno.EEXIST:
raise

diff --git a/src/xcb.h b/src/xcb.h
index 6873e79..cbc0f2b 100644
--- a/src/xcb.h
+++ b/src/xcb.h
@@ -139,14 +139,26 @@ typedef struct {
uint8_t pad0; /**< Padding */
uint16_t sequence; /**< Sequence number */
uint32_t pad[7]; /**< Padding */
uint32_t full_sequence; /**< full sequence */
} xcb_generic_event_t;

/**
+ * @brief Raw Generic event.
+ *
+ * A generic event structure as used on the wire, i.e., without the full_sequence field
+ */
+typedef struct {
+ uint8_t response_type; /**< Type of the response */
+ uint8_t pad0; /**< Padding */
+ uint16_t sequence; /**< Sequence number */
+ uint32_t pad[7]; /**< Padding */
+} xcb_raw_generic_event_t;
+
+/**
* @brief GE event
*
* An event as sent by the XGE extension. The length field specifies the
* number of 4-byte blocks trailing the struct.
*
* @deprecated Since some fields in this struct have unfortunate names, it is
* recommended to use xcb_ge_generic_event_t instead.
--
2.1.4
Christian Linhart
2017-03-11 10:31:40 UTC
Permalink
I have just pushed this series.

These patches have had enough time for review, therefore applying review-by-crickets.

Chris
Post by Christian Linhart
Hi all,
I have added a new xml-element called "eventstruct".
This makes it possible to use events as part of requests.
This is, e.g., needed by the SendExtensionEvent request
of the XINPUT extension.
In this thread, I'll post the patches for that.
There is a testcase attached to this email.
Chris
_______________________________________________
Xcb mailing list
https://lists.freedesktop.org/mailman/listinfo/xcb
Bart Massey
2017-03-11 18:26:41 UTC
Permalink
Christian, thanks huge for this patch series. It all looks good to me.
Post by Christian Linhart
I have just pushed this series.
These patches have had enough time for review, therefore applying review-by-crickets.
Chris
Post by Christian Linhart
Hi all,
I have added a new xml-element called "eventstruct".
This makes it possible to use events as part of requests.
This is, e.g., needed by the SendExtensionEvent request
of the XINPUT extension.
In this thread, I'll post the patches for that.
There is a testcase attached to this email.
Chris
_______________________________________________
Xcb mailing list
https://lists.freedesktop.org/mailman/listinfo/xcb
_______________________________________________
Xcb mailing list
https://lists.freedesktop.org/mailman/listinfo/xcb
Loading...