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);
|
||||
|
||||
/* 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;
|
||||
|
|
Loading…
Reference in New Issue
Block a user