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