Document how to correctly wrap screen procedures
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@keithp.com> Reviewed-by: Eric Anholt <eric@anholt.net>
This commit is contained in:
parent
5eb77697ea
commit
c75fee79ac
|
@ -358,6 +358,96 @@ typedef WindowPtr (*XYToWindowProcPtr)(ScreenPtr pScreen,
|
||||||
|
|
||||||
typedef int (*NameWindowPixmapProcPtr)(WindowPtr, PixmapPtr, CARD32);
|
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 {
|
typedef struct _Screen {
|
||||||
int myNum; /* index of this instance in Screens[] */
|
int myNum; /* index of this instance in Screens[] */
|
||||||
ATOM id;
|
ATOM id;
|
||||||
|
|
Loading…
Reference in New Issue