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
@@ -583,7 +583,11 @@
                        ]
 processXDecl ext (XRequest name opcode membs reply) = do
   m <- get
-  let (args, packStmts) = mkPackStmts ext name m id "x%c2x" membs
+  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"
+      (args, packStmts) = mkPackStmts ext name m id prefix membs
       cookieName = (name ++ "Cookie")
       replyDecl = concat $ maybeToList $ do
         reply' <- reply
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
@@ -138,10 +138,23 @@
 mkXClass clazz superclazz constructor methods =
   let args = [ "self", "unpacker" ]
       super = mkCall (superclazz ++ ".__init__") $ map mkName args
-      body = [(StmtExpr super ())] ++ constructor
+      body = eventToUnpacker : (StmtExpr super ()) : constructor
       initParams = mkParams args
       initMethod = Fun (ident "__init__") initParams Nothing body ()
   in mkClass clazz superclazz $ initMethod : methods
+
+    where
+
+      -- In some cases (e.g. when creating ClientMessageEvents), our events are
+      -- passed directly to __init__. Since we don't keep track of the
+      -- underlying buffers after the event is created, we have to re-pack
+      -- things so they can be unpacked again.
+      eventToUnpacker :: Statement ()
+      eventToUnpacker = let newUnpacker = mkAssign "unpacker" (mkCall "xcffib.MemoryUnpacker"
+                                                              [mkCall "unpacker.pack" noArgs])
+                            cond = mkCall "isinstance" [mkName "unpacker", mkName "xcffib.Protobj"]
+                        in mkIf cond [newUnpacker]
+
 
 mkEmptyClass :: String -> String -> Statement ()
 mkEmptyClass clazz superclazz = mkClass clazz superclazz [Pass ()]
diff --git a/tests/generator/error.py b/tests/generator/error.py
--- a/tests/generator/error.py
+++ b/tests/generator/error.py
@@ -8,6 +8,8 @@
 _errors = {}
 class RequestError(xcffib.Error):
     def __init__(self, unpacker):
+        if isinstance(unpacker, xcffib.Protobj):
+            unpacker = xcffib.MemoryUnpacker(unpacker.pack())
         xcffib.Error.__init__(self, unpacker)
         base = unpacker.offset
         self.bad_value, self.minor_opcode, self.major_opcode = unpacker.unpack("xx2xIHBx")
diff --git a/tests/generator/event.py b/tests/generator/event.py
--- a/tests/generator/event.py
+++ b/tests/generator/event.py
@@ -8,6 +8,8 @@
 _errors = {}
 class ScreenChangeNotifyEvent(xcffib.Event):
     def __init__(self, unpacker):
+        if isinstance(unpacker, xcffib.Protobj):
+            unpacker = xcffib.MemoryUnpacker(unpacker.pack())
         xcffib.Event.__init__(self, unpacker)
         base = unpacker.offset
         self.rotation, self.timestamp, self.config_timestamp, self.root, self.request_window, self.sizeID, self.subpixel_order, self.width, self.height, self.mwidth, self.mheight = unpacker.unpack("xB2xIIIIHHHHHH")
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
@@ -5,6 +5,8 @@
 _errors = {}
 class KeymapNotifyEvent(xcffib.Event):
     def __init__(self, unpacker):
+        if isinstance(unpacker, xcffib.Protobj):
+            unpacker = xcffib.MemoryUnpacker(unpacker.pack())
         xcffib.Event.__init__(self, unpacker)
         base = unpacker.offset
         unpacker.unpack("x")
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
@@ -5,6 +5,8 @@
 _errors = {}
 class STR(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.name_len, = unpacker.unpack("B")
@@ -17,6 +19,8 @@
         return buf.getvalue()
 class ListExtensionsReply(xcffib.Reply):
     def __init__(self, unpacker):
+        if isinstance(unpacker, xcffib.Protobj):
+            unpacker = xcffib.MemoryUnpacker(unpacker.pack())
         xcffib.Reply.__init__(self, unpacker)
         base = unpacker.offset
         self.names_len, = unpacker.unpack("xB2x4x24x")
diff --git a/tests/generator/struct.py b/tests/generator/struct.py
--- a/tests/generator/struct.py
+++ b/tests/generator/struct.py
@@ -5,6 +5,8 @@
 _errors = {}
 class AxisInfo(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.resolution, self.minimum, self.maximum = unpacker.unpack("Iii")
@@ -16,6 +18,8 @@
     fixed_size = 12
 class ValuatorInfo(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.class_id, self.len, self.axes_len, self.mode, self.motion_size = unpacker.unpack("BBBBI")
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
@@ -5,6 +5,8 @@
 _errors = {}
 class CHARINFO(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.left_side_bearing, self.right_side_bearing, self.character_width, self.ascent, self.descent, self.attributes = unpacker.unpack("hhhhhH")
@@ -16,6 +18,8 @@
     fixed_size = 12
 class FONTPROP(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.name, self.value = unpacker.unpack("II")
@@ -27,6 +31,8 @@
     fixed_size = 8
 class ListFontsWithInfoReply(xcffib.Reply):
     def __init__(self, unpacker):
+        if isinstance(unpacker, xcffib.Protobj):
+            unpacker = xcffib.MemoryUnpacker(unpacker.pack())
         xcffib.Reply.__init__(self, unpacker)
         base = unpacker.offset
         self.name_len, = unpacker.unpack("xB2x4x")
diff --git a/tests/generator/union.py b/tests/generator/union.py
--- a/tests/generator/union.py
+++ b/tests/generator/union.py
@@ -5,6 +5,8 @@
 _errors = {}
 class ClientMessageData(xcffib.Union):
     def __init__(self, unpacker):
+        if isinstance(unpacker, xcffib.Protobj):
+            unpacker = xcffib.MemoryUnpacker(unpacker.pack())
         xcffib.Union.__init__(self, unpacker)
         self.data8 = xcffib.List(unpacker.copy(), "B", 20)
         self.data16 = xcffib.List(unpacker.copy(), "H", 10)
diff --git a/xcffib.cabal b/xcffib.cabal
--- a/xcffib.cabal
+++ b/xcffib.cabal
@@ -1,5 +1,5 @@
 name:                xcffib
-version:             0.2.2
+version:             0.2.4
 synopsis:            A cffi-based python binding for X
 homepage:            http://github.com/tych0/xcffib
 license:             OtherLicense
