~ubuntu-branches/ubuntu/intrepid/xserver-xgl/intrepid

« back to all changes in this revision

Viewing changes to Xext/mbufbf.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthew Garrett
  • Date: 2006-02-13 14:21:43 UTC
  • Revision ID: james.westby@ubuntu.com-20060213142143-mad6z9xzem7hzxz9
Tags: upstream-7.0.0
ImportĀ upstreamĀ versionĀ 7.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $XFree86: xc/programs/Xserver/Xext/mbufbf.c,v 3.5tsi Exp $ */
 
2
/*
 
3
 
 
4
Copyright 1989, 1998  The Open Group
 
5
 
 
6
Permission to use, copy, modify, distribute, and sell this software and its
 
7
documentation for any purpose is hereby granted without fee, provided that
 
8
the above copyright notice appear in all copies and that both that
 
9
copyright notice and this permission notice appear in supporting
 
10
documentation.
 
11
 
 
12
The above copyright notice and this permission notice shall be included in
 
13
all copies or substantial portions of the Software.
 
14
 
 
15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
16
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
17
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 
18
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 
19
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 
20
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
21
 
 
22
Except as contained in this notice, the name of The Open Group shall not be
 
23
used in advertising or otherwise to promote the sale, use or other dealings
 
24
in this Software without prior written authorization from The Open Group.
 
25
 
 
26
*/
 
27
 
 
28
/* $Xorg: mbufbf.c,v 1.4 2001/02/09 02:04:32 xorgcvs Exp $ */
 
29
 
 
30
#define NEED_REPLIES
 
31
#define NEED_EVENTS
 
32
#ifdef HAVE_DIX_CONFIG_H
 
33
#include <dix-config.h>
 
34
#endif
 
35
 
 
36
#include <stdio.h>
 
37
#include <X11/X.h>
 
38
#include <X11/Xproto.h>
 
39
#include "misc.h"
 
40
#include "os.h"
 
41
#include "windowstr.h"
 
42
#include "scrnintstr.h"
 
43
#include "pixmapstr.h"
 
44
#include "extnsionst.h"
 
45
#include "dixstruct.h"
 
46
#include "resource.h"
 
47
#include "opaque.h"
 
48
#include "regionstr.h"
 
49
#include "gcstruct.h"
 
50
#include "inputstr.h"
 
51
#include "validate.h"
 
52
#include <sys/time.h>
 
53
 
 
54
#define _MULTIBUF_SERVER_       /* don't want Xlib structures */
 
55
#define _MULTIBUF_BUFFER_
 
56
#include <X11/extensions/multibufst.h>
 
57
 
 
58
/* 
 
59
Support for doublebuffer hardare
 
60
 
 
61
This code is designed to support doublebuffer hardware where the
 
62
displayed buffer is selected on a per-pixel basis by an additional bit
 
63
plane, called the select plane. It could probably be easily modified
 
64
to work with systems that use window-id planes.
 
65
 
 
66
This is done by creating a new drawable type, DRAWABLE_BUFFER. The
 
67
type has the same exact layout as a window drawable. Your code should
 
68
treat a DRAWABLE_BUFFER the same as it would tread a DRAWABLE_WINDOW
 
69
when handling the gc drawing functions. In addition, PaintWindowBackground,
 
70
CopyWindow, and all of the gc drawing functions to be able to draw into both
 
71
framebuffers. Which framebuffer to draw into is selected by the contents of
 
72
        pWin->devPrivates[frameWindowPrivateIndex].
 
73
The content of the devPrivate is either from frameBuffer[0] or
 
74
frameBuffer[1], depending on which buffer is being drawn into. When
 
75
        pWin->devPrivates[frameWindowPrivateIndex] == frameBuffer[0],
 
76
the functions should draw into the front framebuffer. When
 
77
        pWin->devPrivates[frameWindowPrivateIndex] == frameBuffer[1],
 
78
the functions should draw into the back framebuffer.
 
79
 
 
80
In addition, you need to provide a function that allows you to copy
 
81
bits between the buffers (optional since CopyArea can be used) and a
 
82
function that draws into the select plane. Then, you need to register
 
83
your functions and other information, by calling:
 
84
 
 
85
void
 
86
RegisterDoubleBufferHardware(pScreen, nInfo, pInfo, frameBuffer, selectPlane,
 
87
                             CopyBufferBitsFunc, DrawSelectPlaneFunc)
 
88
    int                 nInfo;
 
89
    xMbufBufferInfo     *pInfo;
 
90
    DevUnion            *frameBuffer;
 
91
    DevUnion            selectPlane;
 
92
 
 
93
"pInfo" is an array indicating which visuals and depths that double
 
94
buffering is supported on. "nInfo" is the length of the array.
 
95
 
 
96
"frameBuffer" is array of length 2. The contents of the array element
 
97
is ddx-specific. The content of frameBuffer[0] should, when placed in
 
98
the window private, indicate that framebuffer 0 should be drawn into.
 
99
The contents of frameBuffer[1], when placed into the window private,
 
100
should indicate that framebuffer 1 should be drawn into.
 
101
 
 
102
"selectPlane" is ddx-specific. It should contain information
 
103
neccessary for your displayProc to access the select plane.
 
104
It is passed to DrawSelectPlaneFunc.
 
105
 
 
106
"CopyBufferBitsFunc" is a ddx-specific function that copies from one
 
107
buffer of a multibuffered window to another buffer. If the CopyBufferBitsFunc
 
108
is NULL, a default function will be used that calls pScreen->CopyArea.
 
109
 
 
110
    void CopyBufferBitsFunc(pMBWindow, srcBufferNum, dstBufferNum)
 
111
        mbufWindowPtr pMBWindow;
 
112
        int srcBufferNum, dstBufferNum;
 
113
 
 
114
"DrawSelectPlaneFunc" is a ddx-specific function that fills the
 
115
regions "prgn" of select plane with the value "bufferNum". If 
 
116
selectPlane is a DrawablePtr (such as a PixmapPtr), you can pass
 
117
NULL for DrawSelectPlaneFunc, a default function will be used that
 
118
calls FillRectangle on the selectPlane.
 
119
 
 
120
    void DrawSelectPlaneFunc(pScreen, selectPlane, prgn, bufferNum)
 
121
        ScreenPtr       pScreen;
 
122
        DevUnion        selectPlane;
 
123
        RegionPtr       prgn;
 
124
        long            bufferNum;
 
125
 
 
126
...
 
127
...
 
128
...
 
129
 
 
130
*/
 
131
 
 
132
#define MAX_BUFFERS  2  /* Only supports 2 buffers */
 
133
#define FRONT_BUFFER 0
 
134
#define BACK_BUFFER  1
 
135
 
 
136
 
 
137
/* Buffer drawables have the same structure as window drawables */
 
138
typedef WindowRec BufferRec;
 
139
typedef WindowPtr BufferPtr;
 
140
 
 
141
 
 
142
/*
 
143
 * Call RegisterHdwrBuffer for every screen that has doublebuffer hardware. 
 
144
 */
 
145
 
 
146
static int              bufNumInfo[MAXSCREENS];
 
147
static xMbufBufferInfo  *bufInfo[MAXSCREENS];
 
148
static DevUnion         *bufFrameBuffer[MAXSCREENS];
 
149
static DevUnion         bufselectPlane[MAXSCREENS];
 
150
static void             (* bufCopyBufferBitsFunc[MAXSCREENS])();
 
151
static void             (* bufDrawSelectPlaneFunc[MAXSCREENS])();
 
152
 
 
153
static Bool bufMultibufferInit();
 
154
 
 
155
 
 
156
void
 
157
RegisterDoubleBufferHardware(pScreen, nInfo, pInfo, frameBuffer, selectPlane,
 
158
                             CopyBufferBitsFunc, DrawSelectPlaneFunc)
 
159
    ScreenPtr           pScreen;
 
160
    int                 nInfo;
 
161
    xMbufBufferInfo     *pInfo;
 
162
    DevUnion            *frameBuffer;
 
163
    DevUnion            selectPlane;
 
164
    void                (* CopyBufferBitsFunc)();
 
165
    void                (* DrawSelectPlaneFunc)();
 
166
{
 
167
    bufNumInfo[pScreen->myNum]     = nInfo;
 
168
    bufInfo[pScreen->myNum]        = pInfo;
 
169
    bufFrameBuffer[pScreen->myNum] = frameBuffer;
 
170
    bufselectPlane[pScreen->myNum] = selectPlane;
 
171
 
 
172
    bufCopyBufferBitsFunc[pScreen->myNum]  = CopyBufferBitsFunc;
 
173
    bufDrawSelectPlaneFunc[pScreen->myNum] = DrawSelectPlaneFunc;
 
174
 
 
175
    /* Register ourselves with device-independent multibuffers code */
 
176
    RegisterMultibufferInit(pScreen, bufMultibufferInit);
 
177
}
 
178
 
 
179
 
 
180
/*
 
181
 * Called by Multibuffer extension initialization.
 
182
 * Initializes mbufScreenRec and its devPrivate.
 
183
 */
 
184
    
 
185
static Bool NoopDDA_True() { return TRUE; }
 
186
static Bool bufPositionWindow();
 
187
static int  bufCreateImageBuffers();
 
188
static void bufDestroyImageBuffers();
 
189
static void bufDisplayImageBuffers();
 
190
static void bufClearImageBufferArea();
 
191
static void bufDestroyBuffer();
 
192
static void bufCopyBufferBits();
 
193
static void bufDrawSelectPlane();
 
194
static void bufWrapScreenFuncs();
 
195
static void bufResetProc();
 
196
 
 
197
static void bufPostValidateTree();
 
198
static void bufClipNotify();
 
199
static void bufWindowExposures();
 
200
static Bool bufChangeWindowAttributes();
 
201
static void bufClearToBackground();
 
202
static void bufCopyWindow();
 
203
 
 
204
extern WindowPtr *WindowTable;
 
205
 
 
206
static Bool
 
207
bufMultibufferInit(pScreen, pMBScreen)
 
208
    ScreenPtr pScreen;
 
209
    mbufScreenPtr pMBScreen;
 
210
{
 
211
    mbufBufferPrivPtr   pMBPriv;
 
212
    BoxRec              box;
 
213
 
 
214
    /* Multibuffer info */
 
215
    pMBScreen->nInfo = bufNumInfo[pScreen->myNum];
 
216
    pMBScreen->pInfo = bufInfo[pScreen->myNum];
 
217
 
 
218
    /* Hooks */
 
219
    pMBScreen->CreateImageBuffers = bufCreateImageBuffers;
 
220
    pMBScreen->DestroyImageBuffers = bufDestroyImageBuffers;
 
221
    pMBScreen->DisplayImageBuffers = bufDisplayImageBuffers;
 
222
    pMBScreen->ClearImageBufferArea = bufClearImageBufferArea;
 
223
    pMBScreen->ChangeMBufferAttributes = NoopDDA_True;
 
224
    pMBScreen->ChangeBufferAttributes = NoopDDA_True;
 
225
    pMBScreen->DeleteBufferDrawable = bufDestroyBuffer;
 
226
    pMBScreen->WrapScreenFuncs = bufWrapScreenFuncs;
 
227
    pMBScreen->ResetProc = bufResetProc;
 
228
    /* Create devPrivate part */
 
229
    pMBPriv = (mbufBufferPrivPtr) xalloc(sizeof *pMBPriv);
 
230
    if (!pMBPriv)
 
231
        return (FALSE);
 
232
 
 
233
    pMBScreen->devPrivate.ptr = (pointer) pMBPriv;
 
234
    pMBPriv->frameBuffer  = bufFrameBuffer[pScreen->myNum];
 
235
    pMBPriv->selectPlane = bufselectPlane[pScreen->myNum];
 
236
 
 
237
    /*
 
238
     * Initializing the subtractRgn to the screen area will ensure that
 
239
     * the selectPlane will get cleared on the first PostValidateTree.
 
240
     */
 
241
 
 
242
    box.x1 = 0;
 
243
    box.y1 = 0;
 
244
    box.x2 = pScreen->width;
 
245
    box.y2 = pScreen->height;
 
246
 
 
247
    pMBPriv->rgnChanged = TRUE;
 
248
    REGION_INIT(pScreen, &pMBPriv->backBuffer, &box, 1);
 
249
    REGION_INIT(pScreen, &pMBPriv->subtractRgn, &box, 1);
 
250
    REGION_NULL(pScreen, &pMBPriv->unionRgn);
 
251
 
 
252
    /* Misc functions */
 
253
    pMBPriv->CopyBufferBits  = bufCopyBufferBitsFunc[pScreen->myNum];
 
254
    pMBPriv->DrawSelectPlane = bufDrawSelectPlaneFunc[pScreen->myNum];
 
255
 
 
256
    if (!pMBPriv->CopyBufferBits)
 
257
        pMBPriv->CopyBufferBits = bufCopyBufferBits;
 
258
 
 
259
    if (!pMBPriv->DrawSelectPlane)
 
260
        pMBPriv->DrawSelectPlane = bufDrawSelectPlane;
 
261
 
 
262
    /* screen functions */
 
263
    pMBPriv->funcsWrapped = 0;
 
264
    pMBPriv->inClearToBackground = FALSE;
 
265
    pMBPriv->WindowExposures = NULL;
 
266
    pMBPriv->CopyWindow = NULL;
 
267
    pMBPriv->ClearToBackground = NULL;
 
268
    pMBPriv->ClipNotify = NULL;
 
269
    pMBPriv->ChangeWindowAttributes = NULL;
 
270
 
 
271
    /* Start out wrapped to clear select plane */
 
272
    WRAP_SCREEN_FUNC(pScreen,pMBPriv,PostValidateTree, bufPostValidateTree);
 
273
    return TRUE;
 
274
}
 
275
 
 
276
static void
 
277
UpdateBufferFromWindow(pBuffer, pWin)
 
278
    BufferPtr   pBuffer;
 
279
    WindowPtr   pWin;
 
280
{
 
281
    pBuffer->drawable.x      = pWin->drawable.x;
 
282
    pBuffer->drawable.y      = pWin->drawable.y;
 
283
    pBuffer->drawable.width  = pWin->drawable.width;
 
284
    pBuffer->drawable.height = pWin->drawable.height;
 
285
 
 
286
    pBuffer->drawable.serialNumber = NEXT_SERIAL_NUMBER;
 
287
 
 
288
    /* Update for PaintWindowBackground */
 
289
    pBuffer->parent = pWin->parent;
 
290
 
 
291
    /*
 
292
     * Make the borderClip the same as the clipList so
 
293
     * NotClippedByChildren comes out with just clipList.
 
294
     */
 
295
 
 
296
    pBuffer->clipList   = pWin->clipList;
 
297
    pBuffer->borderClip = pWin->clipList;
 
298
    pBuffer->winSize    = pWin->winSize;
 
299
    pBuffer->borderSize = pWin->borderSize;
 
300
 
 
301
    pBuffer->origin = pWin->origin;
 
302
}
 
303
 
 
304
static BufferPtr
 
305
bufCreateBuffer(pScreen, pWin, bufferNum)
 
306
    ScreenPtr   pScreen;
 
307
    WindowPtr   pWin;
 
308
    int         bufferNum;
 
309
{
 
310
    mbufBufferPrivPtr   pMBPriv;
 
311
    DevUnion    *devPrivates;
 
312
    BufferPtr   pBuffer;
 
313
    int         i;
 
314
 
 
315
    pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
 
316
 
 
317
    pBuffer = AllocateWindow(pWin->drawable.pScreen);
 
318
    if (!pBuffer)
 
319
        return (NULL);
 
320
 
 
321
    /* XXX- Until we know what is needed, copy everything. */
 
322
    devPrivates = pBuffer->devPrivates;
 
323
    *pBuffer = *pWin;
 
324
    pBuffer->devPrivates   = devPrivates;
 
325
 
 
326
    pBuffer->drawable.type = DRAWABLE_BUFFER;
 
327
    pBuffer->drawable.serialNumber = NEXT_SERIAL_NUMBER;
 
328
 
 
329
    pBuffer->nextSib    = NULL;
 
330
    pBuffer->prevSib    = NULL;
 
331
    pBuffer->firstChild = NULL;
 
332
    pBuffer->lastChild  = NULL;
 
333
 
 
334
    /* XXX - Worry about backingstore later */
 
335
    pBuffer->backStorage   = NULL;
 
336
    pBuffer->backingStore  = NotUseful;
 
337
 
 
338
    /* XXX - Need to call pScreen->CreateWindow for tile/stipples
 
339
     *       or should I just copy the devPrivates?
 
340
     */
 
341
    
 
342
    for (i=0; i < pScreen->WindowPrivateLen; i++)
 
343
        pBuffer->devPrivates[i] = pWin->devPrivates[i];
 
344
 
 
345
    pBuffer->devPrivates[frameWindowPrivateIndex] =
 
346
        pMBPriv->frameBuffer[bufferNum];
 
347
 
 
348
    return pBuffer;
 
349
}
 
350
 
 
351
static void
 
352
bufDestroyBuffer(pDrawable)
 
353
    DrawablePtr pDrawable;
 
354
{
 
355
    xfree(pDrawable);
 
356
}
 
357
 
 
358
/*ARGSUSED*/
 
359
static int
 
360
bufCreateImageBuffers (pWin, nbuf, ids, action, hint)
 
361
    WindowPtr   pWin;
 
362
    int         nbuf;
 
363
    XID         *ids;
 
364
    int         action;
 
365
    int         hint;
 
366
{
 
367
    ScreenPtr           pScreen;
 
368
    mbufScreenPtr       pMBScreen;
 
369
    mbufWindowPtr       pMBWindow;
 
370
    mbufBufferPtr       pMBBuffer;
 
371
    int                 i;
 
372
 
 
373
    pScreen   = pWin->drawable.pScreen;
 
374
    pMBScreen = MB_SCREEN_PRIV(pScreen);
 
375
    pMBWindow = MB_WINDOW_PRIV(pWin);
 
376
 
 
377
    pMBWindow->devPrivate.ptr = (pointer) REGION_CREATE(pScreen, 0,0);
 
378
    if (!pMBWindow->devPrivate.ptr)
 
379
        return(0);
 
380
    REGION_COPY(pScreen, (RegionPtr) pMBWindow->devPrivate.ptr,
 
381
                            &pWin->clipList);
 
382
 
 
383
    for (i = 0; i < nbuf; i++)
 
384
    {
 
385
        pMBBuffer = pMBWindow->buffers + i;
 
386
        pMBBuffer->pDrawable = (DrawablePtr) bufCreateBuffer(pScreen,pWin,i);
 
387
 
 
388
        if (!pMBBuffer->pDrawable)
 
389
            break;
 
390
 
 
391
        if (!AddResource (ids[i], MultibufferDrawableResType,
 
392
                          (pointer) pMBBuffer->pDrawable))
 
393
        {
 
394
            bufDestroyBuffer((BufferPtr) pMBBuffer->pDrawable);
 
395
            break;
 
396
        }
 
397
        pMBBuffer->pDrawable->id = ids[i];
 
398
 
 
399
        /*
 
400
         * If window is already mapped, generate exposures and
 
401
         * clear the area of the newly buffers.
 
402
         */
 
403
 
 
404
        if ((pWin->realized) && (i != pMBWindow->displayedMultibuffer))
 
405
            (* pMBScreen->ClearImageBufferArea)(pMBBuffer, 0,0, 0,0, TRUE);
 
406
    }
 
407
 
 
408
    return i;
 
409
}
 
410
 
 
411
static void
 
412
bufDestroyImageBuffers(pWin)
 
413
    WindowPtr   pWin;
 
414
{
 
415
    ScreenPtr           pScreen;
 
416
    mbufWindowPtr       pMBWindow;
 
417
 
 
418
    pScreen   = pWin->drawable.pScreen;
 
419
 
 
420
    if (pMBWindow = MB_WINDOW_PRIV(pWin))
 
421
    {
 
422
        mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
 
423
 
 
424
        /*
 
425
         * if the backbuffer is currently being displayed, move the bits
 
426
         * to the frontbuffer and display it instead.
 
427
         */
 
428
 
 
429
        if (pWin->realized && (pMBWindow->displayedMultibuffer == BACK_BUFFER))
 
430
        {
 
431
            (* pMBPriv->CopyBufferBits)(pMBWindow, BACK_BUFFER, FRONT_BUFFER);
 
432
            REGION_SUBTRACT(pScreen, &pMBPriv->backBuffer,
 
433
                                  &pMBPriv->backBuffer, &pWin->clipList);
 
434
            (* pMBPriv->DrawSelectPlane)(pScreen, pMBPriv->selectPlane,
 
435
                            &pWin->clipList, FRONT_BUFFER);
 
436
        }
 
437
 
 
438
        /* Switch window rendering to front buffer */
 
439
        pWin->devPrivates[frameWindowPrivateIndex] =
 
440
            pMBPriv->frameBuffer[FRONT_BUFFER];
 
441
 
 
442
        REGION_DESTROY(pScreen, (RegionPtr) pMBWindow->devPrivate.ptr);
 
443
        pMBWindow->devPrivate.ptr = NULL;
 
444
    }
 
445
}
 
446
 
 
447
/*
 
448
 * Can be replaced by pScreen->ClearToBackground if pBuffer->eventMask
 
449
 * and wOtherEventsMasks(pBuffer) were setup.
 
450
 */
 
451
 
 
452
static void
 
453
bufClearImageBufferArea(pMBBuffer, x,y, w,h, generateExposures)
 
454
    mbufBufferPtr       pMBBuffer;
 
455
    short               x,y;
 
456
    unsigned short      w,h;
 
457
    Bool                generateExposures;
 
458
{
 
459
    BoxRec box;
 
460
    RegionRec   reg;
 
461
    RegionPtr pBSReg = NullRegion;
 
462
    ScreenPtr   pScreen;
 
463
    BoxPtr  extents;
 
464
    int     x1, y1, x2, y2;
 
465
    BufferPtr pBuffer;
 
466
 
 
467
    pBuffer = (BufferPtr) pMBBuffer->pDrawable;
 
468
    /* compute everything using ints to avoid overflow */
 
469
 
 
470
    x1 = pBuffer->drawable.x + x;
 
471
    y1 = pBuffer->drawable.y + y;
 
472
    if (w)
 
473
        x2 = x1 + (int) w;
 
474
    else
 
475
        x2 = x1 + (int) pBuffer->drawable.width - (int) x;
 
476
    if (h)
 
477
        y2 = y1 + h;    
 
478
    else
 
479
        y2 = y1 + (int) pBuffer->drawable.height - (int) y;
 
480
 
 
481
    extents = &pBuffer->clipList.extents;
 
482
    
 
483
    /* clip the resulting rectangle to the window clipList extents.  This
 
484
     * makes sure that the result will fit in a box, given that the
 
485
     * screen is < 32768 on a side.
 
486
     */
 
487
 
 
488
    if (x1 < extents->x1)
 
489
        x1 = extents->x1;
 
490
    if (x2 > extents->x2)
 
491
        x2 = extents->x2;
 
492
    if (y1 < extents->y1)
 
493
        y1 = extents->y1;
 
494
    if (y2 > extents->y2)
 
495
        y2 = extents->y2;
 
496
 
 
497
    if (x2 <= x1 || y2 <= y1)
 
498
    {
 
499
        x2 = x1 = 0;
 
500
        y2 = y1 = 0;
 
501
    }
 
502
 
 
503
    box.x1 = x1;
 
504
    box.x2 = x2;
 
505
    box.y1 = y1;
 
506
    box.y2 = y2;
 
507
 
 
508
    pScreen = pBuffer->drawable.pScreen;
 
509
    REGION_INIT(pScreen, &reg, &box, 1);
 
510
    if (pBuffer->backStorage)
 
511
    {
 
512
        /*
 
513
         * If the window has backing-store on, call through the
 
514
         * ClearToBackground vector to handle the special semantics
 
515
         * (i.e. things backing store is to be cleared out and
 
516
         * an Expose event is to be generated for those areas in backing
 
517
         * store if generateExposures is TRUE).
 
518
         */
 
519
        pBSReg = (* pScreen->ClearBackingStore)(pBuffer, x, y, w, h,
 
520
                                                 generateExposures);
 
521
    }
 
522
 
 
523
    REGION_INTERSECT(pScreen, &reg, &reg, &pBuffer->clipList);
 
524
    if (pBuffer->backgroundState != None)
 
525
        (*pScreen->PaintWindowBackground)(pBuffer, &reg, PW_BACKGROUND);
 
526
    if (generateExposures)
 
527
        MultibufferExpose(pMBBuffer, &reg);
 
528
#ifdef _notdef
 
529
    /* XXBS - This is the original miClearToBackground code.
 
530
     * WindowExposures needs to be called (or the functionality emulated)
 
531
     * in order for backingStore to work, but first, pBuffer->eventMask
 
532
     * and wOtherEventsMasks(pBuffer) need to be setup correctly.
 
533
     */
 
534
 
 
535
    if (generateExposures)
 
536
        (*pScreen->WindowExposures)(pBuffer, &reg, pBSReg);
 
537
    else if (pBuffer->backgroundState != None)
 
538
        (*pScreen->PaintWindowBackground)(pBuffer, &reg, PW_BACKGROUND);
 
539
#endif
 
540
    REGION_UNINIT(pScreen, &reg);
 
541
    if (pBSReg)
 
542
        REGION_DESTROY(pScreen, pBSReg);
 
543
}
 
544
 
 
545
static void
 
546
bufWrapScreenFuncs(pScreen)
 
547
    ScreenPtr pScreen;
 
548
{
 
549
    mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
 
550
 
 
551
    WRAP_SCREEN_FUNC(pScreen,pMBPriv,PostValidateTree, bufPostValidateTree);
 
552
    WRAP_SCREEN_FUNC(pScreen,pMBPriv,ClipNotify, bufClipNotify);
 
553
    WRAP_SCREEN_FUNC(pScreen,pMBPriv,WindowExposures,bufWindowExposures);
 
554
    WRAP_SCREEN_FUNC(pScreen,pMBPriv,ChangeWindowAttributes, bufChangeWindowAttributes);
 
555
    WRAP_SCREEN_FUNC(pScreen,pMBPriv,ClearToBackground,bufClearToBackground);
 
556
    WRAP_SCREEN_FUNC(pScreen,pMBPriv,CopyWindow,bufCopyWindow);
 
557
}
 
558
 
 
559
static void
 
560
bufResetProc(pScreen)
 
561
    ScreenPtr pScreen;
 
562
{
 
563
    mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
 
564
 
 
565
    /*
 
566
     * frameBuffer, selectPlane, and pInfo should be freed by
 
567
     * whoever called RegisterDoubleBufferHardware
 
568
     */
 
569
 
 
570
    REGION_UNINIT(pScreen, &pMBPriv->backBuffer);
 
571
    REGION_UNINIT(pScreen, &pMBPriv->subtractRgn);
 
572
    REGION_UNINIT(pScreen, &pMBPriv->unionRgn);
 
573
    xfree(pMBPriv);
 
574
}
 
575
 
 
576
/*---------------------------------------------------------------------------*/
 
577
 
 
578
/* 
 
579
 * Used if CopyBufferBitsFunc is not provided when registering.
 
580
 * This should work for everybody since CopyArea needs to support
 
581
 * copying between buffers anyway.
 
582
 */
 
583
 
 
584
static void
 
585
bufCopyBufferBits(pMBWindow, srcBufferNum, dstBufferNum)
 
586
    mbufWindowPtr pMBWindow;
 
587
    int srcBufferNum, dstBufferNum;
 
588
{
 
589
    DrawablePtr pSrcBuffer, pDstBuffer;
 
590
    GCPtr pGC;
 
591
 
 
592
    pSrcBuffer = pMBWindow->buffers[srcBufferNum].pDrawable;
 
593
    pDstBuffer = pMBWindow->buffers[dstBufferNum].pDrawable;
 
594
 
 
595
    pGC = GetScratchGC (pDstBuffer->depth, pDstBuffer->pScreen);
 
596
    if (!pGC)
 
597
        return;
 
598
 
 
599
    ValidateGC (pDstBuffer, pGC);
 
600
    (* pGC->ops->CopyArea) (pSrcBuffer, pDstBuffer, pGC,
 
601
                    0,0, pDstBuffer->width, pDstBuffer->height, 0,0);
 
602
    FreeScratchGC (pGC);
 
603
}
 
604
 
 
605
/*
 
606
 * Used if DrawSelectPlanFunc is not provided for when registering.
 
607
 * However, it only works if selectPlane.ptr is a drawable. Also
 
608
 * assumes that painting with color 0 selects the front buffer,
 
609
 * while color 1 selects the back buffer.
 
610
 */
 
611
 
 
612
static void
 
613
bufDrawSelectPlane(pScreen, selectPlane, prgn, bufferNum)
 
614
    ScreenPtr   pScreen;
 
615
    DevUnion    selectPlane;
 
616
    RegionPtr   prgn;
 
617
    long        bufferNum;
 
618
{
 
619
    DrawablePtr pDrawable;
 
620
    GCPtr pGC;
 
621
    register int i;
 
622
    register BoxPtr pbox;
 
623
    register xRectangle *prect;
 
624
    int numRects;
 
625
    XID value;
 
626
 
 
627
    if (REGION_NUM_RECTS(prgn) == 0)
 
628
        return;
 
629
 
 
630
    pDrawable = (DrawablePtr) selectPlane.ptr;
 
631
    pGC = GetScratchGC (pDrawable->depth, pScreen);
 
632
    if (!pGC)
 
633
        return;
 
634
 
 
635
    prect = (xRectangle *)ALLOCATE_LOCAL(REGION_NUM_RECTS(prgn) *
 
636
                                         sizeof(xRectangle));
 
637
    if (!prect)
 
638
    {
 
639
        FreeScratchGC(pGC);
 
640
        return;
 
641
    }
 
642
 
 
643
    value = (XID) bufferNum;
 
644
    DoChangeGC(pGC, GCForeground, &value, 0);
 
645
    ValidateGC(pDrawable, pGC);
 
646
 
 
647
    numRects = REGION_NUM_RECTS(prgn);
 
648
    pbox = REGION_RECTS(prgn);
 
649
    for (i= numRects; --i >= 0; pbox++, prect++)
 
650
    {
 
651
        prect->x = pbox->x1;
 
652
        prect->y = pbox->y1;
 
653
        prect->width = pbox->x2 - pbox->x1;
 
654
        prect->height = pbox->y2 - pbox->y1;
 
655
    }
 
656
    prect -= numRects;
 
657
    (* pGC->ops->PolyFillRect)(pDrawable, pGC, numRects, prect);
 
658
 
 
659
    DEALLOCATE_LOCAL(prect);
 
660
    FreeScratchGC (pGC);
 
661
}
 
662
 
 
663
 
 
664
static void
 
665
bufDisplayImageBuffers(pScreen, ppMBWindow, ppMBBuffer, nbuf)
 
666
    ScreenPtr           pScreen;
 
667
    mbufBufferPtr       *ppMBBuffer;
 
668
    mbufWindowPtr       *ppMBWindow;
 
669
    int                 nbuf;
 
670
{
 
671
    WindowPtr       pWin;
 
672
    BufferPtr       pPrevBuffer, pNewBuffer;
 
673
    int             i, number;
 
674
    mbufBufferPrivPtr pMBPriv;
 
675
    mbufBufferPtr   pPrevMBBuffer;
 
676
 
 
677
    pMBPriv   = MB_SCREEN_PRIV_BUFFER(pScreen);
 
678
 
 
679
    for (i = 0; i < nbuf; i++)
 
680
    {
 
681
        number = ppMBBuffer[i]->number; /* 0=frontbuffer, 1=backbuffer */
 
682
        pWin = ppMBWindow[i]->pWindow;
 
683
        pPrevMBBuffer = MB_DISPLAYED_BUFFER(ppMBWindow[i]);
 
684
 
 
685
        pPrevBuffer = (BufferPtr) pPrevMBBuffer->pDrawable;
 
686
        pNewBuffer  = (BufferPtr) ppMBBuffer[i]->pDrawable;
 
687
 
 
688
        if (pPrevBuffer != pNewBuffer)
 
689
        {
 
690
            RegionPtr backBuffer = &pMBPriv->backBuffer;
 
691
 
 
692
            /*
 
693
             * Update the select plane and the backBuffer region.
 
694
             */
 
695
 
 
696
            (* pMBPriv->DrawSelectPlane)(pScreen, pMBPriv->selectPlane,
 
697
                            &pWin->clipList, number);
 
698
 
 
699
            if (number == BACK_BUFFER)
 
700
                REGION_UNION(pScreen, backBuffer, backBuffer,
 
701
                                   &pWin->clipList);
 
702
            else
 
703
                REGION_SUBTRACT(pScreen, backBuffer, backBuffer,
 
704
                                   &pWin->clipList);
 
705
 
 
706
            /* Switch which framebuffer the window draws into */
 
707
            pWin->devPrivates[frameWindowPrivateIndex] =
 
708
                pMBPriv->frameBuffer[number];
 
709
        }
 
710
 
 
711
        switch (ppMBWindow[i]->updateAction)
 
712
        {
 
713
        case MultibufferUpdateActionUndefined:
 
714
            break;
 
715
        case MultibufferUpdateActionBackground:
 
716
            (* MB_SCREEN_PRIV(pScreen)->ClearImageBufferArea)
 
717
                (pPrevMBBuffer, 0,0, 0,0, FALSE);
 
718
            break;
 
719
        case MultibufferUpdateActionUntouched:
 
720
            break;
 
721
        case MultibufferUpdateActionCopied:
 
722
            if (pPrevBuffer != pNewBuffer)
 
723
            {
 
724
                (* pMBPriv->CopyBufferBits) (ppMBWindow[i],
 
725
                        ppMBBuffer[i]->number, pPrevMBBuffer->number);
 
726
            }
 
727
            break;
 
728
        }
 
729
    }
 
730
}
 
731
 
 
732
/* Updates the backBuffer region and paints the selectPlane. */
 
733
 
 
734
static void
 
735
bufPostValidateTree(pParent, pChild, kind)
 
736
    WindowPtr   pParent, pChild;
 
737
    VTKind      kind;
 
738
{
 
739
    ScreenPtr pScreen;
 
740
    mbufBufferPrivPtr pMBPriv;
 
741
 
 
742
    if (pParent)
 
743
        pScreen = pParent->drawable.pScreen;
 
744
    else if (pChild)
 
745
        pScreen = pChild->drawable.pScreen;
 
746
    else
 
747
        return; /* Hopeless */
 
748
 
 
749
    pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
 
750
 
 
751
    UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, PostValidateTree);
 
752
    if (pScreen->PostValidateTree)
 
753
        (* pScreen->PostValidateTree)(pParent, pChild, kind);
 
754
    REWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, PostValidateTree);
 
755
 
 
756
    /* Does backBuffer need to change? */
 
757
    if (pMBPriv->rgnChanged)
 
758
    {
 
759
        RegionRec exposed;
 
760
        RegionPtr pSubtractRgn, pUnionRgn;
 
761
        Bool overlap;
 
762
 
 
763
        pMBPriv->rgnChanged = FALSE;
 
764
 
 
765
        pSubtractRgn = &pMBPriv->subtractRgn;
 
766
        pUnionRgn    = &pMBPriv->unionRgn;
 
767
        REGION_VALIDATE(pScreen, pSubtractRgn, &overlap);
 
768
#ifdef DEBUG
 
769
        if (overlap)
 
770
            FatalError("bufPostValidateTree: subtractRgn overlaps");
 
771
#endif
 
772
        REGION_VALIDATE(pScreen, pUnionRgn, &overlap);
 
773
#ifdef DEBUG
 
774
        if (overlap)
 
775
            FatalError("bufPostValidateTree: unionRgn overlaps");
 
776
#endif
 
777
 
 
778
        /* Update backBuffer: subtract must come before union */
 
779
        REGION_SUBTRACT(pScreen, &pMBPriv->backBuffer, &pMBPriv->backBuffer,
 
780
                              pSubtractRgn);
 
781
        REGION_UNION(pScreen, &pMBPriv->backBuffer, &pMBPriv->backBuffer,
 
782
                              pUnionRgn);
 
783
 
 
784
        /* Paint gained and lost backbuffer areas in select plane */
 
785
        REGION_NULL(pScreen, &exposed);
 
786
        REGION_SUBTRACT(pScreen, &exposed, pSubtractRgn, pUnionRgn);
 
787
        (* pMBPriv->DrawSelectPlane)(pScreen, pMBPriv->selectPlane,
 
788
                                     &exposed, FRONT_BUFFER);
 
789
 
 
790
        REGION_SUBTRACT(pScreen, &exposed, pUnionRgn, pSubtractRgn);
 
791
        (* pMBPriv->DrawSelectPlane)(pScreen, pMBPriv->selectPlane,
 
792
                                    &exposed, BACK_BUFFER);
 
793
        
 
794
        REGION_UNINIT(pScreen, &exposed);
 
795
        REGION_EMPTY(pScreen, pSubtractRgn);
 
796
        REGION_EMPTY(pScreen, pUnionRgn);
 
797
    }
 
798
}
 
799
 
 
800
/*
 
801
 * If the window is multibuffered and displaying the backbuffer,
 
802
 * add the old clipList to the subtractRgn and add the new clipList
 
803
 * to the unionRgn. PostValidateTree will use subtractRgn and unionRgn
 
804
 * to update the backBuffer region and the selectPlane.
 
805
 *
 
806
 * Copy changes to the window structure into the buffers.
 
807
 * Send ClobberNotify events.
 
808
 */
 
809
 
 
810
static void
 
811
bufClipNotify(pWin, dx,dy)
 
812
    WindowPtr pWin;
 
813
    int       dx,dy;
 
814
{
 
815
    ScreenPtr pScreen = pWin->drawable.pScreen;
 
816
    mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
 
817
    mbufWindowPtr       pMBWindow;
 
818
    int i;
 
819
 
 
820
    UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, ClipNotify);
 
821
    if (pScreen->ClipNotify)
 
822
        (* pScreen->ClipNotify)(pWin, dx,dy);
 
823
    REWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, ClipNotify);
 
824
 
 
825
    if (pMBWindow = MB_WINDOW_PRIV(pWin))
 
826
    {
 
827
        RegionPtr pOldClipList = (RegionPtr) pMBWindow->devPrivate.ptr;
 
828
 
 
829
        if (! REGION_EQUAL(pScreen, pOldClipList, &pWin->clipList))
 
830
        {
 
831
            if (pMBWindow->displayedMultibuffer == BACK_BUFFER)
 
832
            {
 
833
                pMBPriv->rgnChanged = TRUE;
 
834
                REGION_APPEND(pScreen, &pMBPriv->subtractRgn, pOldClipList);
 
835
                REGION_APPEND(pScreen, &pMBPriv->unionRgn, &pWin->clipList);
 
836
            }
 
837
 
 
838
            REGION_COPY(pScreen, pOldClipList,&pWin->clipList);
 
839
        }
 
840
 
 
841
        /* Update buffer x,y,w,h, and clipList */
 
842
        for (i=0; i<pMBWindow->numMultibuffer; i++)
 
843
        {
 
844
            mbufBufferPtr pMBBuffer = pMBWindow->buffers + i;
 
845
            if (pMBBuffer->clobber != pWin->visibility)
 
846
            {
 
847
                pMBBuffer->clobber = pWin->visibility;
 
848
                MultibufferClobber(pMBBuffer);
 
849
            }
 
850
            UpdateBufferFromWindow(pMBBuffer->pDrawable, pWin);
 
851
        }
 
852
    }
 
853
}
 
854
 
 
855
/*
 
856
 * Updates buffer's background fields when the window's changes.
 
857
 * This is necessary because pScreen->PaintWindowBackground
 
858
 * is used to paint the buffer.
 
859
 *
 
860
 * XXBS - Backingstore state will have be tracked too if it is supported.
 
861
 */
 
862
 
 
863
static Bool
 
864
bufChangeWindowAttributes(pWin, mask)
 
865
    WindowPtr pWin;
 
866
    unsigned long mask;
 
867
{
 
868
    ScreenPtr pScreen = pWin->drawable.pScreen;
 
869
    mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
 
870
    mbufWindowPtr pMBWindow;
 
871
    Bool ret;
 
872
 
 
873
    UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, Bool, ChangeWindowAttributes);
 
874
    ret = (* pScreen->ChangeWindowAttributes)(pWin, mask);
 
875
    REWRAP_SCREEN_FUNC(pScreen, pMBPriv, Bool, ChangeWindowAttributes);
 
876
 
 
877
    if (pMBWindow = MB_WINDOW_PRIV(pWin))
 
878
    {
 
879
        if (mask & (CWBackPixmap | CWBackPixel))
 
880
        {
 
881
            BufferPtr pBuffer;
 
882
            int i;
 
883
 
 
884
            for (i=0; i<pMBWindow->displayedMultibuffer; i++)
 
885
            {
 
886
                pBuffer = (BufferPtr) pMBWindow->buffers[i].pDrawable;
 
887
                pBuffer->backgroundState = pWin->backgroundState;
 
888
                pBuffer->background = pWin->background;
 
889
            }
 
890
        }
 
891
    }
 
892
    return ret;
 
893
}
 
894
 
 
895
/*
 
896
 * Send exposures and clear the background for a buffer whenever
 
897
 * its corresponding window is exposed, except when called by
 
898
 * ClearToBackground.
 
899
 */
 
900
 
 
901
static void 
 
902
bufWindowExposures(pWin, prgn, other_exposed)
 
903
    WindowPtr pWin;
 
904
    register RegionPtr prgn, other_exposed;
 
905
{
 
906
    ScreenPtr pScreen = pWin->drawable.pScreen;
 
907
    mbufWindowPtr pMBWindow = MB_WINDOW_PRIV(pWin);
 
908
    mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
 
909
    RegionRec tmp_rgn;
 
910
    int i;
 
911
    Bool handleBuffers;
 
912
 
 
913
    handleBuffers = (!pMBPriv->inClearToBackground) &&
 
914
        (pWin->drawable.type == DRAWABLE_WINDOW) &&
 
915
        pMBWindow && (prgn && !REGION_NIL(prgn));
 
916
 
 
917
    /* miWindowExposures munges prgn and other_exposed. */
 
918
    if (handleBuffers)
 
919
    {
 
920
        REGION_NULL(pScreen, &tmp_rgn);
 
921
        REGION_COPY(pScreen, &tmp_rgn, prgn);
 
922
    }
 
923
 
 
924
    UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, WindowExposures);
 
925
    (* pScreen->WindowExposures) (pWin, prgn, other_exposed);
 
926
    REWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, WindowExposures);
 
927
 
 
928
    if (!handleBuffers)
 
929
        return;
 
930
 
 
931
    /*
 
932
     * Send expose events to all clients. Paint the exposed region for all
 
933
     * buffers except the displayed buffer since it is handled when the
 
934
     * window is painted.
 
935
     *
 
936
     * XXBS - Will have to be re-written to handle BackingStore on buffers.
 
937
     */
 
938
 
 
939
    for (i=0; i<pMBWindow->numMultibuffer; i++)
 
940
    {
 
941
        mbufBufferPtr pMBBuffer;
 
942
        BufferPtr pBuffer;
 
943
 
 
944
        pMBBuffer = pMBWindow->buffers + i;
 
945
        pBuffer = (BufferPtr) pMBBuffer->pDrawable;
 
946
 
 
947
        if (i != pMBWindow->displayedMultibuffer)
 
948
            (* pScreen->PaintWindowBackground)(pBuffer,&tmp_rgn,PW_BACKGROUND);
 
949
        if ((pMBBuffer->otherEventMask | pMBBuffer->eventMask) & ExposureMask)
 
950
            MultibufferExpose(pMBBuffer, &tmp_rgn);
 
951
    }
 
952
 
 
953
    REGION_UNINIT(pScreen, &tmp_rgn);
 
954
}
 
955
 
 
956
/*
 
957
 * Set ``inClearToBackground'' so that WindowExposures does not attempt
 
958
 * to send expose events or clear the background on the buffers.
 
959
 */
 
960
 
 
961
static void
 
962
bufClearToBackground(pWin, x,y,w,h, sendExpose)
 
963
    WindowPtr pWin;
 
964
    int x,y, w,h;
 
965
    Bool sendExpose;
 
966
{
 
967
    ScreenPtr pScreen = pWin->drawable.pScreen;
 
968
    mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
 
969
 
 
970
    pMBPriv->inClearToBackground = TRUE;
 
971
 
 
972
    UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, ClearToBackground);
 
973
    (* pScreen->ClearToBackground)(pWin, x,y,w,h, sendExpose);
 
974
    REWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, ClearToBackground);
 
975
 
 
976
    pMBPriv->inClearToBackground = FALSE;
 
977
}
 
978
 
 
979
/*
 
980
 * Move bits in both buffers. It does this by calling pScreen->CopyWindow
 
981
 * twice, once with the root window's devPrivate[frameWindowPrivateIndex]
 
982
 * pointing to the frontbuffer pixmap and once with it pointed to the
 
983
 * backbuffer pixmap. It does this if there are *any* existing multibuffered
 
984
 * window... a possible optimization is to copy the backbuffer only if this
 
985
 * window or its inferiors are multibuffered. May be faster, maybe not.
 
986
 *
 
987
 * XXX - Only works if your CopyWindow checks the root window's devPrivate
 
988
 *       to see which buffer to draw into. Works for cfbPaintWindow.
 
989
 */
 
990
 
 
991
/*ARGSUSED*/
 
992
static void 
 
993
bufCopyWindow(pWin, ptOldOrg, prgnSrc)
 
994
    WindowPtr pWin;
 
995
    DDXPointRec ptOldOrg;
 
996
    RegionPtr prgnSrc;
 
997
{
 
998
    ScreenPtr pScreen = pWin->drawable.pScreen;
 
999
    mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
 
1000
    WindowPtr pwinroot;
 
1001
    DevUnion save;
 
1002
 
 
1003
    UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, CopyWindow);
 
1004
 
 
1005
    pwinroot = WindowTable[pScreen->myNum];
 
1006
    save = pwinroot->devPrivates[frameWindowPrivateIndex];
 
1007
 
 
1008
    /*
 
1009
     * Copy front buffer
 
1010
     */
 
1011
 
 
1012
    pwinroot->devPrivates[frameWindowPrivateIndex] =
 
1013
        pMBPriv->frameBuffer[FRONT_BUFFER];
 
1014
    (* pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc);
 
1015
 
 
1016
    /*
 
1017
     * Copy back buffer
 
1018
     */
 
1019
 
 
1020
    /* CopyWindow translates prgnSrc... translate it back for 2nd call. */
 
1021
    REGION_TRANSLATE(pScreen, prgnSrc,
 
1022
                                  ptOldOrg.x - pWin->drawable.x,
 
1023
                                  ptOldOrg.y - pWin->drawable.y);
 
1024
    pwinroot->devPrivates[frameWindowPrivateIndex] =
 
1025
        pMBPriv->frameBuffer[BACK_BUFFER];
 
1026
    (* pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc);
 
1027
 
 
1028
    pwinroot->devPrivates[frameWindowPrivateIndex] = save;
 
1029
    REWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, CopyWindow);
 
1030
}