[PATCH 1/5] Document how to correctly wrap screen procedures
Keith Packard
keithp at keithp.com
Fri Apr 18 14:31:16 PDT 2014
This adds a large comment to include/scrnintstr.h which should serve
to document the correct way to wrap any screen procedure, with a
particular focus on how to dynamically add/remove wrapping layers
while the server is running.
Signed-off-by: Keith Packard <keithp at keithp.com>
---
include/scrnintstr.h | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 90 insertions(+)
diff --git a/include/scrnintstr.h b/include/scrnintstr.h
index 6acdadd..cc6e596 100644
--- a/include/scrnintstr.h
+++ b/include/scrnintstr.h
@@ -358,6 +358,96 @@ typedef WindowPtr (*XYToWindowProcPtr)(ScreenPtr pScreen,
typedef int (*NameWindowPixmapProcPtr)(WindowPtr, PixmapPtr, CARD32);
+/* Wrapping Screen procedures
+
+ There are a few modules in the X server which dynamically add and
+ remove themselves from various screen procedure call chains.
+
+ For example, the BlockHandler is dynamically modified by:
+
+ * xf86Rotate
+ * miSprite
+ * composite
+ * render (for animated cursors)
+
+ Correctly manipulating this chain is complicated by the fact that
+ the chain is constructed through a sequence of screen private
+ structures, each holding the next screen->proc pointer.
+
+ To add a module to a screen->proc chain is fairly simple; just save
+ the current screen->proc value in the module screen private
+ and store the module's function in the screen->proc location.
+
+ Removing a screen proc is a bit trickier. It seems like all you
+ need to do is set the screen->proc pointer back to the value saved
+ in your screen private. However, if some other module has come
+ along and wrapped on top of you, then the right place to store the
+ previous screen->proc value is actually in the wrapping module's
+ screen private structure(!). Of course, you have no idea what
+ other module may have wrapped on top, nor could you poke inside
+ its screen private in any case.
+
+ To make this work, we restrict the unwrapping process to happen
+ during the invocation of the screen proc itself, and then we
+ require the screen proc to take some care when manipulating the
+ screen proc functions pointers.
+
+ The requirements are:
+
+ 1) The screen proc must set the screen->proc pointer back to the
+ value saved in its screen private before calling outside its
+ module.
+
+ 2a) If the screen proc wants to be remove itself from the chain,
+ it must not manipulate screen->proc pointer again before
+ returning.
+
+ 2b) If the screen proc wants to remain in the chain, it must:
+
+ 2b.1) Re-fetch the screen->proc pointer and store that in
+ its screen private. This ensures that any changes
+ to the chain will be preserved.
+
+ 2b.2) Set screen->proc back to itself
+
+ One key requirement here is that these steps must wrap not just
+ any invocation of the nested screen->proc value, but must nest
+ essentially any calls outside the current module. This ensures
+ that other modules can reliably manipulate screen->proc wrapping
+ using these same rules.
+
+ For example, the animated cursor code in render has two macros,
+ Wrap and Unwrap.
+
+ #define Unwrap(as,s,elt) ((s)->elt = (as)->elt)
+
+ Unwrap takes the screen private (as), the screen (s) and the
+ member name (elt), and restores screen->proc to that saved in the
+ screen private.
+
+ #define Wrap(as,s,elt,func) (((as)->elt = (s)->elt), (s)->elt = func)
+
+ Wrap takes the screen private (as), the screen (s), the member
+ name (elt) and the wrapping function (func). It saves the
+ current screen->proc value in the screen private, and then sets the
+ screen->proc to the local wrapping function.
+
+ Within each of these functions, there's a pretty simple pattern:
+
+ Unwrap(as, pScreen, UnrealizeCursor);
+
+ // Do local stuff, including possibly calling down through
+ // pScreen->UnrealizeCursor
+
+ Wrap(as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor);
+
+ The wrapping block handler is a bit different; it does the Unwrap,
+ the local operations and then only re-Wraps if the hook is still
+ required. Unwrap occurrs at the top of each function, just after
+ entry, and Wrap occurrs at the bottom of each function, just
+ before returning.
+ */
+
typedef struct _Screen {
int myNum; /* index of this instance in Screens[] */
ATOM id;
--
1.9.2
More information about the xorg-devel
mailing list