703aeb336357698fe9a423e66a109073c0a6ff27
2 * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina.
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation on the rights to use, copy, modify, merge,
10 * publish, distribute, sublicense, and/or sell copies of the Software,
11 * and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * Kevin E. Martin <kem@redhat.com>
35 * This file provides support for GCs. */
37 #ifdef HAVE_DMX_CONFIG_H
38 #include <dmx-config.h>
45 #include "dmxpixmap.h"
49 #include "pixmapstr.h"
52 static GCFuncs dmxGCFuncs
= {
62 static GCOps dmxGCOps
= {
85 /** Initialize the GC on \a pScreen */
87 dmxInitGC(ScreenPtr pScreen
)
89 if (!dixRegisterPrivateKey
90 (&dmxGCPrivateKeyRec
, PRIVATE_GC
, sizeof(dmxGCPrivRec
)))
95 /** Create the GC on the back-end server. */
97 dmxBECreateGC(ScreenPtr pScreen
, GCPtr pGC
)
99 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
100 dmxGCPrivPtr pGCPriv
= DMX_GET_GC_PRIV(pGC
);
103 for (i
= 0; i
< dmxScreen
->beNumPixmapFormats
; i
++) {
104 if (pGC
->depth
== dmxScreen
->bePixmapFormats
[i
].depth
) {
108 mask
= GCGraphicsExposures
;
109 gcvals
.graphics_exposures
= FALSE
;
111 /* Create GC in the back-end servers */
112 pGCPriv
->gc
= XCreateGC(dmxScreen
->beDisplay
,
113 dmxScreen
->scrnDefDrawables
[i
],
120 /** Create a graphics context on the back-end server associated /a pGC's
123 dmxCreateGC(GCPtr pGC
)
125 ScreenPtr pScreen
= pGC
->pScreen
;
126 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
127 dmxGCPrivPtr pGCPriv
= DMX_GET_GC_PRIV(pGC
);
130 DMX_UNWRAP(CreateGC
, dmxScreen
, pScreen
);
131 if ((ret
= pScreen
->CreateGC(pGC
))) {
132 /* Save the old funcs */
133 pGCPriv
->funcs
= pGC
->funcs
;
136 pGC
->funcs
= &dmxGCFuncs
;
138 if (dmxScreen
->beDisplay
) {
139 dmxBECreateGC(pScreen
, pGC
);
145 /* Check for "magic special case"
146 * 1. see CreateGC in dix/gc.c for more info
147 * 2. see dmxChangeGC for more info
149 pGCPriv
->msc
= (!pGC
->tileIsPixel
&& !pGC
->tile
.pixmap
);
151 DMX_WRAP(CreateGC
, dmxCreateGC
, dmxScreen
, pScreen
);
156 /** Validate a graphics context, \a pGC, locally in the DMX server and
157 * recompute the composite clip, if necessary. */
159 dmxValidateGC(GCPtr pGC
, unsigned long changes
, DrawablePtr pDrawable
)
161 dmxGCPrivPtr pGCPriv
= DMX_GET_GC_PRIV(pGC
);
163 DMX_GC_FUNC_PROLOGUE(pGC
);
165 pGC
->funcs
->ValidateGC(pGC
, changes
, pDrawable
);
168 if (pDrawable
->type
== DRAWABLE_WINDOW
||
169 pDrawable
->type
== DRAWABLE_PIXMAP
) {
170 /* Save the old ops, since we're about to change the ops in the
173 pGCPriv
->ops
= pGC
->ops
;
179 /* If the client clip is different or moved OR the subwindowMode has
180 * changed OR the window's clip has changed since the last
181 * validation, then we need to recompute the composite clip.
183 if ((changes
& (GCClipXOrigin
|
187 (pDrawable
->serialNumber
!=
188 (pGC
->serialNumber
& DRAWABLE_SERIAL_BITS
))) {
189 miComputeCompositeClip(pGC
, pDrawable
);
192 DMX_GC_FUNC_EPILOGUE(pGC
);
195 /** Set the values in the graphics context on the back-end server
196 * associated with \a pGC's screen. */
198 dmxChangeGC(GCPtr pGC
, unsigned long mask
)
200 ScreenPtr pScreen
= pGC
->pScreen
;
201 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
202 dmxGCPrivPtr pGCPriv
= DMX_GET_GC_PRIV(pGC
);
205 DMX_GC_FUNC_PROLOGUE(pGC
);
207 pGC
->funcs
->ChangeGC(pGC
, mask
);
210 /* Handle "magic special case" from CreateGC */
212 /* The "magic special case" is used to handle the case where a
213 * foreground pixel is set when the GC is created so that a
214 * "pseudo default-tile" can be created and used in case the
215 * fillstyle was set to FillTiled. This specific case is tested
216 * in xtest (XCreateGC test #3). What has happened in dix by
217 * the time it reaches here is (1) the pGC->tile.pixel has been
218 * set to pGC->fgPixel and pGC->tileIsPixel is set, (2) if a
219 * tile has also been set, then pGC->tileIsPixel is unset and
220 * pGC->tile.pixmap is initialized; else, the default tile is
221 * created and pGC->tileIsPixel is unset and pGC->tile.pixmap is
222 * initialized to the "pseudo default-tile". In either case,
223 * pGC->tile.pixmap is set; however, in the "magic special case"
224 * the mask is not updated to allow us to detect that we should
225 * initialize the GCTile in the back-end server. Thus, we catch
226 * this case in dmxCreateGC and add GCTile to the mask here.
227 * Are there any cases that I've missed?
230 /* Make sure that the tile.pixmap is set, just in case the user
231 * set GCTile in the mask but forgot to set vals.pixmap
233 if (pGC
->tile
.pixmap
)
236 /* This only happens once when the GC is created */
237 pGCPriv
->msc
= FALSE
;
240 /* Update back-end server's gc */
241 if (mask
& GCFunction
)
242 v
.function
= pGC
->alu
;
243 if (mask
& GCPlaneMask
)
244 v
.plane_mask
= pGC
->planemask
;
245 if (mask
& GCForeground
)
246 v
.foreground
= pGC
->fgPixel
;
247 if (mask
& GCBackground
)
248 v
.background
= pGC
->bgPixel
;
249 if (mask
& GCLineWidth
)
250 v
.line_width
= pGC
->lineWidth
;
251 if (mask
& GCLineStyle
)
252 v
.line_style
= pGC
->lineStyle
;
253 if (mask
& GCCapStyle
)
254 v
.cap_style
= pGC
->capStyle
;
255 if (mask
& GCJoinStyle
)
256 v
.join_style
= pGC
->joinStyle
;
257 if (mask
& GCFillStyle
)
258 v
.fill_style
= pGC
->fillStyle
;
259 if (mask
& GCFillRule
)
260 v
.fill_rule
= pGC
->fillRule
;
262 if (pGC
->tileIsPixel
) {
266 dmxPixPrivPtr pPixPriv
= DMX_GET_PIXMAP_PRIV(pGC
->tile
.pixmap
);
268 v
.tile
= (Drawable
) pPixPriv
->pixmap
;
271 if (mask
& GCStipple
) {
272 dmxPixPrivPtr pPixPriv
= DMX_GET_PIXMAP_PRIV(pGC
->stipple
);
274 v
.stipple
= (Drawable
) pPixPriv
->pixmap
;
276 if (mask
& GCTileStipXOrigin
)
277 v
.ts_x_origin
= pGC
->patOrg
.x
;
278 if (mask
& GCTileStipYOrigin
)
279 v
.ts_y_origin
= pGC
->patOrg
.y
;
281 if (dmxScreen
->beDisplay
) {
282 dmxFontPrivPtr pFontPriv
;
284 pFontPriv
= FontGetPrivate(pGC
->font
, dmxFontPrivateIndex
);
285 v
.font
= pFontPriv
->font
[pScreen
->myNum
]->fid
;
291 if (mask
& GCSubwindowMode
)
292 v
.subwindow_mode
= pGC
->subWindowMode
;
294 /* Graphics exposures are not needed on the back-ends since they can
295 be generated on the front-end thereby saving bandwidth. */
296 if (mask
& GCGraphicsExposures
)
297 mask
&= ~GCGraphicsExposures
;
299 if (mask
& GCClipXOrigin
)
300 v
.clip_x_origin
= pGC
->clipOrg
.x
;
301 if (mask
& GCClipYOrigin
)
302 v
.clip_y_origin
= pGC
->clipOrg
.y
;
303 if (mask
& GCClipMask
)
304 mask
&= ~GCClipMask
; /* See ChangeClip */
305 if (mask
& GCDashOffset
)
306 v
.dash_offset
= pGC
->dashOffset
;
307 if (mask
& GCDashList
) {
309 if (dmxScreen
->beDisplay
)
310 XSetDashes(dmxScreen
->beDisplay
, pGCPriv
->gc
,
311 pGC
->dashOffset
, (char *) pGC
->dash
, pGC
->numInDashList
);
313 if (mask
& GCArcMode
)
314 v
.arc_mode
= pGC
->arcMode
;
316 if (mask
&& dmxScreen
->beDisplay
) {
317 XChangeGC(dmxScreen
->beDisplay
, pGCPriv
->gc
, mask
, &v
);
318 dmxSync(dmxScreen
, FALSE
);
321 DMX_GC_FUNC_EPILOGUE(pGC
);
324 /** Copy \a pGCSrc to \a pGCDst on the back-end server associated with
325 * \a pGCSrc's screen. */
327 dmxCopyGC(GCPtr pGCSrc
, unsigned long changes
, GCPtr pGCDst
)
329 ScreenPtr pScreen
= pGCSrc
->pScreen
;
330 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
331 dmxGCPrivPtr pGCSrcPriv
= DMX_GET_GC_PRIV(pGCSrc
);
332 dmxGCPrivPtr pGCDstPriv
= DMX_GET_GC_PRIV(pGCDst
);
334 DMX_GC_FUNC_PROLOGUE(pGCDst
);
335 pGCDst
->funcs
->CopyGC(pGCSrc
, changes
, pGCDst
);
337 /* Copy the GC on the back-end server */
338 if (dmxScreen
->beDisplay
)
339 XCopyGC(dmxScreen
->beDisplay
, pGCSrcPriv
->gc
, changes
, pGCDstPriv
->gc
);
341 DMX_GC_FUNC_EPILOGUE(pGCDst
);
344 /** Free the \a pGC on the back-end server. */
346 dmxBEFreeGC(GCPtr pGC
)
348 ScreenPtr pScreen
= pGC
->pScreen
;
349 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
350 dmxGCPrivPtr pGCPriv
= DMX_GET_GC_PRIV(pGC
);
353 XFreeGC(dmxScreen
->beDisplay
, pGCPriv
->gc
);
361 /** Destroy the graphics context, \a pGC and free the corresponding GC
362 * on the back-end server. */
364 dmxDestroyGC(GCPtr pGC
)
366 ScreenPtr pScreen
= pGC
->pScreen
;
367 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
369 DMX_GC_FUNC_PROLOGUE(pGC
);
371 /* Free the GC on the back-end server */
372 if (dmxScreen
->beDisplay
)
375 pGC
->funcs
->DestroyGC(pGC
);
376 DMX_GC_FUNC_EPILOGUE(pGC
);
379 /** Change the clip rects for a GC. */
381 dmxChangeClip(GCPtr pGC
, int type
, pointer pvalue
, int nrects
)
383 ScreenPtr pScreen
= pGC
->pScreen
;
384 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
385 dmxGCPrivPtr pGCPriv
= DMX_GET_GC_PRIV(pGC
);
390 DMX_GC_FUNC_PROLOGUE(pGC
);
391 pGC
->funcs
->ChangeClip(pGC
, type
, pvalue
, nrects
);
393 /* Set the client clip on the back-end server */
394 switch (pGC
->clientClipType
) {
396 if (dmxScreen
->beDisplay
)
397 XSetClipMask(dmxScreen
->beDisplay
, pGCPriv
->gc
, None
);
401 if (dmxScreen
->beDisplay
) {
402 nRects
= RegionNumRects((RegionPtr
) pGC
->clientClip
);
403 pRects
= malloc(nRects
* sizeof(*pRects
));
404 pBox
= RegionRects((RegionPtr
) pGC
->clientClip
);
406 for (i
= 0; i
< nRects
; i
++) {
407 pRects
[i
].x
= pBox
[i
].x1
;
408 pRects
[i
].y
= pBox
[i
].y1
;
409 pRects
[i
].width
= pBox
[i
].x2
- pBox
[i
].x1
;
410 pRects
[i
].height
= pBox
[i
].y2
- pBox
[i
].y1
;
413 XSetClipRectangles(dmxScreen
->beDisplay
, pGCPriv
->gc
,
414 pGC
->clipOrg
.x
, pGC
->clipOrg
.y
,
415 pRects
, nRects
, Unsorted
);
422 /* Condensed down to REGION in the mi code */
426 DMX_GC_FUNC_EPILOGUE(pGC
);
429 /** Destroy a GC's clip rects. */
431 dmxDestroyClip(GCPtr pGC
)
433 ScreenPtr pScreen
= pGC
->pScreen
;
434 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
435 dmxGCPrivPtr pGCPriv
= DMX_GET_GC_PRIV(pGC
);
437 DMX_GC_FUNC_PROLOGUE(pGC
);
438 pGC
->funcs
->DestroyClip(pGC
);
440 /* Set the client clip on the back-end server to None */
441 if (dmxScreen
->beDisplay
)
442 XSetClipMask(dmxScreen
->beDisplay
, pGCPriv
->gc
, None
);
444 DMX_GC_FUNC_EPILOGUE(pGC
);
447 /** Copy a GC's clip rects. */
449 dmxCopyClip(GCPtr pGCDst
, GCPtr pGCSrc
)
451 DMX_GC_FUNC_PROLOGUE(pGCDst
);
452 pGCDst
->funcs
->CopyClip(pGCDst
, pGCSrc
);
453 DMX_GC_FUNC_EPILOGUE(pGCDst
);