| 1 | Generic Rootless Layer |
| 2 | Version 1.0 |
| 3 | July 13, 2004 |
| 4 | |
| 5 | Torrey T. Lyons |
| 6 | torrey@xfree86.org |
| 7 | |
| 8 | |
| 9 | Introduction |
| 10 | |
| 11 | The generic rootless layer allows an X server to be implemented |
| 12 | on top of another window server in a cooperative manner. This allows the |
| 13 | X11 windows and native windows of the underlying window server to |
| 14 | coexist on the same screen. The layer is called "rootless" because the root |
| 15 | window of the X server is generally not drawn. Instead, each top-level |
| 16 | child of the root window is represented as a separate on-screen window by |
| 17 | the underlying window server. The layer is referred to as "generic" |
| 18 | because it abstracts away the details of the underlying window system and |
| 19 | contains code that is useful for any rootless X server. The code for the |
| 20 | generic rootless layer is located in xc/programs/Xserver/miext/rootless. To |
| 21 | build a complete rootless X server requires a specific rootless |
| 22 | implementation, which provides functions that allow the generic rootless |
| 23 | layer to interact with the underlying window system. |
| 24 | |
| 25 | |
| 26 | Concepts |
| 27 | |
| 28 | In the context of a rootless X server the term window is used to |
| 29 | mean many fundamentally different things. For X11 a window is a DDX |
| 30 | resource that describes a visible, or potentially visible, rectangle on the |
| 31 | screen. A top-level window is a direct child of the root window. To avoid |
| 32 | confusion, an on-screen native window of the underlying window system |
| 33 | is referred to as a "frame". The generic rootless layer associates each |
| 34 | mapped top-level X11 window with a frame. An X11 window may be said |
| 35 | to be "framed" if it or its top-level parent is represented by a frame. |
| 36 | |
| 37 | The generic rootless layer models each frame as being backed at |
| 38 | all times by a backing buffer, which is periodically flushed to the screen. |
| 39 | If the underlying window system does not provide a backing buffer for |
| 40 | frames, this must be done by the rootless implementation. The generic |
| 41 | rootless layer model does not assume it always has access to the frames' |
| 42 | backing buffers. Any drawing to the buffer will be proceeded by a call to |
| 43 | the rootless implementation's StartDrawing() function and StopDrawing() |
| 44 | will be called when the drawing is concluded. The address of the frame's |
| 45 | backing buffer is returned by the StartDrawing() function and it can |
| 46 | change between successive calls. |
| 47 | |
| 48 | Because each frame is assumed to have a backing buffer, the |
| 49 | generic rootless layer will stop Expose events being generated when the |
| 50 | regions of visibility of a frame change on screen. This is similar to backing |
| 51 | store, but backing buffers are different in that they always store a copy of |
| 52 | the entire window contents, not just the obscured portions. The price paid |
| 53 | in increased memory consumption is made up by the greatly decreased |
| 54 | complexity in not having to track and record regions as they are obscured. |
| 55 | |
| 56 | |
| 57 | Rootless Implementation |
| 58 | |
| 59 | The specifics of the underlying window system are provided to the |
| 60 | generic rootless layer through rootless implementation functions, compile- |
| 61 | time options, and runtime parameters. The rootless implementation |
| 62 | functions are a list of functions that allow the generic rootless layer to |
| 63 | perform operations such as creating, destroying, moving, and resizing |
| 64 | frames. Some of the implementation functions are optional. A detailed |
| 65 | description of the rootless implementation functions is provided in |
| 66 | Appendix A. |
| 67 | |
| 68 | By design, a rootless implementation should only have to include |
| 69 | the rootless.h header file. The rootlessCommon.h file contains definitions |
| 70 | internal to the generic rootless layer. (If you find you need to use |
| 71 | rootlessCommon.h in your implementation, let the generic rootless layer |
| 72 | maintainers know. This could be an area where the generic rootless layer |
| 73 | should be generalized.) A rootless implementation should also modify |
| 74 | rootlessConfig.h to specify compile time options for its platform. |
| 75 | |
| 76 | The following compile-time options are defined in |
| 77 | rootlessConfig.h: |
| 78 | |
| 79 | o ROOTLESS_PROTECT_ALPHA: By default for a color bit depth of 24 and |
| 80 | 32 bits per pixel, fb will overwrite the "unused" 8 bits to optimize |
| 81 | drawing speed. If this is true, the alpha channel of frames is |
| 82 | protected and is not modified when drawing to them. The bits |
| 83 | containing the alpha channel are defined by the macro |
| 84 | RootlessAlphaMask(bpp), which should return a bit mask for |
| 85 | various bits per pixel. |
| 86 | |
| 87 | o ROOTLESS_REDISPLAY_DELAY: Time in milliseconds between updates to |
| 88 | the underlying window server. Most operations will be buffered until |
| 89 | this time has expired. |
| 90 | |
| 91 | o ROOTLESS_RESIZE_GRAVITY: If the underlying window system supports it, |
| 92 | some frame resizes can be optimized by relying on the frame contents |
| 93 | maintaining a particular gravity during the resize. In this way less |
| 94 | of the frame contents need to be preserved by the generic rootless |
| 95 | layer. If true, the generic rootless layer will pass gravity hints |
| 96 | during resizing and rely on the frame contents being preserved |
| 97 | accordingly. |
| 98 | |
| 99 | The following runtime options are defined in rootless.h: |
| 100 | |
| 101 | o rootlessGlobalOffsetX, rootlessGlobalOffsetY: These specify the global |
| 102 | offset that is applied to all screens when converting from |
| 103 | screen-local to global coordinates. |
| 104 | |
| 105 | o rootless_CopyBytes_threshold, rootless_CopyWindow_threshold: |
| 106 | The minimum number of bytes or pixels for which to use the rootless |
| 107 | implementation's respective acceleration function. The rootless |
| 108 | acceleration functions are all optional so these will only be used |
| 109 | if the respective acceleration function pointer is not NULL. |
| 110 | |
| 111 | |
| 112 | Accelerated Drawing |
| 113 | |
| 114 | The rootless implementation typically does not have direct access |
| 115 | to the hardware. Its access to the graphics hardware is generally through |
| 116 | the API of the underlying window system. This underlying API may not |
| 117 | overlap well with the X11 drawing primitives. The generic rootless layer |
| 118 | falls back to using fb for all its 2-D drawing. Providing optional rootless |
| 119 | implementation acceleration functions can accelerate some graphics |
| 120 | primitives and some window functions. Typically calling through to the |
| 121 | underlying window systems API will not speed up these operations for |
| 122 | small enough areas. The rootless_*_threshold runtime options allow the |
| 123 | rootless implementation to provide hints for when the acceleration |
| 124 | functions should be used instead of fb. |
| 125 | |
| 126 | |
| 127 | Alpha Channel Protection |
| 128 | |
| 129 | If the bits per pixel is greater then the color bit depth, the contents |
| 130 | of the extra bits are undefined by the X11 protocol. Some window systems |
| 131 | will use these extra bits as an alpha channel. The generic rootless layer can |
| 132 | be configured to protect these bits and make sure they are not modified by |
| 133 | other parts of the X server. To protect the alpha channel |
| 134 | ROOTLESS_PROTECT_ALPHA and RootlessAlphaMask(bpp) must be |
| 135 | set appropriately as described under the compile time options. This |
| 136 | ensures that the X11 graphics primitives do not overwrite the alpha |
| 137 | channel in an attempt to optimize drawing. In addition, the window |
| 138 | functions PaintWindow() and Composite() must be replaced by alpha |
| 139 | channel safe variants. These are provided in rootless/safeAlpha. |
| 140 | |
| 141 | |
| 142 | Credits |
| 143 | |
| 144 | The generic rootless layer was originally conceived and developed |
| 145 | by Greg Parker as part of the XDarwin X server on Mac OS X. John |
| 146 | Harper made later optimizations to this code but removed its generic |
| 147 | independence of the underlying window system. Torrey T. Lyons |
| 148 | reintroduced the generic abstractions and made the rootless code suitable |
| 149 | for use by other X servers. |
| 150 | |
| 151 | |
| 152 | Appendix A: Rootless Implementation Functions |
| 153 | |
| 154 | The rootless implementation functions are defined in rootless.h. It |
| 155 | is intended that rootless.h contains the complete interface that is needed by |
| 156 | rootless implementations. The definitions contained in rootlessCommon.h |
| 157 | are intended for internal use by the generic rootless layer and are more |
| 158 | likely to change. |
| 159 | |
| 160 | Most of these functions take a RootlessFrameID as a parameter. |
| 161 | The RootlessFrameID is an opaque object that is returned by the |
| 162 | implementation's CreateFrame() function. The generic rootless layer does |
| 163 | not use this frame id other than to pass it back to the rootless |
| 164 | implementation to indicate the frame to operate on. |
| 165 | |
| 166 | /* |
| 167 | * Create a new frame. |
| 168 | * The frame is created unmapped. |
| 169 | * |
| 170 | * pFrame RootlessWindowPtr for this frame should be completely |
| 171 | * initialized before calling except for pFrame->wid, which |
| 172 | * is set by this function. |
| 173 | * pScreen Screen on which to place the new frame |
| 174 | * newX, newY Position of the frame. |
| 175 | * pNewShape Shape for the frame (in frame-local coordinates). NULL for |
| 176 | * unshaped frames. |
| 177 | */ |
| 178 | typedef Bool (*RootlessCreateFrameProc) |
| 179 | (RootlessWindowPtr pFrame, ScreenPtr pScreen, int newX, int newY, |
| 180 | RegionPtr pNewShape); |
| 181 | |
| 182 | /* |
| 183 | * Destroy a frame. |
| 184 | * Drawing is stopped and all updates are flushed before this is called. |
| 185 | * |
| 186 | * wid Frame id |
| 187 | */ |
| 188 | typedef void (*RootlessDestroyFrameProc) |
| 189 | (RootlessFrameID wid); |
| 190 | |
| 191 | /* |
| 192 | * Move a frame on screen. |
| 193 | * Drawing is stopped and all updates are flushed before this is called. |
| 194 | * |
| 195 | * wid Frame id |
| 196 | * pScreen Screen to move the new frame to |
| 197 | * newX, newY New position of the frame |
| 198 | */ |
| 199 | typedef void (*RootlessMoveFrameProc) |
| 200 | (RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY); |
| 201 | |
| 202 | /* |
| 203 | * Resize and move a frame. |
| 204 | * Drawing is stopped and all updates are flushed before this is called. |
| 205 | * |
| 206 | * wid Frame id |
| 207 | * pScreen Screen to move the new frame to |
| 208 | * newX, newY New position of the frame |
| 209 | * newW, newH New size of the frame |
| 210 | * gravity Gravity for window contents (rl_gravity_enum). This is always |
| 211 | * RL_GRAVITY_NONE unless ROOTLESS_RESIZE_GRAVITY is set. |
| 212 | */ |
| 213 | typedef void (*RootlessResizeFrameProc) |
| 214 | (RootlessFrameID wid, ScreenPtr pScreen, |
| 215 | int newX, int newY, unsigned int newW, unsigned int newH, |
| 216 | unsigned int gravity); |
| 217 | |
| 218 | /* |
| 219 | * Change frame ordering (AKA stacking, layering). |
| 220 | * Drawing is stopped before this is called. Unmapped frames are mapped by |
| 221 | * setting their ordering. |
| 222 | * |
| 223 | * wid Frame id |
| 224 | * nextWid Frame id of frame that is now above this one or NULL if this |
| 225 | * frame is at the top. |
| 226 | */ |
| 227 | typedef void (*RootlessRestackFrameProc) |
| 228 | (RootlessFrameID wid, RootlessFrameID nextWid); |
| 229 | |
| 230 | /* |
| 231 | * Change frame's shape. |
| 232 | * Drawing is stopped before this is called. |
| 233 | * |
| 234 | * wid Frame id |
| 235 | * pNewShape New shape for the frame (in frame-local coordinates) |
| 236 | * or NULL if now unshaped. |
| 237 | */ |
| 238 | typedef void (*RootlessReshapeFrameProc) |
| 239 | (RootlessFrameID wid, RegionPtr pNewShape); |
| 240 | |
| 241 | /* |
| 242 | * Unmap a frame. |
| 243 | * |
| 244 | * wid Frame id |
| 245 | */ |
| 246 | typedef void (*RootlessUnmapFrameProc) |
| 247 | (RootlessFrameID wid); |
| 248 | |
| 249 | /* |
| 250 | * Start drawing to a frame. |
| 251 | * Prepare a frame for direct access to its backing buffer. |
| 252 | * |
| 253 | * wid Frame id |
| 254 | * pixelData Address of the backing buffer (returned) |
| 255 | * bytesPerRow Width in bytes of the backing buffer (returned) |
| 256 | */ |
| 257 | typedef void (*RootlessStartDrawingProc) |
| 258 | (RootlessFrameID wid, char **pixelData, int *bytesPerRow); |
| 259 | |
| 260 | /* |
| 261 | * Stop drawing to a frame. |
| 262 | * No drawing to the frame's backing buffer will occur until drawing |
| 263 | * is started again. |
| 264 | * |
| 265 | * wid Frame id |
| 266 | * flush Flush drawing updates for this frame to the screen. |
| 267 | */ |
| 268 | typedef void (*RootlessStopDrawingProc) |
| 269 | (RootlessFrameID wid, Bool flush); |
| 270 | |
| 271 | /* |
| 272 | * Flush drawing updates to the screen. |
| 273 | * Drawing is stopped before this is called. |
| 274 | * |
| 275 | * wid Frame id |
| 276 | * pDamage Region containing all the changed pixels in frame-local |
| 277 | * coordinates. This is clipped to the window's clip. |
| 278 | */ |
| 279 | typedef void (*RootlessUpdateRegionProc) |
| 280 | (RootlessFrameID wid, RegionPtr pDamage); |
| 281 | |
| 282 | /* |
| 283 | * Mark damaged rectangles as requiring redisplay to screen. |
| 284 | * |
| 285 | * wid Frame id |
| 286 | * nrects Number of damaged rectangles |
| 287 | * rects Array of damaged rectangles in frame-local coordinates |
| 288 | * shift_x, Vector to shift rectangles by |
| 289 | * shift_y |
| 290 | */ |
| 291 | typedef void (*RootlessDamageRectsProc) |
| 292 | (RootlessFrameID wid, int nrects, const BoxRec *rects, |
| 293 | int shift_x, int shift_y); |
| 294 | |
| 295 | /* |
| 296 | * Switch the window associated with a frame. (Optional) |
| 297 | * When a framed window is reparented, the frame is resized and set to |
| 298 | * use the new top-level parent. If defined this function will be called |
| 299 | * afterwards for implementation specific bookkeeping. |
| 300 | * |
| 301 | * pFrame Frame whose window has switched |
| 302 | * oldWin Previous window wrapped by this frame |
| 303 | */ |
| 304 | typedef void (*RootlessSwitchWindowProc) |
| 305 | (RootlessWindowPtr pFrame, WindowPtr oldWin); |
| 306 | |
| 307 | /* |
| 308 | * Copy bytes. (Optional) |
| 309 | * Source and destinate may overlap and the right thing should happen. |
| 310 | * |
| 311 | * width Bytes to copy per row |
| 312 | * height Number of rows |
| 313 | * src Source data |
| 314 | * srcRowBytes Width of source in bytes |
| 315 | * dst Destination data |
| 316 | * dstRowBytes Width of destination in bytes |
| 317 | */ |
| 318 | typedef void (*RootlessCopyBytesProc) |
| 319 | (unsigned int width, unsigned int height, |
| 320 | const void *src, unsigned int srcRowBytes, |
| 321 | void *dst, unsigned int dstRowBytes); |
| 322 | |
| 323 | /* |
| 324 | * Copy area in frame to another part of frame. (Optional) |
| 325 | * |
| 326 | * wid Frame id |
| 327 | * dstNrects Number of rectangles to copy |
| 328 | * dstRects Array of rectangles to copy |
| 329 | * dx, dy Number of pixels away to copy area |
| 330 | */ |
| 331 | typedef void (*RootlessCopyWindowProc) |
| 332 | (RootlessFrameID wid, int dstNrects, const BoxRec *dstRects, |
| 333 | int dx, int dy); |
| 334 | |