[Xcb-commit] 2 commits - src

Julien Danjou jdanjou at kemper.freedesktop.org
Mon Mar 26 09:31:59 PDT 2012


 src/Makefile.am               |    8 
 src/c_client.py               |  600 +++++++++++++++++++++++++++++++++++++++++-
 src/list_of_manpages.inc      |    1 
 src/static-man/xcb-examples.3 |   59 ++++
 src/static-man/xcb-requests.3 |  165 +++++++++++
 5 files changed, 827 insertions(+), 6 deletions(-)

New commits:
commit cc7fab2d5e912629d4a2a6adfb7666dc2ba45db2
Author: Julien Danjou <julien at danjou.info>
Date:   Mon Mar 26 18:29:35 2012 +0200

    Allow undocumented code to be built
    
    Signed-off-by: Julien Danjou <julien at danjou.info>

diff --git a/src/c_client.py b/src/c_client.py
index 8382bb5..d006d30 100644
--- a/src/c_client.py
+++ b/src/c_client.py
@@ -271,7 +271,7 @@ def c_enum(self, name):
         equals = ' = ' if eval != '' else ''
         comma = ',' if count > 0 else ''
         doc = ''
-        if self.doc and enam in self.doc.fields:
+        if hasattr(self, "doc") and self.doc and enam in self.doc.fields:
             doc = '\n/**< %s */\n' % self.doc.fields[enam]
         _h('    %s%s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma, doc)
 
@@ -1890,7 +1890,7 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
     _c_setlevel(1)
     _h('')
     _h('/**')
-    if self.doc:
+    if hasattr(self, "doc") and self.doc:
         if self.doc.brief:
             _h(' * @brief ' + self.doc.brief)
         else:
@@ -1899,7 +1899,7 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
     _h(' *')
     _h(' * @param c The connection')
     param_names = [f.c_field_name for f in param_fields]
-    if self.doc:
+    if hasattr(self, "doc") and self.doc:
         for field in param_fields:
             # XXX: hard-coded until we fix xproto.xml
             base_func_name = self.c_request_name if not aux else self.c_aux_name
@@ -1931,7 +1931,7 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
     _h(' * @return A cookie')
     _h(' *')
 
-    if self.doc:
+    if hasattr(self, "doc") and self.doc:
         if self.doc.description:
             desc = self.doc.description
             for name in param_names:
@@ -2281,7 +2281,7 @@ def _man_request(self, name, cookie_type, void, aux):
     # Left-adjust instead of adjusting to both sides
     f.write('.ad l\n')
     f.write('.SH NAME\n')
-    brief = self.doc.brief if self.doc else ''
+    brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
     f.write('%s \\- %s\n' % (func_name, brief))
     f.write('.SH SYNOPSIS\n')
     # Don't split words (hyphenate)
@@ -2500,7 +2500,7 @@ def _man_request(self, name, cookie_type, void, aux):
             field.enum = 'CW'
         elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
             field.enum = 'CW'
-        if field.enum:
+        if hasattr(field, "enum") and field.enum:
             # XXX: why the 'xcb' prefix?
             key = ('xcb', field.enum)
             if key in enums:
@@ -2511,7 +2511,7 @@ def _man_request(self, name, cookie_type, void, aux):
                 for (enam, eval) in enum.values:
                     count = count - 1
                     f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
-                    if enum.doc and enam in enum.doc.fields:
+                    if hasattr(enum, "doc") and enum.doc and enam in enum.doc.fields:
                         desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
                         f.write('%s\n' % desc)
                     else:
@@ -2520,7 +2520,7 @@ def _man_request(self, name, cookie_type, void, aux):
                 f.write('.RS 1i\n')
                 printed_enum = True
 
-        if self.doc and field.field_name in self.doc.fields:
+        if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
             desc = self.doc.fields[field.field_name]
             desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
             if printed_enum:
@@ -2555,7 +2555,7 @@ def _man_request(self, name, cookie_type, void, aux):
                 continue
             f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
             printed_enum = False
-            if field.enum:
+            if hasattr(field, "enum") and field.enum:
                 # XXX: why the 'xcb' prefix?
                 key = ('xcb', field.enum)
                 if key in enums:
@@ -2575,7 +2575,7 @@ def _man_request(self, name, cookie_type, void, aux):
                     f.write('.RS 1i\n')
                     printed_enum = True
 
-            if self.reply.doc and field.field_name in self.reply.doc.fields:
+            if hasattr(self.reply, "doc") and self.reply.doc and field.field_name in self.reply.doc.fields:
                 desc = self.reply.doc.fields[field.field_name]
                 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
                 if printed_enum:
@@ -2590,7 +2590,7 @@ def _man_request(self, name, cookie_type, void, aux):
 
     # text description
     f.write('.SH DESCRIPTION\n')
-    if self.doc and self.doc.description:
+    if hasattr(self, "doc") and self.doc and self.doc.description:
         desc = self.doc.description
         desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
         lines = desc.split('\n')
@@ -2611,14 +2611,14 @@ def _man_request(self, name, cookie_type, void, aux):
                  'details.\n') %
                 (cookie_type, self.c_reply_name, base_func_name))
     f.write('.SH ERRORS\n')
-    if self.doc:
+    if hasattr(self, "doc") and self.doc:
         for errtype, errtext in self.doc.errors.iteritems():
             f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
             errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
             f.write('%s\n' % (errtext))
-    if not self.doc or len(self.doc.errors) == 0:
+    if not hasattr(self, "doc") or not self.doc or len(self.doc.errors) == 0:
         f.write('This request does never generate any errors.\n')
-    if self.doc and self.doc.example:
+    if hasattr(self, "doc") and self.doc and self.doc.example:
         f.write('.SH EXAMPLE\n')
         f.write('.nf\n')
         f.write('.sp\n')
@@ -2626,7 +2626,7 @@ def _man_request(self, name, cookie_type, void, aux):
         f.write('\n'.join(lines) + '\n')
         f.write('.fi\n')
     f.write('.SH SEE ALSO\n')
-    if self.doc:
+    if hasattr(self, "doc") and self.doc:
         see = ['.BR %s (3)' % 'xcb-requests']
         if self.doc.example:
             see.append('.BR %s (3)' % 'xcb-examples')
@@ -2655,7 +2655,7 @@ def _man_event(self, name):
     # Left-adjust instead of adjusting to both sides
     f.write('.ad l\n')
     f.write('.SH NAME\n')
-    brief = self.doc.brief if self.doc else ''
+    brief = self.doc.brief if hasattr(self, "doc") and self.doc else ''
     f.write('%s \\- %s\n' % (self.c_type, brief))
     f.write('.SH SYNOPSIS\n')
     # Don't split words (hyphenate)
@@ -2733,7 +2733,7 @@ def _man_event(self, name):
             if isinstance(field.type, PadType):
                 continue
             f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
-            if self.doc and field.field_name in self.doc.fields:
+            if hasattr(self, "doc") and self.doc and field.field_name in self.doc.fields:
                 desc = self.doc.fields[field.field_name]
                 desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
                 f.write('%s\n' % desc)
@@ -2742,13 +2742,13 @@ def _man_event(self, name):
 
     # text description
     f.write('.SH DESCRIPTION\n')
-    if self.doc and self.doc.description:
+    if hasattr(self, "doc") and self.doc and self.doc.description:
         desc = self.doc.description
         desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
         lines = desc.split('\n')
         f.write('\n'.join(lines) + '\n')
 
-    if self.doc and self.doc.example:
+    if hasattr(self, "doc") and self.doc and self.doc.example:
         f.write('.SH EXAMPLE\n')
         f.write('.nf\n')
         f.write('.sp\n')
@@ -2756,7 +2756,7 @@ def _man_event(self, name):
         f.write('\n'.join(lines) + '\n')
         f.write('.fi\n')
     f.write('.SH SEE ALSO\n')
-    if self.doc:
+    if hasattr(self, "doc") and self.doc:
         see = ['.BR %s (3)' % 'xcb_generic_event_t']
         if self.doc.example:
             see.append('.BR %s (3)' % 'xcb-examples')
commit ea71d7d7e3f5d8189b80747678e9ca9a417b1d37
Author: Michael Stapelberg <michael at stapelberg.de>
Date:   Sun Nov 27 10:38:26 2011 +0000

    c_client.py: generate manpages
    
    Signed-off-by: Julien Danjou <julien at danjou.info>

diff --git a/src/Makefile.am b/src/Makefile.am
index 950de5c..5bcb461 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -225,8 +225,12 @@ endif
 nodist_xcbinclude_HEADERS = $(EXTHEADERS)
 noinst_HEADERS = xcbint.h
 
-BUILT_SOURCES = $(EXTSOURCES)
-CLEANFILES = $(EXTSOURCES) $(EXTHEADERS)
+BUILT_SOURCES = $(EXTSOURCES) $(man_MANS)
+CLEANFILES = $(EXTSOURCES) $(EXTHEADERS) $(man_MANS)
+
+include $(srcdir)/list_of_manpages.inc
 
 $(EXTSOURCES): c_client.py
 	$(PYTHON) $(srcdir)/c_client.py -p $(XCBPROTO_XCBPYTHONDIR) $(XCBPROTO_XCBINCLUDEDIR)/$(@:.c=.xml)
+
+$(man_MANS): $(EXTSOURCES)
diff --git a/src/c_client.py b/src/c_client.py
index ad3ea22..8382bb5 100644
--- a/src/c_client.py
+++ b/src/c_client.py
@@ -3,7 +3,9 @@ from xml.etree.cElementTree import *
 from os.path import basename
 from functools import reduce
 import getopt
+import os
 import sys
+import time
 import re
 
 # Jump to the bottom of this file for the main routine
@@ -31,6 +33,11 @@ finished_serializers = []
 finished_sizeof = []
 finished_switch = []
 
+# keeps enum objects so that we can refer to them when generating manpages.
+enums = {}
+
+manpaths = False
+
 def _h(fmt, *args):
     '''
     Writes the given line to the header file.
@@ -247,6 +254,8 @@ def c_enum(self, name):
     Exported function that handles enum declarations.
     '''
 
+    enums[name] = self
+
     tname = _t(name)
     if namecount[tname] > 1:
         tname = _t(name + ('enum',))
@@ -261,7 +270,10 @@ def c_enum(self, name):
         count = count - 1
         equals = ' = ' if eval != '' else ''
         comma = ',' if count > 0 else ''
-        _h('    %s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma)
+        doc = ''
+        if self.doc and enam in self.doc.fields:
+            doc = '\n/**< %s */\n' % self.doc.fields[enam]
+        _h('    %s%s%s%s%s', _n(name + (enam,)).upper(), equals, eval, comma, doc)
 
     _h('} %s;', tname)
 
@@ -1878,11 +1890,58 @@ def _c_request_helper(self, name, cookie_type, void, regular, aux=False):
     _c_setlevel(1)
     _h('')
     _h('/**')
-    _h(' * Delivers a request to the X server')
+    if self.doc:
+        if self.doc.brief:
+            _h(' * @brief ' + self.doc.brief)
+        else:
+            _h(' * No brief doc yet')
+
+    _h(' *')
     _h(' * @param c The connection')
+    param_names = [f.c_field_name for f in param_fields]
+    if self.doc:
+        for field in param_fields:
+            # XXX: hard-coded until we fix xproto.xml
+            base_func_name = self.c_request_name if not aux else self.c_aux_name
+            if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
+                field.enum = 'GC'
+            elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
+                field.enum = 'CW'
+            elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
+                field.enum = 'CW'
+            if field.enum:
+                # XXX: why the 'xcb' prefix?
+                key = ('xcb', field.enum)
+
+                tname = _t(key)
+                if namecount[tname] > 1:
+                    tname = _t(key + ('enum',))
+                _h(' * @param %s A bitmask of #%s values.' % (field.c_field_name, tname))
+
+            if self.doc and field.field_name in self.doc.fields:
+                desc = self.doc.fields[field.field_name]
+                for name in param_names:
+                    desc = desc.replace('`%s`' % name, '\\a %s' % (name))
+                desc = desc.split("\n")
+                desc = [line if line != '' else '\\n' for line in desc]
+                _h(' * @param %s %s' % (field.c_field_name, "\n * ".join(desc)))
+            # If there is no documentation yet, we simply don't generate an
+            # @param tag. Doxygen will then warn about missing documentation.
+
     _h(' * @return A cookie')
     _h(' *')
-    _h(' * Delivers a request to the X server.')
+
+    if self.doc:
+        if self.doc.description:
+            desc = self.doc.description
+            for name in param_names:
+                desc = desc.replace('`%s`' % name, '\\a %s' % (name))
+            desc = desc.split("\n")
+            _h(' * ' + "\n * ".join(desc))
+        else:
+            _h(' * No description yet')
+    else:
+        _h(' * Delivers a request to the X server.')
     _h(' * ')
     if checked:
         _h(' * This form can be used only if the request will not cause')
@@ -2201,6 +2260,523 @@ def _c_cookie(self, name):
     _h('    unsigned int sequence; /**<  */')
     _h('} %s;', self.c_cookie_type)
 
+def _man_request(self, name, cookie_type, void, aux):
+    param_fields = [f for f in self.fields if f.visible]
+
+    func_name = self.c_request_name if not aux else self.c_aux_name
+
+    def create_link(linkname):
+        name = 'man/%s.3' % linkname
+        if manpaths:
+            sys.stdout.write(name)
+        f = open(name, 'w')
+        f.write('.so man3/%s.3' % func_name)
+        f.close()
+
+    if manpaths:
+        sys.stdout.write('man/%s.3 ' % func_name)
+    # Our CWD is src/, so this will end up in src/man/
+    f = open('man/%s.3' % func_name, 'w')
+    f.write('.TH %s 3  %s "XCB" "XCB Requests"\n' % (func_name, today))
+    # Left-adjust instead of adjusting to both sides
+    f.write('.ad l\n')
+    f.write('.SH NAME\n')
+    brief = self.doc.brief if self.doc else ''
+    f.write('%s \\- %s\n' % (func_name, brief))
+    f.write('.SH SYNOPSIS\n')
+    # Don't split words (hyphenate)
+    f.write('.hy 0\n')
+    f.write('.B #include <xcb/%s.h>\n' % _ns.header)
+
+    # function prototypes
+    prototype = ''
+    count = len(param_fields)
+    for field in param_fields:
+        count = count - 1
+        c_field_const_type = field.c_field_const_type
+        c_pointer = field.c_pointer
+        if c_pointer == ' ':
+            c_pointer = ''
+        if field.type.need_serialize and not aux:
+            c_field_const_type = "const void"
+            c_pointer = '*'
+        comma = ', ' if count else ');'
+        prototype += '%s\\ %s\\fI%s\\fP%s' % (c_field_const_type, c_pointer, field.c_field_name, comma)
+
+    f.write('.SS Request function\n')
+    f.write('.HP\n')
+    base_func_name = self.c_request_name if not aux else self.c_aux_name
+    f.write('%s \\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\n' % (cookie_type, base_func_name, prototype))
+    create_link('%s_%s' % (base_func_name, ('checked' if void else 'unchecked')))
+    if not void:
+        f.write('.PP\n')
+        f.write('.SS Reply datastructure\n')
+        f.write('.nf\n')
+        f.write('.sp\n')
+        f.write('typedef %s %s {\n' % (self.reply.c_container, self.reply.c_type))
+        struct_fields = []
+        maxtypelen = 0
+
+        for field in self.reply.fields:
+            if not field.type.fixed_size() and not self.is_switch and not self.is_union:
+                continue
+            if field.wire:
+                struct_fields.append(field)
+
+        for field in struct_fields:
+            length = len(field.c_field_type)
+            # account for '*' pointer_spec
+            if not field.type.fixed_size():
+                length += 1
+            maxtypelen = max(maxtypelen, length)
+
+        def _c_complex_field(self, field, space=''):
+            if (field.type.fixed_size() or
+                # in case of switch with switch children, don't make the field a pointer
+                # necessary for unserialize to work
+                (self.is_switch and field.type.is_switch)):
+                spacing = ' ' * (maxtypelen - len(field.c_field_type))
+                f.write('%s    %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
+            else:
+                spacing = ' ' * (maxtypelen - (len(field.c_field_type) + 1))
+                f.write('ELSE %s = %s\n' % (field.c_field_type, field.c_field_name))
+                #_h('%s    %s%s *%s%s; /**<  */', space, field.c_field_type, spacing, field.c_field_name, field.c_subscript)
+
+        if not self.is_switch:
+            for field in struct_fields:
+                _c_complex_field(self, field)
+        else:
+            for b in self.bitcases:
+                space = ''
+                if b.type.has_name:
+                    space = '    '
+                for field in b.type.fields:
+                    _c_complex_field(self, field, space)
+                if b.type.has_name:
+                    print >> sys.stderr, 'ERROR: New unhandled documentation case'
+                    pass
+
+        f.write('} \\fB%s\\fP;\n' % self.reply.c_type)
+        f.write('.fi\n')
+
+        f.write('.SS Reply function\n')
+        f.write('.HP\n')
+        f.write(('%s *\\fB%s\\fP(xcb_connection_t\\ *\\fIconn\\fP, %s\\ '
+                 '\\fIcookie\\fP, xcb_generic_error_t\\ **\\fIe\\fP);\n') %
+                (self.c_reply_type, self.c_reply_name, self.c_cookie_type))
+        create_link('%s' % self.c_reply_name)
+
+        has_accessors = False
+        for field in self.reply.fields:
+            if field.type.is_list and not field.type.fixed_size():
+                has_accessors = True
+            elif field.prev_varsized_field is not None or not field.type.fixed_size():
+                has_accessors = True
+
+        if has_accessors:
+            f.write('.SS Reply accessors\n')
+
+        def _c_accessors_field(self, field):
+            '''
+            Declares the accessor functions for a non-list field that follows a variable-length field.
+            '''
+            c_type = self.c_type
+
+            # special case: switch
+            switch_obj = self if self.is_switch else None
+            if self.is_bitcase:
+                switch_obj = self.parents[-1]
+            if switch_obj is not None:
+                c_type = switch_obj.c_type
+
+            if field.type.is_simple:
+                f.write('%s %s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
+                create_link('%s' % field.c_accessor_name)
+            else:
+                f.write('%s *%s (const %s *reply)\n' % (field.c_field_type, field.c_accessor_name, c_type))
+                create_link('%s' % field.c_accessor_name)
+
+        def _c_accessors_list(self, field):
+            '''
+            Declares the accessor functions for a list field.
+            Declares a direct-accessor function only if the list members are fixed size.
+            Declares length and get-iterator functions always.
+            '''
+            list = field.type
+            c_type = self.reply.c_type
+
+            # special case: switch
+            # in case of switch, 2 params have to be supplied to certain accessor functions:
+            #   1. the anchestor object (request or reply)
+            #   2. the (anchestor) switch object
+            # the reason is that switch is either a child of a request/reply or nested in another switch,
+            # so whenever we need to access a length field, we might need to refer to some anchestor type
+            switch_obj = self if self.is_switch else None
+            if self.is_bitcase:
+                switch_obj = self.parents[-1]
+            if switch_obj is not None:
+                c_type = switch_obj.c_type
+
+            params = []
+            fields = {}
+            parents = self.parents if hasattr(self, 'parents') else [self]
+            # 'R': parents[0] is always the 'toplevel' container type
+            params.append(('const %s *\\fIreply\\fP' % parents[0].c_type, parents[0]))
+            fields.update(_c_helper_field_mapping(parents[0], [('R', '->', parents[0])], flat=True))
+            # auxiliary object for 'R' parameters
+            R_obj = parents[0]
+
+            if switch_obj is not None:
+                # now look where the fields are defined that are needed to evaluate
+                # the switch expr, and store the parent objects in accessor_params and
+                # the fields in switch_fields
+
+                # 'S': name for the 'toplevel' switch
+                toplevel_switch = parents[1]
+                params.append(('const %s *S' % toplevel_switch.c_type, toplevel_switch))
+                fields.update(_c_helper_field_mapping(toplevel_switch, [('S', '->', toplevel_switch)], flat=True))
+
+                # initialize prefix for everything "below" S
+                prefix_str = '/* %s */ S' % toplevel_switch.name[-1]
+                prefix = [(prefix_str, '->', toplevel_switch)]
+
+                # look for fields in the remaining containers
+                for p in parents[2:] + [self]:
+                    # the separator between parent and child is always '.' here,
+                    # because of nested switch statements
+                    if not p.is_bitcase or (p.is_bitcase and p.has_name):
+                        prefix.append((p.name[-1], '.', p))
+                    fields.update(_c_helper_field_mapping(p, prefix, flat=True))
+
+                # auxiliary object for 'S' parameter
+                S_obj = parents[1]
+
+            if list.member.fixed_size():
+                idx = 1 if switch_obj is not None else 0
+                f.write('.HP\n')
+                f.write('%s *\\fB%s\\fP(%s);\n' %
+                        (field.c_field_type, field.c_accessor_name, params[idx][0]))
+                create_link('%s' % field.c_accessor_name)
+
+            f.write('.HP\n')
+            f.write('int \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
+                    (field.c_length_name, c_type))
+            create_link('%s' % field.c_length_name)
+
+            if field.type.member.is_simple:
+                f.write('.HP\n')
+                f.write('xcb_generic_iterator_t \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
+                        (field.c_end_name, c_type))
+                create_link('%s' % field.c_end_name)
+            else:
+                f.write('.HP\n')
+                f.write('%s \\fB%s\\fP(const %s *\\fIreply\\fP);\n' %
+                        (field.c_iterator_type, field.c_iterator_name,
+                         c_type))
+                create_link('%s' % field.c_iterator_name)
+
+        for field in self.reply.fields:
+            if field.type.is_list and not field.type.fixed_size():
+                _c_accessors_list(self, field)
+            elif field.prev_varsized_field is not None or not field.type.fixed_size():
+                _c_accessors_field(self, field)
+
+
+    f.write('.br\n')
+    # Re-enable hyphenation and adjusting to both sides
+    f.write('.hy 1\n')
+
+    # argument reference
+    f.write('.SH REQUEST ARGUMENTS\n')
+    f.write('.IP \\fI%s\\fP 1i\n' % 'conn')
+    f.write('The XCB connection to X11.\n')
+    for field in param_fields:
+        f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
+        printed_enum = False
+        # XXX: hard-coded until we fix xproto.xml
+        if base_func_name == 'xcb_change_gc' and field.c_field_name == 'value_mask':
+            field.enum = 'GC'
+        elif base_func_name == 'xcb_change_window_attributes' and field.c_field_name == 'value_mask':
+            field.enum = 'CW'
+        elif base_func_name == 'xcb_create_window' and field.c_field_name == 'value_mask':
+            field.enum = 'CW'
+        if field.enum:
+            # XXX: why the 'xcb' prefix?
+            key = ('xcb', field.enum)
+            if key in enums:
+                f.write('One of the following values:\n')
+                f.write('.RS 1i\n')
+                enum = enums[key]
+                count = len(enum.values)
+                for (enam, eval) in enum.values:
+                    count = count - 1
+                    f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
+                    if enum.doc and enam in enum.doc.fields:
+                        desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
+                        f.write('%s\n' % desc)
+                    else:
+                        f.write('TODO: NOT YET DOCUMENTED.\n')
+                f.write('.RE\n')
+                f.write('.RS 1i\n')
+                printed_enum = True
+
+        if self.doc and field.field_name in self.doc.fields:
+            desc = self.doc.fields[field.field_name]
+            desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
+            if printed_enum:
+                f.write('\n')
+            f.write('%s\n' % desc)
+        else:
+            f.write('TODO: NOT YET DOCUMENTED.\n')
+        if printed_enum:
+            f.write('.RE\n')
+
+    # Reply reference
+    if not void:
+        f.write('.SH REPLY FIELDS\n')
+        # These fields are present in every reply:
+        f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
+        f.write(('The type of this reply, in this case \\fI%s\\fP. This field '
+                 'is also present in the \\fIxcb_generic_reply_t\\fP and can '
+                 'be used to tell replies apart from each other.\n') %
+                 _n(self.reply.name).upper())
+        f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
+        f.write('The sequence number of the last request processed by the X11 server.\n')
+        f.write('.IP \\fI%s\\fP 1i\n' % 'length')
+        f.write('The length of the reply, in words (a word is 4 bytes).\n')
+        for field in self.reply.fields:
+            if (field.c_field_name in frozenset(['response_type', 'sequence', 'length']) or
+                field.c_field_name.startswith('pad')):
+                continue
+
+            if field.type.is_list and not field.type.fixed_size():
+                continue
+            elif field.prev_varsized_field is not None or not field.type.fixed_size():
+                continue
+            f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
+            printed_enum = False
+            if field.enum:
+                # XXX: why the 'xcb' prefix?
+                key = ('xcb', field.enum)
+                if key in enums:
+                    f.write('One of the following values:\n')
+                    f.write('.RS 1i\n')
+                    enum = enums[key]
+                    count = len(enum.values)
+                    for (enam, eval) in enum.values:
+                        count = count - 1
+                        f.write('.IP \\fI%s\\fP 1i\n' % (_n(key + (enam,)).upper()))
+                        if enum.doc and enam in enum.doc.fields:
+                            desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', enum.doc.fields[enam])
+                            f.write('%s\n' % desc)
+                        else:
+                            f.write('TODO: NOT YET DOCUMENTED.\n')
+                    f.write('.RE\n')
+                    f.write('.RS 1i\n')
+                    printed_enum = True
+
+            if self.reply.doc and field.field_name in self.reply.doc.fields:
+                desc = self.reply.doc.fields[field.field_name]
+                desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
+                if printed_enum:
+                    f.write('\n')
+                f.write('%s\n' % desc)
+            else:
+                f.write('TODO: NOT YET DOCUMENTED.\n')
+            if printed_enum:
+                f.write('.RE\n')
+
+
+
+    # text description
+    f.write('.SH DESCRIPTION\n')
+    if self.doc and self.doc.description:
+        desc = self.doc.description
+        desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
+        lines = desc.split('\n')
+        f.write('\n'.join(lines) + '\n')
+
+    f.write('.SH RETURN VALUE\n')
+    if void:
+        f.write(('Returns an \\fIxcb_void_cookie_t\\fP. Errors (if any) '
+                 'have to be handled in the event loop.\n\nIf you want to '
+                 'handle errors directly with \\fIxcb_request_check\\fP '
+                 'instead, use \\fI%s_checked\\fP. See '
+                 '\\fBxcb-requests(3)\\fP for details.\n') % (base_func_name))
+    else:
+        f.write(('Returns an \\fI%s\\fP. Errors have to be handled when '
+                 'calling the reply function \\fI%s\\fP.\n\nIf you want to '
+                 'handle errors in the event loop instead, use '
+                 '\\fI%s_unchecked\\fP. See \\fBxcb-requests(3)\\fP for '
+                 'details.\n') %
+                (cookie_type, self.c_reply_name, base_func_name))
+    f.write('.SH ERRORS\n')
+    if self.doc:
+        for errtype, errtext in self.doc.errors.iteritems():
+            f.write('.IP \\fI%s\\fP 1i\n' % (_t(('xcb', errtype, 'error'))))
+            errtext = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', errtext)
+            f.write('%s\n' % (errtext))
+    if not self.doc or len(self.doc.errors) == 0:
+        f.write('This request does never generate any errors.\n')
+    if self.doc and self.doc.example:
+        f.write('.SH EXAMPLE\n')
+        f.write('.nf\n')
+        f.write('.sp\n')
+        lines = self.doc.example.split('\n')
+        f.write('\n'.join(lines) + '\n')
+        f.write('.fi\n')
+    f.write('.SH SEE ALSO\n')
+    if self.doc:
+        see = ['.BR %s (3)' % 'xcb-requests']
+        if self.doc.example:
+            see.append('.BR %s (3)' % 'xcb-examples')
+        for seename, seetype in self.doc.see.iteritems():
+            if seetype == 'program':
+                see.append('.BR %s (1)' % seename)
+            elif seetype == 'event':
+                see.append('.BR %s (3)' % _t(('xcb', seename, 'event')))
+            elif seetype == 'request':
+                see.append('.BR %s (3)' % _n(('xcb', seename)))
+            elif seetype == 'function':
+                see.append('.BR %s (3)' % seename)
+            else:
+                see.append('TODO: %s (type %s)' % (seename, seetype))
+        f.write(',\n'.join(see) + '\n')
+    f.write('.SH AUTHOR\n')
+    f.write('Generated from %s.xml. Contact xcb at lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
+    f.close()
+
+def _man_event(self, name):
+    if manpaths:
+        sys.stdout.write('man/%s.3 ' % self.c_type)
+    # Our CWD is src/, so this will end up in src/man/
+    f = open('man/%s.3' % self.c_type, 'w')
+    f.write('.TH %s 3  %s "XCB" "XCB Events"\n' % (self.c_type, today))
+    # Left-adjust instead of adjusting to both sides
+    f.write('.ad l\n')
+    f.write('.SH NAME\n')
+    brief = self.doc.brief if self.doc else ''
+    f.write('%s \\- %s\n' % (self.c_type, brief))
+    f.write('.SH SYNOPSIS\n')
+    # Don't split words (hyphenate)
+    f.write('.hy 0\n')
+    f.write('.B #include <xcb/%s.h>\n' % _ns.header)
+
+    f.write('.PP\n')
+    f.write('.SS Event datastructure\n')
+    f.write('.nf\n')
+    f.write('.sp\n')
+    f.write('typedef %s %s {\n' % (self.c_container, self.c_type))
+    struct_fields = []
+    maxtypelen = 0
+
+    for field in self.fields:
+        if not field.type.fixed_size() and not self.is_switch and not self.is_union:
+            continue
+        if field.wire:
+            struct_fields.append(field)
+
+    for field in struct_fields:
+        length = len(field.c_field_type)
+        # account for '*' pointer_spec
+        if not field.type.fixed_size():
+            length += 1
+        maxtypelen = max(maxtypelen, length)
+
+    def _c_complex_field(self, field, space=''):
+        if (field.type.fixed_size() or
+            # in case of switch with switch children, don't make the field a pointer
+            # necessary for unserialize to work
+            (self.is_switch and field.type.is_switch)):
+            spacing = ' ' * (maxtypelen - len(field.c_field_type))
+            f.write('%s    %s%s \\fI%s\\fP%s;\n' % (space, field.c_field_type, spacing, field.c_field_name, field.c_subscript))
+        else:
+            print >> sys.stderr, 'ERROR: New unhandled documentation case'
+
+    if not self.is_switch:
+        for field in struct_fields:
+            _c_complex_field(self, field)
+    else:
+        for b in self.bitcases:
+            space = ''
+            if b.type.has_name:
+                space = '    '
+            for field in b.type.fields:
+                _c_complex_field(self, field, space)
+            if b.type.has_name:
+                print >> sys.stderr, 'ERROR: New unhandled documentation case'
+                pass
+
+    f.write('} \\fB%s\\fP;\n' % self.c_type)
+    f.write('.fi\n')
+
+
+    f.write('.br\n')
+    # Re-enable hyphenation and adjusting to both sides
+    f.write('.hy 1\n')
+
+    # argument reference
+    f.write('.SH EVENT FIELDS\n')
+    f.write('.IP \\fI%s\\fP 1i\n' % 'response_type')
+    f.write(('The type of this event, in this case \\fI%s\\fP. This field is '
+             'also present in the \\fIxcb_generic_event_t\\fP and can be used '
+             'to tell events apart from each other.\n') % _n(name).upper())
+    f.write('.IP \\fI%s\\fP 1i\n' % 'sequence')
+    f.write('The sequence number of the last request processed by the X11 server.\n')
+
+    if not self.is_switch:
+        for field in struct_fields:
+            # Skip the fields which every event has, we already documented
+            # them (see above).
+            if field.c_field_name in ('response_type', 'sequence'):
+                continue
+            if isinstance(field.type, PadType):
+                continue
+            f.write('.IP \\fI%s\\fP 1i\n' % (field.c_field_name))
+            if self.doc and field.field_name in self.doc.fields:
+                desc = self.doc.fields[field.field_name]
+                desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
+                f.write('%s\n' % desc)
+            else:
+                f.write('NOT YET DOCUMENTED.\n')
+
+    # text description
+    f.write('.SH DESCRIPTION\n')
+    if self.doc and self.doc.description:
+        desc = self.doc.description
+        desc = re.sub(r'`([^`]+)`', r'\\fI\1\\fP', desc)
+        lines = desc.split('\n')
+        f.write('\n'.join(lines) + '\n')
+
+    if self.doc and self.doc.example:
+        f.write('.SH EXAMPLE\n')
+        f.write('.nf\n')
+        f.write('.sp\n')
+        lines = self.doc.example.split('\n')
+        f.write('\n'.join(lines) + '\n')
+        f.write('.fi\n')
+    f.write('.SH SEE ALSO\n')
+    if self.doc:
+        see = ['.BR %s (3)' % 'xcb_generic_event_t']
+        if self.doc.example:
+            see.append('.BR %s (3)' % 'xcb-examples')
+        for seename, seetype in self.doc.see.iteritems():
+            if seetype == 'program':
+                see.append('.BR %s (1)' % seename)
+            elif seetype == 'event':
+                see.append('.BR %s (3)' % _t(('xcb', seename, 'event')))
+            elif seetype == 'request':
+                see.append('.BR %s (3)' % _n(('xcb', seename)))
+            elif seetype == 'function':
+                see.append('.BR %s (3)' % seename)
+            else:
+                see.append('TODO: %s (type %s)' % (seename, seetype))
+        f.write(',\n'.join(see) + '\n')
+    f.write('.SH AUTHOR\n')
+    f.write('Generated from %s.xml. Contact xcb at lists.freedesktop.org for corrections and improvements.\n' % _ns.header)
+    f.close()
+
+
 def c_request(self, name):
     '''
     Exported function that handles request declarations.
@@ -2238,6 +2814,10 @@ def c_request(self, name):
             _c_request_helper(self, name, 'xcb_void_cookie_t', True, False, True)
             _c_request_helper(self, name, 'xcb_void_cookie_t', True, True, True)
 
+    # We generate the manpage afterwards because _c_type_setup has been called.
+    # TODO: what about aux helpers?
+    cookie_type = self.c_cookie_type if self.reply else 'xcb_void_cookie_t'
+    _man_request(self, name, cookie_type, not self.reply, False)
 
 def c_event(self, name):
     '''
@@ -2256,6 +2836,8 @@ def c_event(self, name):
         _h('')
         _h('typedef %s %s;', _t(self.name + ('event',)), _t(name + ('event',)))
 
+    _man_event(self, name)
+
 def c_error(self, name):
     '''
     Exported function that handles error declarations.
@@ -2292,7 +2874,7 @@ output = {'open'    : c_open,
 
 # Check for the argument that specifies path to the xcbgen python package.
 try:
-    opts, args = getopt.getopt(sys.argv[1:], 'p:')
+    opts, args = getopt.getopt(sys.argv[1:], 'p:m')
 except getopt.GetoptError as err:
     print(err)
     print('Usage: c_client.py [-p path] file.xml')
@@ -2301,10 +2883,14 @@ except getopt.GetoptError as err:
 for (opt, arg) in opts:
     if opt == '-p':
         sys.path.insert(1, arg)
+    elif opt == '-m':
+        manpaths = True
+        sys.stdout.write('man_MANS = ')
 
 # Import the module class
 try:
     from xcbgen.state import Module
+    from xcbgen.xtypes import *
 except ImportError:
     print('''
 Failed to load the xcbgen Python package!
@@ -2315,6 +2901,12 @@ Refer to the README file in xcb/proto for more info.
 ''')
     raise
 
+# Ensure the man subdirectory exists
+if not os.path.exists('man'):
+    os.mkdir('man')
+
+today = time.strftime('%Y-%m-%d', time.gmtime(os.path.getmtime(args[0])))
+
 # Parse the xml header
 module = Module(args[0], output)
 
diff --git a/src/list_of_manpages.inc b/src/list_of_manpages.inc
new file mode 100644
index 0000000..6f06303
--- /dev/null
+++ b/src/list_of_manpages.inc
@@ -0,0 +1 @@
+man_MANS = static-man/xcb-examples.3 static-man/xcb-requests.3 man/xcb_create_window.3 man/xcb_create_window_checked.3 man/xcb_change_window_attributes.3 man/xcb_change_window_attributes_checked.3 man/xcb_get_window_attributes.3 man/xcb_get_window_attributes_unchecked.3 man/xcb_get_window_attributes_reply.3 man/xcb_destroy_window.3 man/xcb_destroy_window_checked.3 man/xcb_destroy_subwindows.3 man/xcb_destroy_subwindows_checked.3 man/xcb_change_save_set.3 man/xcb_change_save_set_checked.3 man/xcb_reparent_window.3 man/xcb_reparent_window_checked.3 man/xcb_map_window.3 man/xcb_map_window_checked.3 man/xcb_map_subwindows.3 man/xcb_map_subwindows_checked.3 man/xcb_unmap_window.3 man/xcb_unmap_window_checked.3 man/xcb_unmap_subwindows.3 man/xcb_unmap_subwindows_checked.3 man/xcb_configure_window.3 man/xcb_configure_window_checked.3 man/xcb_circulate_window.3 man/xcb_circulate_window_checked.3 man/xcb_get_geometry.3 man/xcb_get_geometry_unchecked.3 man/xcb_get_geometry_reply.3 man
 /xcb_query_tree.3 man/xcb_query_tree_unchecked.3 man/xcb_query_tree_reply.3 man/xcb_query_tree_children.3 man/xcb_query_tree_children_length.3 man/xcb_query_tree_children_end.3 man/xcb_intern_atom.3 man/xcb_intern_atom_unchecked.3 man/xcb_intern_atom_reply.3 man/xcb_get_atom_name.3 man/xcb_get_atom_name_unchecked.3 man/xcb_get_atom_name_reply.3 man/xcb_get_atom_name_name.3 man/xcb_get_atom_name_name_length.3 man/xcb_get_atom_name_name_end.3 man/xcb_change_property.3 man/xcb_change_property_checked.3 man/xcb_delete_property.3 man/xcb_delete_property_checked.3 man/xcb_get_property.3 man/xcb_get_property_unchecked.3 man/xcb_get_property_reply.3 man/xcb_get_property_value.3 man/xcb_get_property_value_length.3 man/xcb_get_property_value_end.3 man/xcb_list_properties.3 man/xcb_list_properties_unchecked.3 man/xcb_list_properties_reply.3 man/xcb_list_properties_atoms.3 man/xcb_list_properties_atoms_length.3 man/xcb_list_properties_atoms_end.3 man/xcb_set_selection_owner.3 man/xcb_se
 t_selection_owner_checked.3 man/xcb_get_selection_owner.3 man/xcb_get_selection_owner_unchecked.3 man/xcb_get_selection_owner_reply.3 man/xcb_convert_selection.3 man/xcb_convert_selection_checked.3 man/xcb_send_event.3 man/xcb_send_event_checked.3 man/xcb_grab_pointer.3 man/xcb_grab_pointer_unchecked.3 man/xcb_grab_pointer_reply.3 man/xcb_ungrab_pointer.3 man/xcb_ungrab_pointer_checked.3 man/xcb_grab_button.3 man/xcb_grab_button_checked.3 man/xcb_ungrab_button.3 man/xcb_ungrab_button_checked.3 man/xcb_change_active_pointer_grab.3 man/xcb_change_active_pointer_grab_checked.3 man/xcb_grab_keyboard.3 man/xcb_grab_keyboard_unchecked.3 man/xcb_grab_keyboard_reply.3 man/xcb_ungrab_keyboard.3 man/xcb_ungrab_keyboard_checked.3 man/xcb_grab_key.3 man/xcb_grab_key_checked.3 man/xcb_ungrab_key.3 man/xcb_ungrab_key_checked.3 man/xcb_allow_events.3 man/xcb_allow_events_checked.3 man/xcb_grab_server.3 man/xcb_grab_server_checked.3 man/xcb_ungrab_server.3 man/xcb_ungrab_server_checked.3 ma
 n/xcb_query_pointer.3 man/xcb_query_pointer_unchecked.3 man/xcb_query_pointer_reply.3 man/xcb_get_motion_events.3 man/xcb_get_motion_events_unchecked.3 man/xcb_get_motion_events_reply.3 man/xcb_get_motion_events_events.3 man/xcb_get_motion_events_events_length.3 man/xcb_get_motion_events_events_iterator.3 man/xcb_translate_coordinates.3 man/xcb_translate_coordinates_unchecked.3 man/xcb_translate_coordinates_reply.3 man/xcb_warp_pointer.3 man/xcb_warp_pointer_checked.3 man/xcb_set_input_focus.3 man/xcb_set_input_focus_checked.3 man/xcb_get_input_focus.3 man/xcb_get_input_focus_unchecked.3 man/xcb_get_input_focus_reply.3 man/xcb_query_keymap.3 man/xcb_query_keymap_unchecked.3 man/xcb_query_keymap_reply.3 man/xcb_open_font.3 man/xcb_open_font_checked.3 man/xcb_close_font.3 man/xcb_close_font_checked.3 man/xcb_query_font.3 man/xcb_query_font_unchecked.3 man/xcb_query_font_reply.3 man/xcb_query_font_properties.3 man/xcb_query_font_properties_length.3 man/xcb_query_font_properties
 _iterator.3 man/xcb_query_font_char_infos.3 man/xcb_query_font_char_infos_length.3 man/xcb_query_font_char_infos_iterator.3 man/xcb_query_text_extents.3 man/xcb_query_text_extents_unchecked.3 man/xcb_query_text_extents_reply.3 man/xcb_list_fonts.3 man/xcb_list_fonts_unchecked.3 man/xcb_list_fonts_reply.3 man/xcb_list_fonts_names_length.3 man/xcb_list_fonts_names_iterator.3 man/xcb_list_fonts_with_info.3 man/xcb_list_fonts_with_info_unchecked.3 man/xcb_list_fonts_with_info_reply.3 man/xcb_list_fonts_with_info_properties.3 man/xcb_list_fonts_with_info_properties_length.3 man/xcb_list_fonts_with_info_properties_iterator.3 man/xcb_list_fonts_with_info_name.3 man/xcb_list_fonts_with_info_name_length.3 man/xcb_list_fonts_with_info_name_end.3 man/xcb_set_font_path.3 man/xcb_set_font_path_checked.3 man/xcb_get_font_path.3 man/xcb_get_font_path_unchecked.3 man/xcb_get_font_path_reply.3 man/xcb_get_font_path_path_length.3 man/xcb_get_font_path_path_iterator.3 man/xcb_create_pixmap.3 m
 an/xcb_create_pixmap_checked.3 man/xcb_free_pixmap.3 man/xcb_free_pixmap_checked.3 man/xcb_create_gc.3 man/xcb_create_gc_checked.3 man/xcb_change_gc.3 man/xcb_change_gc_checked.3 man/xcb_copy_gc.3 man/xcb_copy_gc_checked.3 man/xcb_set_dashes.3 man/xcb_set_dashes_checked.3 man/xcb_set_clip_rectangles.3 man/xcb_set_clip_rectangles_checked.3 man/xcb_free_gc.3 man/xcb_free_gc_checked.3 man/xcb_clear_area.3 man/xcb_clear_area_checked.3 man/xcb_copy_area.3 man/xcb_copy_area_checked.3 man/xcb_copy_plane.3 man/xcb_copy_plane_checked.3 man/xcb_poly_point.3 man/xcb_poly_point_checked.3 man/xcb_poly_line.3 man/xcb_poly_line_checked.3 man/xcb_poly_segment.3 man/xcb_poly_segment_checked.3 man/xcb_poly_rectangle.3 man/xcb_poly_rectangle_checked.3 man/xcb_poly_arc.3 man/xcb_poly_arc_checked.3 man/xcb_fill_poly.3 man/xcb_fill_poly_checked.3 man/xcb_poly_fill_rectangle.3 man/xcb_poly_fill_rectangle_checked.3 man/xcb_poly_fill_arc.3 man/xcb_poly_fill_arc_checked.3 man/xcb_put_image.3 man/xcb_
 put_image_checked.3 man/xcb_get_image.3 man/xcb_get_image_unchecked.3 man/xcb_get_image_reply.3 man/xcb_get_image_data.3 man/xcb_get_image_data_length.3 man/xcb_get_image_data_end.3 man/xcb_poly_text_8.3 man/xcb_poly_text_8_checked.3 man/xcb_poly_text_16.3 man/xcb_poly_text_16_checked.3 man/xcb_image_text_8.3 man/xcb_image_text_8_checked.3 man/xcb_image_text_16.3 man/xcb_image_text_16_checked.3 man/xcb_create_colormap.3 man/xcb_create_colormap_checked.3 man/xcb_free_colormap.3 man/xcb_free_colormap_checked.3 man/xcb_copy_colormap_and_free.3 man/xcb_copy_colormap_and_free_checked.3 man/xcb_install_colormap.3 man/xcb_install_colormap_checked.3 man/xcb_uninstall_colormap.3 man/xcb_uninstall_colormap_checked.3 man/xcb_list_installed_colormaps.3 man/xcb_list_installed_colormaps_unchecked.3 man/xcb_list_installed_colormaps_reply.3 man/xcb_list_installed_colormaps_cmaps.3 man/xcb_list_installed_colormaps_cmaps_length.3 man/xcb_list_installed_colormaps_cmaps_end.3 man/xcb_alloc_colo
 r.3 man/xcb_alloc_color_unchecked.3 man/xcb_alloc_color_reply.3 man/xcb_alloc_named_color.3 man/xcb_alloc_named_color_unchecked.3 man/xcb_alloc_named_color_reply.3 man/xcb_alloc_color_cells.3 man/xcb_alloc_color_cells_unchecked.3 man/xcb_alloc_color_cells_reply.3 man/xcb_alloc_color_cells_pixels.3 man/xcb_alloc_color_cells_pixels_length.3 man/xcb_alloc_color_cells_pixels_end.3 man/xcb_alloc_color_cells_masks.3 man/xcb_alloc_color_cells_masks_length.3 man/xcb_alloc_color_cells_masks_end.3 man/xcb_alloc_color_planes.3 man/xcb_alloc_color_planes_unchecked.3 man/xcb_alloc_color_planes_reply.3 man/xcb_alloc_color_planes_pixels.3 man/xcb_alloc_color_planes_pixels_length.3 man/xcb_alloc_color_planes_pixels_end.3 man/xcb_free_colors.3 man/xcb_free_colors_checked.3 man/xcb_store_colors.3 man/xcb_store_colors_checked.3 man/xcb_store_named_color.3 man/xcb_store_named_color_checked.3 man/xcb_query_colors.3 man/xcb_query_colors_unchecked.3 man/xcb_query_colors_reply.3 man/xcb_query_color
 s_colors.3 man/xcb_query_colors_colors_length.3 man/xcb_query_colors_colors_iterator.3 man/xcb_lookup_color.3 man/xcb_lookup_color_unchecked.3 man/xcb_lookup_color_reply.3 man/xcb_create_cursor.3 man/xcb_create_cursor_checked.3 man/xcb_create_glyph_cursor.3 man/xcb_create_glyph_cursor_checked.3 man/xcb_free_cursor.3 man/xcb_free_cursor_checked.3 man/xcb_recolor_cursor.3 man/xcb_recolor_cursor_checked.3 man/xcb_query_best_size.3 man/xcb_query_best_size_unchecked.3 man/xcb_query_best_size_reply.3 man/xcb_query_extension.3 man/xcb_query_extension_unchecked.3 man/xcb_query_extension_reply.3 man/xcb_list_extensions.3 man/xcb_list_extensions_unchecked.3 man/xcb_list_extensions_reply.3 man/xcb_list_extensions_names_length.3 man/xcb_list_extensions_names_iterator.3 man/xcb_change_keyboard_mapping.3 man/xcb_change_keyboard_mapping_checked.3 man/xcb_get_keyboard_mapping.3 man/xcb_get_keyboard_mapping_unchecked.3 man/xcb_get_keyboard_mapping_reply.3 man/xcb_get_keyboard_mapping_keysyms
 .3 man/xcb_get_keyboard_mapping_keysyms_length.3 man/xcb_get_keyboard_mapping_keysyms_end.3 man/xcb_change_keyboard_control.3 man/xcb_change_keyboard_control_checked.3 man/xcb_get_keyboard_control.3 man/xcb_get_keyboard_control_unchecked.3 man/xcb_get_keyboard_control_reply.3 man/xcb_bell.3 man/xcb_bell_checked.3 man/xcb_change_pointer_control.3 man/xcb_change_pointer_control_checked.3 man/xcb_get_pointer_control.3 man/xcb_get_pointer_control_unchecked.3 man/xcb_get_pointer_control_reply.3 man/xcb_set_screen_saver.3 man/xcb_set_screen_saver_checked.3 man/xcb_get_screen_saver.3 man/xcb_get_screen_saver_unchecked.3 man/xcb_get_screen_saver_reply.3 man/xcb_change_hosts.3 man/xcb_change_hosts_checked.3 man/xcb_list_hosts.3 man/xcb_list_hosts_unchecked.3 man/xcb_list_hosts_reply.3 man/xcb_list_hosts_hosts_length.3 man/xcb_list_hosts_hosts_iterator.3 man/xcb_set_access_control.3 man/xcb_set_access_control_checked.3 man/xcb_set_close_down_mode.3 man/xcb_set_close_down_mode_checked.
 3 man/xcb_kill_client.3 man/xcb_kill_client_checked.3 man/xcb_rotate_properties.3 man/xcb_rotate_properties_checked.3 man/xcb_force_screen_saver.3 man/xcb_force_screen_saver_checked.3 man/xcb_set_pointer_mapping.3 man/xcb_set_pointer_mapping_unchecked.3 man/xcb_set_pointer_mapping_reply.3 man/xcb_get_pointer_mapping.3 man/xcb_get_pointer_mapping_unchecked.3 man/xcb_get_pointer_mapping_reply.3 man/xcb_get_pointer_mapping_map.3 man/xcb_get_pointer_mapping_map_length.3 man/xcb_get_pointer_mapping_map_end.3 man/xcb_set_modifier_mapping.3 man/xcb_set_modifier_mapping_unchecked.3 man/xcb_set_modifier_mapping_reply.3 man/xcb_get_modifier_mapping.3 man/xcb_get_modifier_mapping_unchecked.3 man/xcb_get_modifier_mapping_reply.3 man/xcb_get_modifier_mapping_keycodes.3 man/xcb_get_modifier_mapping_keycodes_length.3 man/xcb_get_modifier_mapping_keycodes_end.3 man/xcb_no_operation.3 man/xcb_no_operation_checked.3
diff --git a/src/static-man/xcb-examples.3 b/src/static-man/xcb-examples.3
new file mode 100644
index 0000000..291af37
--- /dev/null
+++ b/src/static-man/xcb-examples.3
@@ -0,0 +1,59 @@
+.TH xcb-examples 3 2011-12-11 "XCB" "XCB examples"
+.ad l
+.SH NAME
+xcb-examples \- manpage examples
+.SH DESCRIPTION
+Many of the XCB manpages contain example code. These examples intend to explain
+how to use one particular part of XCB. They almost never represent a standalone
+(or even useful) program - X11 programs are relatively involved and
+thus beyond the scope of a manpage example.
+
+.SH ENVIRONMENT
+
+Every example assumes you have an \fIxcb_connection\fP and possibly other
+variables at hand. For illustrating how \fIxcb_get_property\fP works, you need
+the window of which you want to get the property, for example. To make it clear
+that these variables are your responsibility, these examples consist of a
+single function which takes the necessary variables as parameters.
+
+.SH FLUSHING
+
+Flushing means calling \fIxcb_flush\fP to clear the XCB-internal write buffer
+and send all pending requests to the X11 server. You don't explicitly need to
+flush before using a reply function (like \fIxcb_query_pointer_reply\fP), but
+you do need to flush before entering the event loop of your program.
+
+There are only two cases when XCB flushes by itself. The first case is when
+its write buffer becomes full, the second case is when you are asking for
+the reply of a request which wasn't flushed out yet (like
+\fIxcb_query_pointer_reply\fP). This last point also includes
+xcb_request_check(). Please note that waiting for an event does \fBNOT\fP
+flush.
+
+Examples generally include the \fIxcb_flush\fP call where appropriate (for
+example after setting a property). Therefore, including these functions and
+calling them in your application should just work. However, you might get
+better results when flushing outside of the function, depending on the
+architecture of your program.
+
+.SH COMPILATION
+
+If an example does not compile (without warnings) when using \fI-std=c99\fP,
+that is considered a documentation bug. Similarly, not handling errors or
+leaking memory is also considered a documentation bug. Please inform us about
+it on xcb at lists.freedesktop.org.
+
+.SH CODING STYLE
+
+Every example uses 4 spaces for indention.
+
+Comments are in asterisks, like /* this */.
+
+No line is longer than 80 characters (including indention).
+
+.SH SEE ALSO
+.BR xcb_connect (3),
+.BR xcb_get_property (3),
+.BR xcb_flush (3)
+.SH AUTHOR
+Michael Stapelberg <michael+xcb at stapelberg dot de>
diff --git a/src/static-man/xcb-requests.3 b/src/static-man/xcb-requests.3
new file mode 100644
index 0000000..278bcff
--- /dev/null
+++ b/src/static-man/xcb-requests.3
@@ -0,0 +1,165 @@
+.TH xcb-requests 3 2011-12-11 "XCB" "XCB examples"
+.ad l
+.SH NAME
+xcb-requests \- about request manpages
+.SH DESCRIPTION
+Every request in X11, like \fIMapWindow\fP, corresponds to a number of
+functions and data structures in XCB. For \fIMapWindow\fP, XCB provides the
+function \fIxcb_map_window\fP, which fills the \fIxcb_map_window_request_t\fP
+data structure and writes that to the X11 connection. Since the \fIMapWindow\fP
+request does not have a reply, this is the most simple case.
+
+.SH REPLIES
+
+Many requests have replies. For each reply, XCB provides at least a
+corresponding data structure and a function to return a pointer to a filled
+data structure. Let's take the \fIInternAtom\fP request as an example: XCB
+provides the \fIxcb_intern_atom_reply_t\fP data structure and
+\fIxcb_intern_atom_reply\fP function. For replies which are more complex (for
+example lists, such as in \fIxcb_list_fonts\fP), accessor functions are
+provided.
+
+.SH COOKIES
+
+XCB returns a cookie for each request you send. This is an XCB-specific data
+structure containing the sequence number with which the request was sent to the
+X11 server. To get any reply, you have to provide that cookie (so that XCB
+knows which of the waiting replies you want). Here is an example to illustrate
+the use of cookies:
+
+.nf
+.sp
+void my_example(xcb_connection *conn) {
+    xcb_intern_atom_cookie_t cookie;
+    xcb_intern_atom_reply_t *reply;
+
+    cookie = xcb_intern_atom(conn, 0, strlen("_NET_WM_NAME"), "_NET_WM_NAME");
+    /* ... do other work here if possible ... */
+    if ((reply = xcb_intern_atom_reply(conn, cookie, NULL))) {
+        printf("The _NET_WM_NAME atom has ID %u\n", reply->atom);
+    }
+    free(reply);
+}
+.fi
+
+.SH CHECKED VS. UNCHECKED
+
+The checked and unchecked suffixes for functions determine which kind of error
+handling is used for this specific request.
+
+For requests which have no reply (for example \fIxcb_map_window\fP), errors
+will be delivered to the event loop (you will receive an X11 event of type 0
+when calling \fIxcb_poll_for_event\fP).
+If you want to explicitly check for errors in a blocking fashion, call the
+_checked version of the function (for example \fIxcb_map_window_checked\fP) and
+use \fIxcb_request_check\fP.
+
+For requests which have a reply (for example \fIxcb_intern_atom\fP), errors
+will be checked when calling the reply function. To get errors in the event
+loop instead, use the _unchecked version of the function (for example
+\fIxcb_intern_atom_unchecked\fP).
+
+Here is an example which illustrates the four different ways of handling errors:
+
+.nf
+.sp
+/*
+ * Request without a reply, handling errors in the event loop (default)
+ *
+ */
+void my_example(xcb_connection *conn, xcb_window_t window) {
+    /* This is a request without a reply. Errors will be delivered to the event
+     * loop. Getting an error to xcb_map_window most likely is a bug in our
+     * program, so we don't need to check for that in a blocking way. */
+    xcb_map_window(conn, window);
+
+    /* ... of course your event loop would not be in the same function ... */
+    while ((event = xcb_wait_for_event(conn)) != NULL) {
+        if (event->response_type == 0) {
+            fprintf("Received X11 error %d\\n", error->error_code);
+            free(event);
+            continue;
+        }
+
+        /* ... handle a normal event ... */
+    }
+}
+
+/*
+ * Request without a reply, handling errors directly
+ *
+ */
+void my_example(xcb_connection *conn, xcb_window_t deco, xcb_window_t window) {
+    /* A reparenting window manager wants to know whether a new window was
+     * successfully reparented. If not (because the window got destroyed
+     * already, for example), it does not make sense to map an empty window
+     * decoration at all, so we need to know this right now. */
+    xcb_void_cookie_t cookie = xcb_reparent_window_checked(conn, window,
+                                                           deco, 0, 0);
+    xcb_generic_error_t *error;
+    if ((error = xcb_request_check(conn, cookie))) {
+        fprintf(stderr, "Could not reparent the window\\n");
+        free(error);
+        return;
+    }
+
+    /* ... do window manager stuff here ... */
+}
+
+/*
+ * Request with a reply, handling errors directly (default)
+ *
+ */
+void my_example(xcb_connection *conn, xcb_window_t window) {
+    xcb_intern_atom_cookie_t cookie;
+    xcb_intern_atom_reply_t *reply;
+    xcb_generic_error_t *error;
+
+    cookie = xcb_intern_atom(c, 0, strlen("_NET_WM_NAME"), "_NET_WM_NAME");
+    /* ... do other work here if possible ... */
+    if ((reply = xcb_intern_atom_reply(c, cookie, &error))) {
+        printf("The _NET_WM_NAME atom has ID %u\n", reply->atom);
+        free(reply);
+    } else {
+        fprintf(stderr, "X11 Error %d\\n", error->error_code);
+        free(error);
+    }
+}
+
+/*
+ * Request with a reply, handling errors in the event loop
+ *
+ */
+void my_example(xcb_connection *conn, xcb_window_t window) {
+    xcb_intern_atom_cookie_t cookie;
+    xcb_intern_atom_reply_t *reply;
+
+    cookie = xcb_intern_atom_unchecked(c, 0, strlen("_NET_WM_NAME"),
+                                       "_NET_WM_NAME");
+    /* ... do other work here if possible ... */
+    if ((reply = xcb_intern_atom_reply(c, cookie, NULL))) {
+        printf("The _NET_WM_NAME atom has ID %u\n", reply->atom);
+        free(reply);
+    }
+
+    /* ... of course your event loop would not be in the same function ... */
+    while ((event = xcb_wait_for_event(conn)) != NULL) {
+        if (event->response_type == 0) {
+            fprintf("Received X11 error %d\\n", error->error_code);
+            free(event);
+            continue;
+        }
+
+        /* ... handle a normal event ... */
+    }
+}
+.fi
+
+.SH SEE ALSO
+.BR xcb_map_window (3),
+.BR xcb_intern_atom (3),
+.BR xcb_list_fonts (3),
+.BR xcb_poll_for_event (3),
+.BR xcb_request_check (3)
+.SH AUTHOR
+Michael Stapelberg <michael+xcb at stapelberg dot de>


More information about the xcb-commit mailing list