diff --git a/generator/Data/XCB/Python/Parse.hs b/generator/Data/XCB/Python/Parse.hs
--- a/generator/Data/XCB/Python/Parse.hs
+++ b/generator/Data/XCB/Python/Parse.hs
@@ -48,8 +48,7 @@
   -- struct.unpack string, second is the size.
   BaseType String |
   -- | A composite type, i.e. a Struct or Union created by XCB. First arg is
-  -- the extension that defined it, second is the name of the type, third arg
-  -- is the size if it is known.
+  -- the extension that defined it, second is the name of the type.
   CompositeType String String
   deriving (Eq, Ord, Show)
 
@@ -336,25 +335,30 @@
   let name = accessor n
   in case m M.! typ of
        BaseType c -> Left (Just name, c)
-       -- XXX: be a little smarter here? we should really make sure that things
-       -- have a .pack(); if users are calling us via the old style api, we need
-       -- to support that as well. This isn't super necessary, though, because
-       -- currently (xcb-proto 1.10) there are no direct packs of raw structs, so
-       -- this is really only necessary if xpyb gets forward ported in the future if
-       -- there are actually calls of this type.
-       CompositeType _ _ -> Right $ [(name, mkCall (name ++ ".pack") noArgs)]
+       CompositeType _ typNam ->
+         let cond = mkCall "hasattr" [mkArg name, ArgExpr (mkStr "pack") ()]
+             trueB = mkCall (name ++ ".pack") noArgs
+             synthetic = mkCall (typNam ++ ".synthetic") [mkArg ("*" ++ name)]
+             falseB = mkCall (mkDot synthetic "pack") noArgs
+         in Right $ [(name, CondExpr trueB cond falseB ())]
 -- TODO: assert values are in enum?
-structElemToPyPack ext m accessor (X.List n typ _ _) =
+structElemToPyPack ext m accessor (X.List n typ expr _) =
   let name = accessor n
-  in case m M.! typ of
-        BaseType c -> Right $ [(name, mkCall "xcffib.pack_list" [ mkName $ name
-                                                                , mkStr c
-                                                                ])]
+      -- The convention seems to be either to have a <fieldref> nested in the
+      -- list, or use "%s_len" % name if there is no fieldref. We use a little
+      -- hack here and write an empty string, since we don't need to write this
+      -- length, but we have no way to indicate that right now.
+      list_len = if isNothing expr then [(name ++ "_len", mkStr "")] else []
+      list = case m M.! typ of
+        BaseType c -> [(name, mkCall "xcffib.pack_list" [ mkName $ name
+                                                        , mkStr c
+                                                        ])]
         CompositeType tExt c ->
           let c' = if tExt == ext then c else (tExt ++ "." ++ c)
-          in Right $ [(name, mkCall "xcffib.pack_list" ([ mkName $ name
-                                                        , mkName c'
-                                                        ]))]
+          in [(name, mkCall "xcffib.pack_list" ([ mkName $ name
+                                                , mkName c'
+                                                ]))]
+  in Right $ list_len ++ list
 structElemToPyPack _ m accessor (ExprField name typ expr) =
   let e = (xExpressionToPyExpr accessor) expr
       name' = accessor name
@@ -401,12 +405,12 @@
       -- implicitly.
       (listNames, lists) = unzip $ filter (flip notElem args . fst) (concat stmts)
       listNames' = case (ext, name) of
-                     -- XXX: QueryTextExtents has a field named "odd_length" with a
-                     -- fieldref of "string_len", so we fix it up here to match.
+                     -- XXX: QueryTextExtents has a field named "odd_length"
+                     -- which is unused, let's just drop it.
                      ("xproto", "QueryTextExtents") ->
-                       let replacer "odd_length" = "string_len"
-                           replacer s = s
-                       in map replacer listNames
+                       let notOdd "odd_length" = False
+                           notOdd _ = True
+                       in filter notOdd listNames
                      _ -> listNames
       packStr = addStructData prefix $ intercalate "" keys
       write = mkCall "buf.write" [mkCall "struct.pack"
@@ -535,6 +539,30 @@
                       ]
   in M.union m m'
 
+mkSyntheticMethod :: [GenStructElem Type] -> [Statement ()]
+mkSyntheticMethod membs = do
+  let names = catMaybes $ map getName membs
+      args = mkParams $ "cls" : names
+      self = mkAssign "self" $ mkCall (mkDot "cls" "__new__") [mkName "cls"]
+      body = map assign names
+      ret = mkReturn $ mkName "self"
+      synthetic = mkMethod "synthetic" args $ (self : body) ++ [ret]
+      classmethod = Decorator [ident "classmethod"] noArgs ()
+  if null names then [] else [Decorated [classmethod] synthetic ()]
+    where
+      getName :: GenStructElem Type -> Maybe String
+      getName (Pad _) = Nothing
+      getName (X.List n _ _ _) = Just n
+      getName (SField n _ _ _) = Just n
+      getName (ExprField n _ _) = Just n
+      getName (ValueParam _ n _ _) = Just n
+      getName (Switch n _ _) = Just n
+      getName (Doc _ _ _) = Nothing
+      getName (Fd n) = Just n
+
+      assign :: String -> Statement ()
+      assign n = mkAssign (mkDot "self" n) $ mkName n
+
 processXDecl :: String
              -> XDecl
              -> State TypeInfoMap BindingPart
@@ -553,20 +581,22 @@
   m <- get
   let (statements, len) = mkStructStyleUnpack "" ext m membs
       pack = mkPackMethod ext n m Nothing membs Nothing
+      synthetic = mkSyntheticMethod membs
       fixedLength = maybeToList $ do
         theLen <- len
         let rhs = mkInt theLen
         return $ mkAssign "fixed_size" rhs
   modify $ mkModify ext n (CompositeType ext n)
-  return $ Declaration [mkXClass n "xcffib.Struct" statements (pack : fixedLength)]
+  return $ Declaration [mkXClass n "xcffib.Struct" statements (pack : fixedLength ++ synthetic)]
 processXDecl ext (XEvent name opcode membs noSequence) = do
   m <- get
   let cname = name ++ "Event"
       prefix = if fromMaybe False noSequence then "x" else "x%c2x"
       pack = mkPackMethod ext name m (Just (prefix, opcode)) membs (Just 32)
+      synthetic = mkSyntheticMethod membs
       (statements, _) = mkStructStyleUnpack prefix ext m membs
       eventsUpd = mkDictUpdate "_events" opcode cname
-  return $ Declaration [ mkXClass cname "xcffib.Event" statements [pack]
+  return $ Declaration [ mkXClass cname "xcffib.Event" statements (pack : synthetic)
                        , eventsUpd
                        ]
 processXDecl ext (XError name opcode membs) = do
@@ -586,7 +616,7 @@
   let
       -- xtest doesn't seem to use the same packing strategy as everyone else,
       -- but there is no clear indication in the XML as to why that is. yay.
-      prefix = if ext == "xtest" then "xx2x" else "x%c2x"
+      prefix = if ext /= "xproto" then "xx2x" else "x%c2x"
       (args, packStmts) = mkPackStmts ext name m id prefix membs
       cookieName = (name ++ "Cookie")
       replyDecl = concat $ maybeToList $ do
@@ -605,12 +635,12 @@
       argChecked = ArgKeyword (ident "is_checked") (mkName "is_checked") ()
       checkedParam = Param (ident "is_checked") Nothing (Just isChecked) ()
       allArgs = (mkParams $ "self" : args) ++ [checkedParam]
-      mkArg = flip ArgExpr ()
-      ret = mkReturn $ mkCall "self.send_request" ((map mkArg [ mkInt opcode
-                                                              , mkName "buf"
-                                                              ])
-                                                              ++ hasReply
-                                                              ++ [argChecked])
+      mkArg' = flip ArgExpr ()
+      ret = mkReturn $ mkCall "self.send_request" ((map mkArg' [ mkInt opcode
+                                                               , mkName "buf"
+                                                               ])
+                                                               ++ hasReply
+                                                               ++ [argChecked])
       requestBody = buf ++ packStmts ++ [ret]
       request = mkMethod name allArgs requestBody
   return $ Request request replyDecl
diff --git a/generator/Data/XCB/Python/PyHelpers.hs b/generator/Data/XCB/Python/PyHelpers.hs
--- a/generator/Data/XCB/Python/PyHelpers.hs
+++ b/generator/Data/XCB/Python/PyHelpers.hs
@@ -21,6 +21,7 @@
   mkAssign,
   mkCall,
   noArgs,
+  mkArg,
   mkEnum,
   mkName,
   mkDot,
diff --git a/tests/GeneratorTests.hs b/tests/GeneratorTests.hs
--- a/tests/GeneratorTests.hs
+++ b/tests/GeneratorTests.hs
@@ -39,6 +39,7 @@
           , "type_pad"
           , "render_1.7"
           , "xproto_1.7"
+          , "render"
           ]
 
 mkFname :: String -> FilePath
diff --git a/tests/generator/event.py b/tests/generator/event.py
--- a/tests/generator/event.py
+++ b/tests/generator/event.py
@@ -22,5 +22,20 @@
         if buf_len < 32:
             buf.write(struct.pack("x" * (32 - buf_len)))
         return buf.getvalue()
+    @classmethod
+    def synthetic(cls, rotation, timestamp, config_timestamp, root, request_window, sizeID, subpixel_order, width, height, mwidth, mheight):
+        self = cls.__new__(cls)
+        self.rotation = rotation
+        self.timestamp = timestamp
+        self.config_timestamp = config_timestamp
+        self.root = root
+        self.request_window = request_window
+        self.sizeID = sizeID
+        self.subpixel_order = subpixel_order
+        self.width = width
+        self.height = height
+        self.mwidth = mwidth
+        self.mheight = mheight
+        return self
 _events[0] = ScreenChangeNotifyEvent
 xcffib._add_ext(key, eventExtension, _events, _errors)
diff --git a/tests/generator/no_sequence.py b/tests/generator/no_sequence.py
--- a/tests/generator/no_sequence.py
+++ b/tests/generator/no_sequence.py
@@ -20,5 +20,10 @@
         if buf_len < 32:
             buf.write(struct.pack("x" * (32 - buf_len)))
         return buf.getvalue()
+    @classmethod
+    def synthetic(cls, keys):
+        self = cls.__new__(cls)
+        self.keys = keys
+        return self
 _events[11] = KeymapNotifyEvent
 xcffib._add_ext(key, no_sequenceExtension, _events, _errors)
diff --git a/tests/generator/render.py b/tests/generator/render.py
new file mode 100644
--- /dev/null
+++ b/tests/generator/render.py
@@ -0,0 +1,59 @@
+import xcffib
+import struct
+import six
+MAJOR_VERSION = 0
+MINOR_VERSION = 11
+key = xcffib.ExtensionKey("RENDER")
+_events = {}
+_errors = {}
+class COLOR(xcffib.Struct):
+    def __init__(self, unpacker):
+        if isinstance(unpacker, xcffib.Protobj):
+            unpacker = xcffib.MemoryUnpacker(unpacker.pack())
+        xcffib.Struct.__init__(self, unpacker)
+        base = unpacker.offset
+        self.red, self.green, self.blue, self.alpha = unpacker.unpack("HHHH")
+        self.bufsize = unpacker.offset - base
+    def pack(self):
+        buf = six.BytesIO()
+        buf.write(struct.pack("=HHHH", self.red, self.green, self.blue, self.alpha))
+        return buf.getvalue()
+    fixed_size = 8
+    @classmethod
+    def synthetic(cls, red, green, blue, alpha):
+        self = cls.__new__(cls)
+        self.red = red
+        self.green = green
+        self.blue = blue
+        self.alpha = alpha
+        return self
+class RECTANGLE(xcffib.Struct):
+    def __init__(self, unpacker):
+        if isinstance(unpacker, xcffib.Protobj):
+            unpacker = xcffib.MemoryUnpacker(unpacker.pack())
+        xcffib.Struct.__init__(self, unpacker)
+        base = unpacker.offset
+        self.x, self.y, self.width, self.height = unpacker.unpack("hhHH")
+        self.bufsize = unpacker.offset - base
+    def pack(self):
+        buf = six.BytesIO()
+        buf.write(struct.pack("=hhHH", self.x, self.y, self.width, self.height))
+        return buf.getvalue()
+    fixed_size = 8
+    @classmethod
+    def synthetic(cls, x, y, width, height):
+        self = cls.__new__(cls)
+        self.x = x
+        self.y = y
+        self.width = width
+        self.height = height
+        return self
+class renderExtension(xcffib.Extension):
+    def FillRectangles(self, op, dst, color, rects_len, rects, is_checked=False):
+        buf = six.BytesIO()
+        buf.write(struct.pack("=xx2xB3xI", op, dst))
+        buf.write(color.pack() if hasattr(color, "pack") else COLOR.synthetic(*color).pack())
+        buf.write("")
+        buf.write(xcffib.pack_list(rects, RECTANGLE))
+        return self.send_request(26, buf, is_checked=is_checked)
+xcffib._add_ext(key, renderExtension, _events, _errors)
diff --git a/tests/generator/render.xml b/tests/generator/render.xml
new file mode 100644
--- /dev/null
+++ b/tests/generator/render.xml
@@ -0,0 +1,27 @@
+<xcb header="render" extension-xname="RENDER" extension-name="Render"
+    major-version="0" minor-version="11">
+
+  <struct name="COLOR">
+    <field type="CARD16" name="red" />
+    <field type="CARD16" name="green" />
+    <field type="CARD16" name="blue" />
+    <field type="CARD16" name="alpha" />
+  </struct>
+
+  <xidtype name="PICTURE" />
+
+  <struct name="RECTANGLE">
+    <field type="INT16" name="x" />
+    <field type="INT16" name="y" />
+    <field type="CARD16" name="width" />
+    <field type="CARD16" name="height" />
+  </struct>
+
+  <request name="FillRectangles" opcode="26">
+    <field type="CARD8" name="op" enum="PictOp" />
+    <pad bytes="3" />
+    <field type="PICTURE" name="dst" />
+    <field type="COLOR" name="color" />
+    <list type="RECTANGLE" name="rects" />
+  </request>
+</xcb>
diff --git a/tests/generator/request.py b/tests/generator/request.py
--- a/tests/generator/request.py
+++ b/tests/generator/request.py
@@ -6,7 +6,7 @@
 class requestExtension(xcffib.Extension):
     def CreateWindow(self, depth, wid, parent, x, y, width, height, border_width, _class, visual, value_mask, value_list, is_checked=False):
         buf = six.BytesIO()
-        buf.write(struct.pack("=xB2xIIhhHHHHI", depth, wid, parent, x, y, width, height, border_width, _class, visual))
+        buf.write(struct.pack("=xx2xBIIhhHHHHI", depth, wid, parent, x, y, width, height, border_width, _class, visual))
         buf.write(struct.pack("=I", value_mask))
         buf.write(xcffib.pack_list(value_list, "I"))
         return self.send_request(1, buf, is_checked=is_checked)
diff --git a/tests/generator/request_reply.py b/tests/generator/request_reply.py
--- a/tests/generator/request_reply.py
+++ b/tests/generator/request_reply.py
@@ -17,6 +17,12 @@
         buf.write(struct.pack("=B", self.name_len))
         buf.write(xcffib.pack_list(self.name, "c"))
         return buf.getvalue()
+    @classmethod
+    def synthetic(cls, name_len, name):
+        self = cls.__new__(cls)
+        self.name_len = name_len
+        self.name = name
+        return self
 class ListExtensionsReply(xcffib.Reply):
     def __init__(self, unpacker):
         if isinstance(unpacker, xcffib.Protobj):
diff --git a/tests/generator/struct.py b/tests/generator/struct.py
--- a/tests/generator/struct.py
+++ b/tests/generator/struct.py
@@ -16,6 +16,13 @@
         buf.write(struct.pack("=Iii", self.resolution, self.minimum, self.maximum))
         return buf.getvalue()
     fixed_size = 12
+    @classmethod
+    def synthetic(cls, resolution, minimum, maximum):
+        self = cls.__new__(cls)
+        self.resolution = resolution
+        self.minimum = minimum
+        self.maximum = maximum
+        return self
 class ValuatorInfo(xcffib.Struct):
     def __init__(self, unpacker):
         if isinstance(unpacker, xcffib.Protobj):
@@ -30,4 +37,14 @@
         buf.write(struct.pack("=BBBBI", self.class_id, self.len, self.axes_len, self.mode, self.motion_size))
         buf.write(xcffib.pack_list(self.axes, AxisInfo))
         return buf.getvalue()
+    @classmethod
+    def synthetic(cls, class_id, len, axes_len, mode, motion_size, axes):
+        self = cls.__new__(cls)
+        self.class_id = class_id
+        self.len = len
+        self.axes_len = axes_len
+        self.mode = mode
+        self.motion_size = motion_size
+        self.axes = axes
+        return self
 xcffib._add_ext(key, structExtension, _events, _errors)
diff --git a/tests/generator/type_pad.py b/tests/generator/type_pad.py
--- a/tests/generator/type_pad.py
+++ b/tests/generator/type_pad.py
@@ -16,6 +16,16 @@
         buf.write(struct.pack("=hhhhhH", self.left_side_bearing, self.right_side_bearing, self.character_width, self.ascent, self.descent, self.attributes))
         return buf.getvalue()
     fixed_size = 12
+    @classmethod
+    def synthetic(cls, left_side_bearing, right_side_bearing, character_width, ascent, descent, attributes):
+        self = cls.__new__(cls)
+        self.left_side_bearing = left_side_bearing
+        self.right_side_bearing = right_side_bearing
+        self.character_width = character_width
+        self.ascent = ascent
+        self.descent = descent
+        self.attributes = attributes
+        return self
 class FONTPROP(xcffib.Struct):
     def __init__(self, unpacker):
         if isinstance(unpacker, xcffib.Protobj):
@@ -29,6 +39,12 @@
         buf.write(struct.pack("=II", self.name, self.value))
         return buf.getvalue()
     fixed_size = 8
+    @classmethod
+    def synthetic(cls, name, value):
+        self = cls.__new__(cls)
+        self.name = name
+        self.value = value
+        return self
 class ListFontsWithInfoReply(xcffib.Reply):
     def __init__(self, unpacker):
         if isinstance(unpacker, xcffib.Protobj):
@@ -51,7 +67,7 @@
 class type_padExtension(xcffib.Extension):
     def ListFontsWithInfo(self, max_names, pattern_len, pattern, is_checked=True):
         buf = six.BytesIO()
-        buf.write(struct.pack("=xx2xHH", max_names, pattern_len))
+        buf.write(struct.pack("=xx2xxHH", max_names, pattern_len))
         buf.write(xcffib.pack_list(pattern, "c"))
         return self.send_request(50, buf, ListFontsWithInfoCookie, is_checked=is_checked)
 xcffib._add_ext(key, type_padExtension, _events, _errors)
diff --git a/xcffib.cabal b/xcffib.cabal
--- a/xcffib.cabal
+++ b/xcffib.cabal
@@ -1,5 +1,5 @@
 name:                xcffib
-version:             0.3.6
+version:             0.4.0
 synopsis:            A cffi-based python binding for X
 homepage:            http://github.com/tych0/xcffib
 license:             OtherLicense
