summaryrefslogtreecommitdiff
path: root/chromium/ui/gfx/x/gen_xproto.py
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ui/gfx/x/gen_xproto.py')
-rw-r--r--chromium/ui/gfx/x/gen_xproto.py1124
1 files changed, 840 insertions, 284 deletions
diff --git a/chromium/ui/gfx/x/gen_xproto.py b/chromium/ui/gfx/x/gen_xproto.py
index 4a34901012d..24a2efcc245 100644
--- a/chromium/ui/gfx/x/gen_xproto.py
+++ b/chromium/ui/gfx/x/gen_xproto.py
@@ -23,15 +23,15 @@
# #include "base/component_export.h"
# #include "ui/gfx/x/xproto_types.h"
#
-# typedef struct _XDisplay XDisplay;
-#
# namespace x11 {
#
+# class Connection;
+#
# class COMPONENT_EXPORT(X11) XProto {
# public:
-# explicit XProto(XDisplay* display);
+# explicit XProto(Connection* connection);
#
-# XDisplay* display() { return display_; }
+# Connection* connection() const { return connection_; }
#
# struct RGB {
# uint16_t red{};
@@ -54,7 +54,7 @@
# Future<QueryColorsReply> QueryColors(const QueryColorsRequest& request);
#
# private:
-# XDisplay* display_;
+# Connection* const connection_;
# };
#
# } // namespace x11
@@ -66,12 +66,13 @@
# #include <xcb/xcb.h>
# #include <xcb/xcbext.h>
#
-# #include "base/logging.h"
+# #include "base/notreached.h"
+# #include "base/check_op.h"
# #include "ui/gfx/x/xproto_internal.h"
#
# namespace x11 {
#
-# XProto::XProto(XDisplay* display) : display_(display) {}
+# XProto::XProto(Connection* connection) : connection_(connection) {}
#
# Future<XProto::QueryColorsReply>
# XProto::QueryColors(
@@ -102,7 +103,7 @@
# Write(&pixels_elem, &buf);
# }
#
-# return x11::SendRequest<XProto::QueryColorsReply>(display_, &buf);
+# return x11::SendRequest<XProto::QueryColorsReply>(connection_, &buf);
# }
#
# template<> COMPONENT_EXPORT(X11)
@@ -168,6 +169,8 @@ from __future__ import print_function
import argparse
import collections
+import functools
+import itertools
import os
import re
import sys
@@ -177,61 +180,106 @@ import types
# so this global is unavoidable.
output = collections.defaultdict(int)
-UPPER_CASE_PATTERN = re.compile(r'^[A-Z0-9_]+$')
-
-
-def adjust_type_case(name):
- if UPPER_CASE_PATTERN.match(name):
- SPECIAL = {
- 'ANIMCURSORELT': 'AnimationCursorElement',
- 'CA': 'ChangeAlarmAttribute',
- 'CHAR2B': 'Char16',
- 'CHARINFO': 'CharInfo',
- 'COLORITEM': 'ColorItem',
- 'COLORMAP': 'ColorMap',
- 'CP': 'CreatePictureAttribute',
- 'CW': 'CreateWindowAttribute',
- 'DAMAGE': 'DamageId',
- 'DIRECTFORMAT': 'DirectFormat',
- 'DOTCLOCK': 'DotClock',
- 'FBCONFIG': 'FbConfig',
- 'FLOAT32': 'float',
- 'FLOAT64': 'double',
- 'FONTPROP': 'FontProperty',
- 'GC': 'GraphicsContextAttribute',
- 'GCONTEXT': 'GraphicsContext',
- 'GLYPHINFO': 'GlyphInfo',
- 'GLYPHSET': 'GlyphSet',
- 'INDEXVALUE': 'IndexValue',
- 'KB': 'Keyboard',
- 'KEYCODE': 'KeyCode',
- 'KEYCODE32': 'KeyCode32',
- 'KEYSYM': 'KeySym',
- 'LINEFIX': 'LineFix',
- 'OP': 'Operation',
- 'PBUFFER': 'PBuffer',
- 'PCONTEXT': 'PContext',
- 'PICTDEPTH': 'PictDepth',
- 'PICTFORMAT': 'PictFormat',
- 'PICTFORMINFO': 'PictFormInfo',
- 'PICTSCREEN': 'PictScreen',
- 'PICTVISUAL': 'PictVisual',
- 'POINTFIX': 'PointFix',
- 'SEGMENT': 'SEGMENT',
- 'SPANFIX': 'SpanFix',
- 'SUBPICTURE': 'SubPicture',
- 'SYSTEMCOUNTER': 'SystemCounter',
- 'TIMECOORD': 'TimeCoord',
- 'TIMESTAMP': 'TimeStamp',
- 'VISUALID': 'VisualId',
- 'VISUALTYPE': 'VisualType',
- 'WAITCONDITION': 'WaitCondition',
- }
- if name in SPECIAL:
- return SPECIAL[name]
+RENAME = {
+ 'ANIMCURSORELT': 'AnimationCursorElement',
+ 'CA': 'ChangeAlarmAttribute',
+ 'CHAR2B': 'Char16',
+ 'CHARINFO': 'CharInfo',
+ 'COLORITEM': 'ColorItem',
+ 'COLORMAP': 'ColorMap',
+ 'Connection': 'RandRConnection',
+ 'CP': 'CreatePictureAttribute',
+ 'CW': 'CreateWindowAttribute',
+ 'DAMAGE': 'DamageId',
+ 'DIRECTFORMAT': 'DirectFormat',
+ 'DOTCLOCK': 'DotClock',
+ 'FBCONFIG': 'FbConfig',
+ 'FLOAT32': 'float',
+ 'FLOAT64': 'double',
+ 'FONTPROP': 'FontProperty',
+ 'GC': 'GraphicsContextAttribute',
+ 'GCONTEXT': 'GraphicsContext',
+ 'GLYPHINFO': 'GlyphInfo',
+ 'GLYPHSET': 'GlyphSet',
+ 'INDEXVALUE': 'IndexValue',
+ 'KB': 'Keyboard',
+ 'KEYCODE': 'KeyCode',
+ 'KEYCODE32': 'KeyCode32',
+ 'KEYSYM': 'KeySym',
+ 'LINEFIX': 'LineFix',
+ 'OP': 'Operation',
+ 'PBUFFER': 'PBuffer',
+ 'PCONTEXT': 'PContext',
+ 'PICTDEPTH': 'PictDepth',
+ 'PICTFORMAT': 'PictFormat',
+ 'PICTFORMINFO': 'PictFormInfo',
+ 'PICTSCREEN': 'PictScreen',
+ 'PICTVISUAL': 'PictVisual',
+ 'POINTFIX': 'PointFix',
+ 'SPANFIX': 'SpanFix',
+ 'SUBPICTURE': 'SubPicture',
+ 'SYSTEMCOUNTER': 'SystemCounter',
+ 'TIMECOORD': 'TimeCoord',
+ 'TIMESTAMP': 'Time',
+ 'VISUALID': 'VisualId',
+ 'VISUALTYPE': 'VisualType',
+ 'WAITCONDITION': 'WaitCondition',
+}
+
+READ_SPECIAL = set([
+ ('xcb', 'Setup'),
+])
+
+WRITE_SPECIAL = set([
+ ('xcb', 'ClientMessage'),
+ ('xcb', 'UnmapNotify'),
+ ('xcb', 'SelectionNotify'),
+])
+
+
+def adjust_type_name(name):
+ if name in RENAME:
+ return RENAME[name]
+ # If there's an underscore, then this is either snake case or upper case.
+ if '_' in name:
return ''.join([
token[0].upper() + token[1:].lower() for token in name.split('_')
])
+ if name.isupper():
+ name = name.lower()
+ # Now the only possibilities are caml case and pascal case. It could also
+ # be snake case with a single word, but that would be same as caml case.
+ # To convert all of these, just capitalize the first letter.
+ return name[0].upper() + name[1:]
+
+
+# Given a list of event names like ["KeyPress", "KeyRelease"], returns a name
+# suitable for use as a base event like "Key".
+def event_base_name(names):
+ # If there's only one event in this group, the "common name" is just
+ # the event name.
+ if len(names) == 1:
+ return names[0]
+
+ # Handle a few special cases where the longest common prefix is empty: eg.
+ # EnterNotify/LeaveNotify/FocusIn/FocusOut -> Crossing.
+ EVENT_NAMES = [
+ ('TouchBegin', 'Device'),
+ ('RawTouchBegin', 'RawDevice'),
+ ('Enter', 'Crossing'),
+ ('EnterNotify', 'Crossing'),
+ ('DeviceButtonPress', 'LegacyDevice'),
+ ]
+ for name, rename in EVENT_NAMES:
+ if name in names:
+ return rename
+
+ # Use the longest common prefix of the event names as the base name.
+ name = ''.join(
+ chars[0]
+ for chars in itertools.takewhile(lambda chars: len(set(chars)) == 1,
+ zip(*names)))
+ assert name
return name
@@ -251,17 +299,6 @@ class Indent:
self.xproto.write(self.closing_line)
-class NullContext:
- def __init__(self):
- pass
-
- def __enter__(self):
- pass
-
- def __exit__(self, exc_type, exc_value, exc_traceback):
- pass
-
-
# Make all members of |obj|, given by |fields|, visible in
# the local scope while this class is alive.
class ScopedFields:
@@ -302,20 +339,37 @@ def safe_name(name):
return name
-class GenXproto:
- def __init__(self, args, xcbgen):
+class FileWriter:
+ def __init__(self):
+ self.indent = 0
+
+ # Write a line to the current file.
+ def write(self, line=''):
+ indent = self.indent if line and not line.startswith('#') else 0
+ print((' ' * indent) + line, file=self.file)
+
+
+class GenXproto(FileWriter):
+ def __init__(self, proto, proto_dir, gen_dir, xcbgen, all_types):
+ FileWriter.__init__(self)
+
# Command line arguments
- self.args = args
+ self.proto = proto
+ self.xml_filename = os.path.join(proto_dir, '%s.xml' % proto)
+ self.header_file = open(os.path.join(gen_dir, '%s.h' % proto), 'w')
+ self.source_file = open(os.path.join(gen_dir, '%s.cc' % proto), 'w')
+ self.undef_file = open(os.path.join(gen_dir, '%s_undef.h' % proto),
+ 'w')
# Top-level xcbgen python module
self.xcbgen = xcbgen
+ # Types for every module including this one
+ self.all_types = all_types
+
# The last used UID for making unique names
self.prev_id = -1
- # Current indentation level
- self.indent = 0
-
# Current file to write to
self.file = None
@@ -331,7 +385,7 @@ class GenXproto:
# Map from type names to a set of types. Certain types
# like enums and simple types can alias each other.
- self.types = collections.defaultdict(set)
+ self.types = collections.defaultdict(list)
# Set of names of simple types to be replaced with enums
self.replace_with_enum = set()
@@ -339,10 +393,11 @@ class GenXproto:
# Map of enums to their underlying types
self.enum_types = collections.defaultdict(set)
- # Write a line to the current file.
- def write(self, line=''):
- indent = self.indent if line and not line.startswith('#') else 0
- print((' ' * indent) + line, file=self.file)
+ # Map from (XML tag, XML name) to XML element
+ self.module_names = {}
+
+ # Enums that represent bit masks.
+ self.bitenums = []
# Geenerate an ID suitable for use in temporary variable names.
def new_uid(self, ):
@@ -361,57 +416,70 @@ class GenXproto:
return ''
def rename_type(self, t, name):
- name = list(name)
- for i in range(1, len(name)):
- name[i] = adjust_type_case(name[i])
- name[-1] += self.type_suffix(t)
- return name
-
- # Given an xcbgen.xtypes.Type, returns a C++-namespace-qualified
- # string that looks like Input::InputClass::Key.
- def qualtype(self, t, name):
# Work around a bug in xcbgen: ('int') should have been ('int',)
if name == 'int':
name = ('int', )
- name = self.rename_type(t, name)
+ name = list(name)
if name[0] == 'xcb':
# Use namespace x11 instead of xcb.
name[0] = 'x11'
- # We want the non-extension X11 structures to live in a class too.
- if len(name) == 2:
- name[1:1] = ['XProto']
+ for i in range(1, len(name)):
+ name[i] = adjust_type_name(name[i])
+ name[-1] += self.type_suffix(t)
+ return name
+
+ # Given an unqualified |name| like ('Window') and a namespace like ['x11'],
+ # returns a fully qualified name like ('x11', 'Window').
+ def qualify_type(self, name, namespace):
+ if tuple(namespace + name) in self.all_types:
+ return namespace + name
+ return self.qualify_type(name, namespace[:-1])
+
+ # Given an xcbgen.xtypes.Type, returns a C++-namespace-qualified
+ # string that looks like Input::InputClass::Key.
+ def qualtype(self, t, name):
+ name = self.rename_type(t, name)
# Try to avoid adding namespace qualifiers if they're not necessary.
chop = 0
for t1, t2 in zip(name, self.namespace):
if t1 != t2:
break
+ if self.qualify_type(name[chop + 1:], self.namespace) != name:
+ break
chop += 1
return '::'.join(name[chop:])
def fieldtype(self, field):
- return self.qualtype(field.type, field.field_type)
+ return self.qualtype(field.type,
+ field.enum if field.enum else field.field_type)
+
+ def switch_fields(self, switch):
+ fields = []
+ for case in switch.bitcases:
+ if case.field_name:
+ fields.append(case)
+ else:
+ fields.extend(case.type.fields)
+ return fields
def add_field_to_scope(self, field, obj):
- if not field.visible or not field.wire:
+ if not field.visible or (not field.wire and not field.isfd):
+ return 0
+
+ field_name = safe_name(field.field_name)
+
+ if field.type.is_switch:
+ self.write('auto& %s = %s;' % (field_name, obj))
return 0
self.scope.append(field)
- field_name = safe_name(field.field_name)
- # There's one case where we would have generated:
- # auto& enable = enable.enable;
- # To prevent a compiler error from trying to use the variable
- # in its own definition, save to a temporary variable first.
- if field_name == obj:
- tmp_id = self.new_uid()
- self.write('auto& tmp%d = %s.%s;' % (tmp_id, obj, field_name))
- self.write('auto& %s = tmp%d;' % (field_name, tmp_id))
- elif field.for_list:
- self.write('%s %s;' % (self.fieldtype(field), field_name))
+ if field.for_list or field.for_switch:
+ self.write('%s %s{};' % (self.fieldtype(field), field_name))
else:
self.write('auto& %s = %s.%s;' % (field_name, obj, field_name))
@@ -432,9 +500,9 @@ class GenXproto:
# Work around conflicts caused by Xlib's liberal use of macros.
def undef(self, name):
- print('#ifdef %s' % name, file=self.args.undeffile)
- print('#undef %s' % name, file=self.args.undeffile)
- print('#endif', file=self.args.undeffile)
+ print('#ifdef %s' % name, file=self.undef_file)
+ print('#undef %s' % name, file=self.undef_file)
+ print('#endif', file=self.undef_file)
def expr(self, expr):
if expr.op == 'popcount':
@@ -476,16 +544,53 @@ class GenXproto:
assert expr.lenfield_name
return expr.lenfield_name
+ def get_xidunion_element(self, name):
+ key = ('xidunion', name[-1])
+ return self.module_names.get(key, None)
+
+ def declare_xidunion(self, xidunion, xidname):
+ names = [type_element.text for type_element in xidunion]
+ types = list(set([self.module.get_type(name) for name in names]))
+ assert len(types) == 1
+ value_type = types[0]
+ value_typename = self.qualtype(value_type, value_type.name)
+ with Indent(self, 'struct %s {' % xidname, '};'):
+ self.write('%s() : value{} {}' % xidname)
+ self.write()
+ for name in names:
+ cpp_name = self.module.get_type_name(name)
+ typename = self.qualtype(value_type, cpp_name)
+ self.write('%s(%s value) : value{static_cast<%s>(value)} {}' %
+ (xidname, typename, value_typename))
+ self.write(
+ 'operator %s() const { return static_cast<%s>(value); }' %
+ (typename, typename))
+ self.write()
+ self.write('%s value{};' % value_typename)
+
def declare_simple(self, item, name):
# The underlying type of an enum must be integral, so avoid defining
# FLOAT32 or FLOAT64. Usages are renamed to float and double instead.
renamed = tuple(self.rename_type(item, name))
- if name[-1] not in ('FLOAT32', 'FLOAT64'
- ) and renamed not in self.replace_with_enum:
- self.write(
- 'enum class %s : %s {};' %
- (adjust_type_case(name[-1]), self.qualtype(item, item.name)))
+ if (name[-1] in ('FLOAT32', 'FLOAT64')
+ or renamed in self.replace_with_enum):
+ return
+ elif name[-1] == 'FP1616':
+ # Xcbproto defines FP1616 as uint32_t instead of a struct of
+ # two 16-bit ints, which is how it's intended to be used.
+ with Indent(self, 'struct Fp1616 {', '};'):
+ self.write('int16_t integral;')
+ self.write('uint16_t frac;')
self.write()
+ return
+
+ xidunion = self.get_xidunion_element(name)
+ if xidunion:
+ self.declare_xidunion(xidunion, renamed[-1])
+ else:
+ self.write('enum class %s : %s {};' %
+ (renamed[-1], self.qualtype(item, item.name)))
+ self.write()
def copy_primitive(self, name):
self.write('%s(&%s, &buf);' %
@@ -495,28 +600,36 @@ class GenXproto:
type_name = self.fieldtype(field)
name = safe_name(field.field_name)
+ def copy_basic():
+ self.write('%s %s;' % (type_name, name))
+ self.copy_primitive(name)
+
if name in ('major_opcode', 'minor_opcode'):
assert not self.is_read
- is_ext = any(
- [f.field_name == 'minor_opcode' for f in field.parent.fields])
- if is_ext and name == 'major_opcode':
- self.write('// Caller fills in extension major opcode.')
- self.write('Pad(&buf, sizeof(%s));' % type_name)
+ is_ext = self.module.namespace.is_ext
+ self.write(
+ '%s %s = %s;' %
+ (type_name, name, 'info_.major_opcode' if is_ext
+ and name == 'major_opcode' else field.parent[0].opcode))
+ self.copy_primitive(name)
+ elif name == 'response_type':
+ if self.is_read:
+ copy_basic()
else:
- self.write('%s %s = %s;' %
- (type_name, name, field.parent.opcode))
+ container_type, container_name = field.parent
+ assert container_type.is_event
+ opcode = container_type.opcodes[container_name]
+ self.write('%s %s = %s;' % (type_name, name, opcode))
self.copy_primitive(name)
- elif name in ('response_type', 'sequence', 'extension'):
+ elif name in ('extension', 'error_code', 'event_type'):
assert self.is_read
- self.write('%s %s;' % (type_name, name))
- self.copy_primitive(name)
+ copy_basic()
elif name == 'length':
if not self.is_read:
self.write('// Caller fills in length for writes.')
self.write('Pad(&buf, sizeof(%s));' % type_name)
else:
- self.write('%s %s;' % (type_name, name))
- self.copy_primitive(name)
+ copy_basic()
else:
assert field.type.is_expr
assert (not isinstance(field.type, self.xcbgen.xtypes.Enum))
@@ -527,48 +640,52 @@ class GenXproto:
def declare_case(self, case):
assert case.type.is_case != case.type.is_bitcase
- with (Indent(self, 'struct {', '} %s;' % safe_name(case.field_name))
- if case.field_name else NullContext()):
- for case_field in case.type.fields:
- self.declare_field(case_field)
-
- def copy_case(self, case, switch_var):
- op = 'CaseEq' if case.type.is_case else 'BitAnd'
+ fields = [
+ field for case_field in case.type.fields
+ for field in self.declare_field(case_field)
+ ]
+ if not case.field_name:
+ return fields
+ name = safe_name(case.field_name)
+ with Indent(self, 'struct %s_t {' % name, '};'):
+ for field in fields:
+ self.write('%s %s{};' % field)
+ return [(name + '_t', name)]
+
+ def copy_case(self, case, switch_name):
+ op = 'CaseEq' if case.type.is_case else 'CaseAnd'
condition = ' || '.join([
- '%s(%s, %s)' % (op, switch_var, self.expr(expr))
+ '%s(%s_expr, %s)' % (op, switch_name, self.expr(expr))
for expr in case.type.expr
])
with Indent(self, 'if (%s) {' % condition, '}'):
- with (ScopedFields(self, case.field_name, case.type.fields)
- if case.field_name else NullContext()):
+ if case.field_name:
+ fields = [case]
+ obj = '(*%s.%s)' % (switch_name, safe_name(case.field_name))
+ else:
+ fields = case.type.fields
+ obj = '*' + switch_name
+ for case_field in fields:
+ name = safe_name(case_field.field_name)
+ if case_field.visible and self.is_read:
+ self.write('%s.%s.emplace();' % (switch_name, name))
+ with ScopedFields(self, obj, case.type.fields):
for case_field in case.type.fields:
- assert case_field.wire
self.copy_field(case_field)
def declare_switch(self, field):
- t = field.type
- name = safe_name(field.field_name)
-
- with Indent(self, 'struct {', '} %s;' % name):
- for case in t.bitcases:
- self.declare_case(case)
+ return [('base::Optional<%s>' % field_type, field_name)
+ for case in field.type.bitcases
+ for field_type, field_name in self.declare_case(case)]
def copy_switch(self, field):
t = field.type
name = safe_name(field.field_name)
- scope_fields = []
+ self.write('auto %s_expr = %s;' % (name, self.expr(t.expr)))
for case in t.bitcases:
- if case.field_name:
- scope_fields.append(case)
- else:
- scope_fields.extend(case.type.fields)
- with Indent(self, '{', '}'), ScopedFields(self, name, scope_fields):
- switch_var = name + '_expr'
- self.write('auto %s = %s;' % (switch_var, self.expr(t.expr)))
- for case in t.bitcases:
- self.copy_case(case, switch_var)
+ self.copy_case(case, name)
def declare_list(self, field):
t = field.type
@@ -588,7 +705,7 @@ class GenXproto:
type_name = 'std::string'
else:
type_name = 'std::vector<%s>' % type_name
- self.write('%s %s{};' % (type_name, name))
+ return [(type_name, name)]
def copy_list(self, field):
t = field.type
@@ -604,35 +721,60 @@ class GenXproto:
with Indent(self, 'for (auto& %s_elem : %s) {' % (name, name), '}'):
elem_name = name + '_elem'
elem_type = t.member
- if elem_type.is_simple or elem_type.is_union:
- assert (not isinstance(elem_type, self.xcbgen.xtypes.Enum))
- self.copy_primitive(elem_name)
- else:
- assert elem_type.is_container
- self.copy_container(elem_type, elem_name)
+ elem_field = self.xcbgen.expr.Field(elem_type, field.field_type,
+ elem_name, field.visible,
+ field.wire, field.auto,
+ field.enum, field.isfd)
+ elem_field.for_list = None
+ elem_field.for_switch = None
+ self.copy_field(elem_field)
+
+ def generate_switch_var(self, field):
+ name = safe_name(field.field_name)
+ for case in field.for_switch.type.bitcases:
+ case_field = case if case.field_name else case.type.fields[0]
+ self.write('SwitchVar(%s, %s.%s.has_value(), %s, &%s);' %
+ (self.expr(case.type.expr[0]),
+ safe_name(field.for_switch.field_name),
+ safe_name(case_field.field_name),
+ 'true' if case.type.is_bitcase else 'false', name))
def declare_field(self, field):
t = field.type
name = safe_name(field.field_name)
- if not field.wire or not field.visible or field.for_list:
- return
+ if not field.visible or field.for_list or field.for_switch:
+ return []
if t.is_switch:
- self.declare_switch(field)
- elif t.is_list:
- self.declare_list(field)
- else:
- self.write(
- '%s %s{};' %
- (self.qualtype(field.type, field.enum
- if field.enum else field.field_type), name))
+ return self.declare_switch(field)
+ if t.is_list:
+ return self.declare_list(field)
+ return [(self.fieldtype(field), name)]
def copy_field(self, field):
+ if not field.wire and not field.isfd:
+ return
+
t = field.type
+ renamed = tuple(self.rename_type(field.type, field.field_type))
+ if t.is_list:
+ t.member = self.all_types.get(renamed, t.member)
+ else:
+ t = self.all_types.get(renamed, t)
name = safe_name(field.field_name)
self.write('// ' + name)
+
+ # If this is a generated field, initialize the value of the field
+ # variable from the given context.
+ if not self.is_read:
+ if field.for_list:
+ self.write('%s = %s.size();' %
+ (name, safe_name(field.for_list.field_name)))
+ if field.for_switch:
+ self.generate_switch_var(field)
+
if t.is_pad:
if t.align > 1:
assert t.nmemb == 1
@@ -642,11 +784,6 @@ class GenXproto:
self.write('Pad(&buf, %d);' % t.nmemb)
elif not field.visible:
self.copy_special_field(field)
- elif field.for_list:
- if not self.is_read:
- self.write('%s = %s.size();' %
- (name, safe_name(field.for_list.field_name)))
- self.copy_primitive(name)
elif t.is_switch:
self.copy_switch(field)
elif t.is_list:
@@ -656,6 +793,9 @@ class GenXproto:
elif t.is_container:
with Indent(self, '{', '}'):
self.copy_container(t, name)
+ elif t.is_fd:
+ # TODO(https://crbug.com/1066670): Copy FDs out of band.
+ self.write('NOTIMPLEMENTED();')
else:
assert t.is_simple
if field.enum:
@@ -663,6 +803,8 @@ class GenXproto:
else:
self.copy_primitive(name)
+ self.write()
+
def declare_enum(self, enum):
def declare_enum_entry(name, value):
name = safe_name(name)
@@ -672,7 +814,7 @@ class GenXproto:
self.undef(enum.name[-1])
with Indent(
self, 'enum class %s : %s {' %
- (adjust_type_case(enum.name[-1]), self.enum_types[enum.name][0]
+ (adjust_type_name(enum.name[-1]), self.enum_types[enum.name][0]
if enum.name in self.enum_types else 'int'), '};'):
bitnames = set([name for name, _ in enum.bits])
for name, value in enum.values:
@@ -686,7 +828,7 @@ class GenXproto:
# The size of enum types may be different depending on the
# context, so they should always be casted to the contextual
# underlying type before calling Read() or Write().
- underlying_type = self.fieldtype(field)
+ underlying_type = self.qualtype(field.type, field.type.name)
tmp_name = 'tmp%d' % self.new_uid()
real_name = safe_name(field.field_name)
self.write('%s %s;' % (underlying_type, tmp_name))
@@ -699,30 +841,84 @@ class GenXproto:
self.write('%s = static_cast<%s>(%s);' %
(real_name, enum_type, tmp_name))
- def declare_container(self, struct):
- name = struct.name[-1] + self.type_suffix(struct)
+ def declare_fields(self, fields):
+ for field in fields:
+ for field_type_name in self.declare_field(field):
+ self.write('%s %s{};' % field_type_name)
+
+ def declare_event(self, event, name):
+ event_name = name[-1] + 'Event'
+ self.undef(event_name)
+ with Indent(self, 'struct %s {' % adjust_type_name(event_name), '};'):
+ self.write('static constexpr int type_id = %d;' % event.type_id)
+ if len(event.opcodes) == 1:
+ self.write('static constexpr uint8_t opcode = %s;' %
+ event.opcodes[name])
+ else:
+ with Indent(self, 'enum Opcode {', '} opcode{};'):
+ items = [(int(x), y)
+ for (y, x) in event.enum_opcodes.items()]
+ for opcode, opname in sorted(items):
+ self.undef(opname)
+ self.write('%s = %s,' % (opname, opcode))
+ self.write('bool send_event{};')
+ self.declare_fields(event.fields)
+ self.write()
+
+ def declare_container(self, struct, struct_name):
+ name = struct_name[-1] + self.type_suffix(struct)
self.undef(name)
- with Indent(self, 'struct %s {' % adjust_type_case(name), '};'):
- for field in struct.fields:
- self.declare_field(field)
+ with Indent(self, 'struct %s {' % adjust_type_name(name), '};'):
+ self.declare_fields(struct.fields)
self.write()
def copy_container(self, struct, name):
assert not struct.is_union
with ScopedFields(self, name, struct.fields):
for field in struct.fields:
- if field.wire:
- self.copy_field(field)
- self.write()
+ self.copy_field(field)
+
+ def read_special_container(self, struct, name):
+ self.namespace = ['x11']
+ name = self.qualtype(struct, name)
+ self.write('template <> COMPONENT_EXPORT(X11)')
+ self.write('%s Read<%s>(' % (name, name))
+ with Indent(self, ' const uint8_t* buffer) {', '}'):
+ self.write('ReadBuffer buf{buffer, 0UL};')
+ self.write('%s obj;' % name)
+ self.write()
+ self.is_read = True
+ self.copy_container(struct, 'obj')
+ self.write('return obj;')
+ self.write()
+
+ def write_special_container(self, struct, name):
+ self.namespace = ['x11']
+ name = self.qualtype(struct, name)
+ self.write('template <> COMPONENT_EXPORT(X11)')
+ self.write('std::vector<uint8_t> Write<%s>(' % name)
+ with Indent(self, ' const %s& obj) {' % name, '}'):
+ self.write('WriteBuffer buf;')
+ self.write()
+ self.is_read = False
+ self.copy_container(struct, 'obj')
+ self.write('return buf;')
+ self.write()
def declare_union(self, union):
name = union.name[-1]
+ if union.elt.tag == 'eventstruct':
+ # There's only one of these in all of the protocol descriptions.
+ # It's just used to represent any 32-byte event for XInput.
+ self.write('using %s = std::array<uint8_t, 32>;' % name)
+ return
with Indent(self, 'union %s {' % name, '};'):
self.write('%s() { memset(this, 0, sizeof(*this)); }' % name)
self.write()
for field in union.fields:
- type_name = self.fieldtype(field)
- self.write('%s %s;' % (type_name, safe_name(field.field_name)))
+ field_type_names = self.declare_field(field)
+ assert len(field_type_names) == 1
+ self.write('%s %s;' % field_type_names[0])
self.write(
'static_assert(std::is_trivially_copyable<%s>::value, "");' % name)
self.write()
@@ -730,26 +926,30 @@ class GenXproto:
def declare_request(self, request):
method_name = request.name[-1]
request_name = method_name + 'Request'
- reply_name = method_name + 'Reply'
+ reply_name = method_name + 'Reply' if request.reply else 'void'
- self.declare_container(request)
- if request.reply:
- self.declare_container(request.reply)
- else:
- reply_name = 'void'
+ in_class = self.namespace == ['x11', self.class_name]
- self.write('using %sResponse = Response<%s>;' %
- (method_name, reply_name))
- self.write()
+ if not in_class or self.module.namespace.is_ext:
+ self.declare_container(request, request.name)
+ if request.reply:
+ self.declare_container(request.reply, request.reply.name)
- self.write('Future<%s> %s(' % (reply_name, method_name))
- self.write(' const %s& request);' % request_name)
- self.write()
+ self.write('using %sResponse = Response<%s>;' %
+ (method_name, reply_name))
+ self.write()
+
+ if in_class:
+ self.write('Future<%s> %s(' % (reply_name, method_name))
+ self.write(' const %s& request);' % request_name)
+ self.write()
def define_request(self, request):
method_name = '%s::%s' % (self.class_name, request.name[-1])
- request_name = method_name + 'Request'
- reply_name = method_name + 'Reply'
+ prefix = (method_name
+ if self.module.namespace.is_ext else request.name[-1])
+ request_name = prefix + 'Request'
+ reply_name = prefix + 'Reply'
reply = request.reply
if not reply:
@@ -758,6 +958,12 @@ class GenXproto:
self.write('Future<%s>' % reply_name)
self.write('%s(' % method_name)
with Indent(self, ' const %s& request) {' % request_name, '}'):
+ cond = '!connection_->Ready()'
+ if self.module.namespace.is_ext:
+ cond += ' || !present()'
+ self.write('if (%s)' % cond)
+ self.write(' return {};')
+ self.write()
self.namespace = ['x11', self.class_name]
self.write('WriteBuffer buf;')
self.write()
@@ -765,7 +971,7 @@ class GenXproto:
self.copy_container(request, 'request')
self.write('Align(&buf, 4);')
self.write()
- self.write('return x11::SendRequest<%s>(display_, &buf);' %
+ self.write('return x11::SendRequest<%s>(connection_, &buf);' %
reply_name)
self.write()
@@ -789,14 +995,38 @@ class GenXproto:
self.write('return reply;')
self.write()
+ def define_event(self, event, name):
+ self.namespace = ['x11']
+ name = self.qualtype(event, name)
+ self.write('template <> COMPONENT_EXPORT(X11)')
+ self.write('void ReadEvent<%s>(' % name)
+ with Indent(self, ' %s* event_, const uint8_t* buffer) {' % name,
+ '}'):
+ self.write('ReadBuffer buf{buffer, 0UL};')
+ self.write()
+ self.is_read = True
+ self.copy_container(event, '(*event_)')
+ self.write()
+
+ def define_type(self, item, name):
+ if name in READ_SPECIAL:
+ self.read_special_container(item, name)
+ if name in WRITE_SPECIAL:
+ self.write_special_container(item, name)
+ if isinstance(item, self.xcbgen.xtypes.Request):
+ self.define_request(item)
+ elif item.is_event:
+ self.define_event(item, name)
+
def declare_type(self, item, name):
if item.is_union:
self.declare_union(item)
elif isinstance(item, self.xcbgen.xtypes.Request):
self.declare_request(item)
+ elif item.is_event:
+ self.declare_event(item, name)
elif item.is_container:
- item.name = name
- self.declare_container(item)
+ self.declare_container(item, name)
elif isinstance(item, self.xcbgen.xtypes.Enum):
self.declare_enum(item)
else:
@@ -823,72 +1053,141 @@ class GenXproto:
if enums:
assert len(enums) == 1
enum = enums[0]
- field.enum = self.module.get_type(enum).name if enums else None
+ field.enum = self.module.get_type(enum).name
self.enum_types[enum].add(field.type.name)
+ else:
+ field.enum = None
def resolve_type(self, t, name):
renamed = tuple(self.rename_type(t, name))
- if t in self.types[renamed]:
- return
- self.types[renamed].add(t)
+ assert renamed[0] == 'x11'
+ assert t not in self.types[renamed]
+ self.types[renamed].append(t)
+ self.all_types[renamed] = t
+
+ if isinstance(t, self.xcbgen.xtypes.Enum):
+ self.bitenums.append((t, name))
if not t.is_container:
return
- if t.is_switch:
- fields = {}
- for case in t.bitcases:
- if case.field_name:
- fields[case.field_name] = case
- else:
- for field in case.type.fields:
- fields[field.field_name] = field
- else:
- fields = {field.field_name: field for field in t.fields}
+ fields = {
+ field.field_name: field
+ for field in (self.switch_fields(t) if t.is_switch else t.fields)
+ }
self.resolve_element(t.elt, fields)
for field in fields.values():
- field.parent = t
- field.for_list = None
+ if field.field_name == 'sequence':
+ field.visible = True
+ field.parent = (t, name)
+ # |for_list| and |for_switch| may have already been set when
+ # processing other fields in this structure.
+ field.for_list = getattr(field, 'for_list', None)
+ field.for_switch = getattr(field, 'for_switch', None)
+
+ for is_type, for_type in ((field.type.is_list, 'for_list'),
+ (field.type.is_switch, 'for_switch')):
+ if not is_type:
+ continue
+ expr = field.type.expr
+ field_name = expr.lenfield_name
+ if (expr.op in (None, 'calculate_len')
+ and field_name in fields):
+ setattr(fields[field_name], for_type, field)
+
if field.type.is_switch or field.type.is_case_or_bitcase:
self.resolve_type(field.type, field.field_type)
- elif field.type.is_list:
- self.resolve_type(field.type.member, field.type.member.name)
- expr = field.type.expr
- if not expr.op and expr.lenfield_name in fields:
- fields[expr.lenfield_name].for_list = field
- else:
- self.resolve_type(field.type, field.type.name)
if isinstance(t, self.xcbgen.xtypes.Request) and t.reply:
self.resolve_type(t.reply, t.reply.name)
+ # Multiple event names may map to the same underlying event. For these
+ # cases, we want to avoid duplicating the event structure. Instead, put
+ # all of these events under one structure with an additional opcode field
+ # to indicate the type of event.
+ def uniquify_events(self):
+ # Manually merge some events in XInput. These groups of 8 events have
+ # idential structure, and are merged as XIDeviceEvent in Xlib. To avoid
+ # duplication, and to ease the transition from Xlib to XProto, we merge
+ # the events here too.
+ # TODO(thomasanderson): We should avoid adding workarounds for xcbproto.
+ # Instead, the protocol files should be modified directly. However,
+ # some of the changes we want to make change the API, so the changes
+ # should be made in a fork in //third_party rather than upstreamed.
+ MERGE = [
+ ([
+ 'KeyPress', 'KeyRelease', 'ButtonPress', 'ButtonRelease',
+ 'Motion', 'TouchBegin', 'TouchUpdate', 'TouchEnd'
+ ], []),
+ ([
+ 'RawKeyPress', 'RawKeyRelease', 'RawButtonPress',
+ 'RawButtonRelease', 'RawMotion', 'RawTouchBegin',
+ 'RawTouchUpdate', 'RawTouchEnd'
+ ], []),
+ ]
+ for i, (name, t) in enumerate(self.module.all):
+ if t.is_event and name[1] == 'Input':
+ for names, event in MERGE:
+ if name[-1] in names:
+ if event:
+ event[0].opcodes.update(t.opcodes)
+ self.module.all[i] = name, event[0]
+ else:
+ event.append(t)
+
+ types = []
+ events = set()
+ for name, t in self.module.all:
+ if not t.is_event or len(t.opcodes) == 1:
+ types.append((name, t))
+ continue
+
+ renamed = tuple(self.rename_type(t, name))
+ self.all_types[renamed] = t
+ if t in events:
+ continue
+ events.add(t)
+
+ names = [name[-1] for name in t.opcodes.keys()]
+ name = name[:-1] + (event_base_name(names), )
+ types.append((name, t))
+
+ t.enum_opcodes = {}
+ for opname in t.opcodes:
+ opcode = t.opcodes[opname]
+ opname = opname[-1]
+ if opname.startswith(name[-1]):
+ opname = opname[len(name[-1]):]
+ t.enum_opcodes[opname] = opcode
+ self.module.all = types
+
# Perform preprocessing like renaming, reordering, and adding additional
# data fields.
def resolve(self):
- for name, t in self.module.all:
+ self.class_name = (adjust_type_name(self.module.namespace.ext_name)
+ if self.module.namespace.is_ext else 'XProto')
+
+ self.uniquify_events()
+
+ for i, (name, t) in enumerate(self.module.all):
+ # Work around a name conflict: the type ScreenSaver has the same
+ # name as the extension, so rename the type.
+ if name == ('xcb', 'ScreenSaver'):
+ name = ('xcb', 'ScreenSaverMode')
+ t.name = name
+ self.module.all[i] = (name, t)
self.resolve_type(t, name)
- to_delete = []
- for enum in self.enum_types:
- types = self.enum_types[enum]
+ for enum, types in list(self.enum_types.items()):
if len(types) == 1:
self.enum_types[enum] = list(types)[0]
else:
- to_delete.append(enum)
- for x in to_delete:
- del self.enum_types[x]
+ del self.enum_types[enum]
for t in self.types:
- # Lots of fields have types like uint8_t. Ignore these.
- if len(t) == 1:
- continue
- l = list(self.types[t])
- # For some reason, FDs always have distint types so they appear
- # duplicated in the set. If the set contains only FDs, then bail.
- if all(x.is_fd for x in l):
- continue
+ l = self.types[t]
if len(l) == 1:
continue
@@ -908,26 +1207,34 @@ class GenXproto:
self.replace_with_enum.add(t)
self.enum_types[enum.name] = simple.name
+ for node in self.module.namespace.root:
+ if 'name' in node.attrib:
+ key = (node.tag, node.attrib['name'])
+ assert key not in self.module_names
+ self.module_names[key] = node
+
# The order of types in xcbproto's xml files are inconsistent, so sort
- # them in the order {type aliases, enums, structs, requests/replies}.
- def type_order_priority(item):
+ # them in the order {type aliases, enums, xidunions, structs,
+ # requests/replies}.
+ def type_order_priority(module_type):
+ name, item = module_type
if item.is_simple:
- return 0
+ return 2 if self.get_xidunion_element(name) else 0
if isinstance(item, self.xcbgen.xtypes.Enum):
return 1
if isinstance(item, self.xcbgen.xtypes.Request):
- return 3
- return 2
+ return 4
+ return 3
- def cmp((_1, item1), (_2, item2)):
- return type_order_priority(item1) - type_order_priority(item2)
+ def cmp(type1, type2):
+ return type_order_priority(type1) - type_order_priority(type2)
# sort() is guaranteed to be stable.
- self.module.all.sort(cmp=cmp)
+ self.module.all.sort(key=functools.cmp_to_key(cmp))
def gen_header(self):
- self.file = self.args.headerfile
- include_guard = self.args.headerfile.name.replace('/', '_').replace(
+ self.file = self.header_file
+ include_guard = self.header_file.name.replace('/', '_').replace(
'.', '_').upper() + '_'
self.write('#ifndef ' + include_guard)
self.write('#define ' + include_guard)
@@ -939,37 +1246,86 @@ class GenXproto:
self.write('#include <vector>')
self.write()
self.write('#include "base/component_export.h"')
+ self.write('#include "base/optional.h"')
self.write('#include "ui/gfx/x/xproto_types.h"')
- for direct_import in self.module.direct_imports:
+ imports = set(self.module.direct_imports)
+ if self.module.namespace.is_ext:
+ imports.add(('xproto', 'xproto'))
+ for direct_import in sorted(list(imports)):
self.write('#include "%s.h"' % direct_import[-1])
self.write('#include "%s_undef.h"' % self.module.namespace.header)
self.write()
- self.write('typedef struct _XDisplay XDisplay;')
- self.write()
self.write('namespace x11 {')
self.write()
+ self.write('class Connection;')
+ self.write()
+
+ self.namespace = ['x11']
+ if not self.module.namespace.is_ext:
+ for (name, item) in self.module.all:
+ self.declare_type(item, name)
name = self.class_name
self.undef(name)
with Indent(self, 'class COMPONENT_EXPORT(X11) %s {' % name, '};'):
self.namespace = ['x11', self.class_name]
self.write('public:')
- self.write('explicit %s(XDisplay* display);' % name)
+ if self.module.namespace.is_ext:
+ self.write('static constexpr unsigned major_version = %s;' %
+ self.module.namespace.major_version)
+ self.write('static constexpr unsigned minor_version = %s;' %
+ self.module.namespace.minor_version)
+ self.write()
+ self.write(name + '(Connection* connection,')
+ self.write(' const x11::QueryExtensionReply& info);')
+ self.write()
+ with Indent(self, 'uint8_t present() const {', '}'):
+ self.write('return info_.present;')
+ with Indent(self, 'uint8_t major_opcode() const {', '}'):
+ self.write('return info_.major_opcode;')
+ with Indent(self, 'uint8_t first_event() const {', '}'):
+ self.write('return info_.first_event;')
+ with Indent(self, 'uint8_t first_error() const {', '}'):
+ self.write('return info_.first_error;')
+ else:
+ self.write('explicit %s(Connection* connection);' % name)
self.write()
- self.write('XDisplay* display() { return display_; }')
+ self.write(
+ 'Connection* connection() const { return connection_; }')
self.write()
for (name, item) in self.module.all:
- self.declare_type(item, name)
+ if self.module.namespace.is_ext:
+ self.declare_type(item, name)
+ elif isinstance(item, self.xcbgen.xtypes.Request):
+ self.declare_request(item)
self.write('private:')
- self.write('XDisplay* const display_;')
+ self.write('x11::Connection* const connection_;')
+ if self.module.namespace.is_ext:
+ self.write('x11::QueryExtensionReply info_{};')
self.write()
self.write('} // namespace x11')
self.write()
+ self.namespace = []
+
+ def binop(op, name):
+ self.write('inline constexpr %s operator%s(' % (name, op))
+ with Indent(self, ' {0} l, {0} r)'.format(name) + ' {', '}'):
+ self.write('using T = std::underlying_type_t<%s>;' % name)
+ self.write('return static_cast<%s>(' % name)
+ self.write(' static_cast<T>(l) %s static_cast<T>(r));' % op)
+ self.write()
+
+ for enum, name in self.bitenums:
+ name = self.qualtype(enum, name)
+ binop('|', name)
+ binop('&', name)
+
+ self.write()
self.write('#endif // ' + include_guard)
def gen_source(self):
- self.file = self.args.sourcefile
+ self.file = self.source_file
self.write('#include "%s.h"' % self.module.namespace.header)
self.write()
self.write('#include <xcb/xcb.h>')
@@ -980,46 +1336,246 @@ class GenXproto:
self.write()
self.write('namespace x11 {')
self.write()
- name = self.class_name
- self.write('%s::%s(XDisplay* display) : display_(display) {}' %
- (name, name))
+ ctor = '%s::%s' % (self.class_name, self.class_name)
+ if self.module.namespace.is_ext:
+ self.write(ctor + '(x11::Connection* connection,')
+ self.write(' const x11::QueryExtensionReply& info)')
+ self.write(' : connection_(connection), info_(info) {}')
+ else:
+ self.write(ctor +
+ '(Connection* connection) : connection_(connection) {}')
self.write()
for (name, item) in self.module.all:
- if isinstance(item, self.xcbgen.xtypes.Request):
- self.define_request(item)
+ self.define_type(item, name)
self.write('} // namespace x11')
- def generate(self):
- self.module = self.xcbgen.state.Module(self.args.xmlfile.name, None)
+ def parse(self):
+ self.module = self.xcbgen.state.Module(self.xml_filename, None)
self.module.register()
self.module.resolve()
- self.resolve()
- self.class_name = (adjust_type_case(self.module.namespace.ext_name)
- if self.module.namespace.is_ext else 'XProto')
+ def generate(self):
self.gen_header()
self.gen_source()
+class GenExtensionManager(FileWriter):
+ def __init__(self, gen_dir, genprotos):
+ FileWriter.__init__(self)
+
+ self.gen_dir = gen_dir
+ self.genprotos = genprotos
+ self.extensions = [
+ proto for proto in genprotos if proto.module.namespace.is_ext
+ ]
+
+ def gen_header(self):
+ self.file = open(os.path.join(self.gen_dir, 'extension_manager.h'),
+ 'w')
+ self.write('#ifndef UI_GFX_X_EXTENSION_MANAGER_H_')
+ self.write('#define UI_GFX_X_EXTENSION_MANAGER_H_')
+ self.write()
+ self.write('#include <memory>')
+ self.write()
+ self.write('#include "base/component_export.h"')
+ self.write()
+ self.write('// Avoid conflicts caused by the GenericEvent macro.')
+ self.write('#include "ui/gfx/x/ge_undef.h"')
+ self.write()
+ self.write('namespace x11 {')
+ self.write()
+ self.write('class Connection;')
+ self.write()
+ for genproto in self.genprotos:
+ self.write('class %s;' % genproto.class_name)
+ self.write()
+ with Indent(self, 'class COMPONENT_EXPORT(X11) ExtensionManager {',
+ '};'):
+ self.write('public:')
+ self.write('ExtensionManager();')
+ self.write('~ExtensionManager();')
+ self.write()
+ for extension in self.extensions:
+ name = extension.proto
+ self.write('%s& %s() { return *%s_; }' %
+ (extension.class_name, name, name))
+ self.write()
+ self.write('protected:')
+ self.write('void Init(Connection* conn);')
+ self.write()
+ self.write('private:')
+ for extension in self.extensions:
+ self.write('std::unique_ptr<%s> %s_;' %
+ (extension.class_name, extension.proto))
+ self.write()
+ self.write('} // namespace x11')
+ self.write()
+ self.write('#endif // UI_GFX_X_EXTENSION_MANAGER_H_')
+
+ def gen_source(self):
+ self.file = open(os.path.join(self.gen_dir, 'extension_manager.cc'),
+ 'w')
+ self.write('#include "ui/gfx/x/extension_manager.h"')
+ self.write()
+ self.write('#include "ui/gfx/x/connection.h"')
+ self.write('#include "ui/gfx/x/xproto_internal.h"')
+ for genproto in self.genprotos:
+ self.write('#include "ui/gfx/x/%s.h"' % genproto.proto)
+ self.write()
+ self.write('namespace x11 {')
+ self.write()
+ init = 'void ExtensionManager::Init'
+ with Indent(self, init + '(Connection* conn) {', '}'):
+ for extension in self.extensions:
+ self.write(
+ 'auto %s_future = conn->QueryExtension({"%s"});' %
+ (extension.proto, extension.module.namespace.ext_xname))
+ self.write()
+ for extension in self.extensions:
+ name = extension.proto
+ self.write(
+ '%s_ = MakeExtension<%s>(conn, std::move(%s_future));' %
+ (name, extension.class_name, name))
+ self.write()
+ self.write('ExtensionManager::ExtensionManager() = default;')
+ self.write('ExtensionManager::~ExtensionManager() = default;')
+ self.write()
+ self.write('} // namespace x11')
+
+
+class GenReadEvent(FileWriter):
+ def __init__(self, gen_dir, genprotos):
+ FileWriter.__init__(self)
+
+ self.gen_dir = gen_dir
+ self.genprotos = genprotos
+
+ self.events = []
+ for proto in self.genprotos:
+ for name, item in proto.module.all:
+ if item.is_event:
+ self.events.append((name, item, proto))
+
+ def event_condition(self, event, typename, proto):
+ ext = 'conn->%s()' % proto.proto
+
+ conds = []
+ if not proto.module.namespace.is_ext:
+ # Core protocol event
+ opcode = 'evtype'
+ elif event.is_ge_event:
+ # GenericEvent extension event
+ conds.extend([
+ 'evtype == GeGenericEvent::opcode',
+ '%s.present()' % ext,
+ 'ge->extension == %s.major_opcode()' % ext,
+ ])
+ opcode = 'ge->event_type'
+ else:
+ # Extension event
+ opcode = 'evtype - %s.first_event()' % ext
+ conds.append('%s.present()' % ext)
+
+ if len(event.opcodes) == 1:
+ conds.append('%s == %s::opcode' % (opcode, typename))
+ else:
+ conds.append('(%s)' % ' || '.join([
+ '%s == %s::%s' % (opcode, typename, opname)
+ for opname in event.enum_opcodes.keys()
+ ]))
+
+ return ' && '.join(conds), opcode
+
+ def gen_event(self, name, event, proto):
+ # We can't ever have a plain generic event. It must be a concrete
+ # event provided by an extension.
+ if name == ('xcb', 'GeGeneric'):
+ return
+
+ name = [adjust_type_name(part) for part in name[1:]]
+ typename = '::'.join(name) + 'Event'
+
+ cond, opcode = self.event_condition(event, typename, proto)
+ with Indent(self, 'if (%s) {' % cond, '}'):
+ self.write('event->type_id_ = %d;' % event.type_id)
+ with Indent(self, 'event->deleter_ = [](void* event) {', '};'):
+ self.write('delete reinterpret_cast<%s*>(event);' % typename)
+ self.write('auto* event_ = new %s;' % typename)
+ self.write('ReadEvent(event_, buf);')
+ if len(event.opcodes) > 1:
+ self.write('{0} = static_cast<decltype({0})>({1});'.format(
+ 'event_->opcode', opcode))
+ self.write('event_->send_event = send_event;')
+ self.write('event->event_ = event_;')
+ self.write('return;')
+ self.write()
+
+ def gen_source(self):
+ self.file = open(os.path.join(self.gen_dir, 'read_event.cc'), 'w')
+ self.write('#include "ui/gfx/x/event.h"')
+ self.write()
+ self.write('#include "ui/gfx/x/connection.h"')
+ for genproto in self.genprotos:
+ self.write('#include "ui/gfx/x/%s.h"' % genproto.proto)
+ self.write()
+ self.write('namespace x11 {')
+ self.write()
+ self.write('void ReadEvent(')
+ args = 'Event* event, Connection* conn, const uint8_t* buf'
+ with Indent(self, ' %s) {' % args, '}'):
+ cast = 'auto* %s = reinterpret_cast<const %s*>(buf);'
+ self.write(cast % ('ev', 'xcb_generic_event_t'))
+ self.write(cast % ('ge', 'xcb_ge_generic_event_t'))
+ self.write('auto evtype = ev->response_type & ~kSendEventMask;')
+ self.write('bool send_event = ev->response_type & kSendEventMask;')
+ self.write()
+ for name, event, proto in self.events:
+ self.gen_event(name, event, proto)
+ self.write('NOTREACHED();')
+ self.write()
+ self.write('} // namespace x11')
+
+
def main():
parser = argparse.ArgumentParser()
- parser.add_argument('xmlfile', type=argparse.FileType('r'))
- parser.add_argument('undeffile', type=argparse.FileType('w'))
- parser.add_argument('headerfile', type=argparse.FileType('w'))
- parser.add_argument('sourcefile', type=argparse.FileType('w'))
- parser.add_argument('--sysroot')
+ parser.add_argument('xcbproto_dir', type=str)
+ parser.add_argument('gen_dir', type=str)
+ parser.add_argument('protos', type=str, nargs='*')
args = parser.parse_args()
- if args.sysroot:
- path = os.path.join(args.sysroot, 'usr', 'lib', 'python2.7',
- 'dist-packages')
- sys.path.insert(1, path)
-
+ sys.path.insert(1, args.xcbproto_dir)
import xcbgen.xtypes
import xcbgen.state
- generator = GenXproto(args, xcbgen)
- generator.generate()
+ all_types = {}
+ proto_src_dir = os.path.join(args.xcbproto_dir, 'src')
+ genprotos = [
+ GenXproto(proto, proto_src_dir, args.gen_dir, xcbgen, all_types)
+ for proto in args.protos
+ ]
+ for genproto in genprotos:
+ genproto.parse()
+ for genproto in genprotos:
+ genproto.resolve()
+
+ # Give each event a unique type ID. This is used by x11::Event to
+ # implement downcasting for events.
+ type_id = 1
+ for proto in genprotos:
+ for _, item in proto.module.all:
+ if item.is_event:
+ item.type_id = type_id
+ type_id += 1
+
+ for genproto in genprotos:
+ genproto.generate()
+
+ gen_extension_manager = GenExtensionManager(args.gen_dir, genprotos)
+ gen_extension_manager.gen_header()
+ gen_extension_manager.gen_source()
+
+ gen_read_event = GenReadEvent(args.gen_dir, genprotos)
+ gen_read_event.gen_source()
return 0