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, which currently involves allocating
86 * the GC private associated with this screen. */
87 Bool
dmxInitGC(ScreenPtr pScreen
)
89 if (!AllocateGCPrivate(pScreen
, dmxGCPrivateIndex
, sizeof(dmxGCPrivRec
)))
95 /** Create the GC on the back-end server. */
96 void dmxBECreateGC(ScreenPtr pScreen
, GCPtr pGC
)
98 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
99 dmxGCPrivPtr pGCPriv
= DMX_GET_GC_PRIV(pGC
);
102 for (i
= 0; i
< dmxScreen
->beNumPixmapFormats
; i
++) {
103 if (pGC
->depth
== dmxScreen
->bePixmapFormats
[i
].depth
) {
107 mask
= GCGraphicsExposures
;
108 gcvals
.graphics_exposures
= FALSE
;
110 /* Create GC in the back-end servers */
111 pGCPriv
->gc
= XCreateGC(dmxScreen
->beDisplay
,
112 dmxScreen
->scrnDefDrawables
[i
],
119 /** Create a graphics context on the back-end server associated /a pGC's
121 Bool
dmxCreateGC(GCPtr pGC
)
123 ScreenPtr pScreen
= pGC
->pScreen
;
124 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
125 dmxGCPrivPtr pGCPriv
= DMX_GET_GC_PRIV(pGC
);
128 DMX_UNWRAP(CreateGC
, dmxScreen
, pScreen
);
129 if ((ret
= pScreen
->CreateGC(pGC
))) {
130 /* Save the old funcs */
131 pGCPriv
->funcs
= pGC
->funcs
;
134 pGC
->funcs
= &dmxGCFuncs
;
136 if (dmxScreen
->beDisplay
) {
137 dmxBECreateGC(pScreen
, pGC
);
142 /* Check for "magic special case"
143 * 1. see CreateGC in dix/gc.c for more info
144 * 2. see dmxChangeGC for more info
146 pGCPriv
->msc
= (!pGC
->tileIsPixel
&& !pGC
->tile
.pixmap
);
148 DMX_WRAP(CreateGC
, dmxCreateGC
, dmxScreen
, pScreen
);
153 /** Validate a graphics context, \a pGC, locally in the DMX server and
154 * recompute the composite clip, if necessary. */
155 void dmxValidateGC(GCPtr pGC
, unsigned long changes
, DrawablePtr pDrawable
)
157 dmxGCPrivPtr pGCPriv
= DMX_GET_GC_PRIV(pGC
);
159 DMX_GC_FUNC_PROLOGUE(pGC
);
161 pGC
->funcs
->ValidateGC(pGC
, changes
, pDrawable
);
164 if (pDrawable
->type
== DRAWABLE_WINDOW
||
165 pDrawable
->type
== DRAWABLE_PIXMAP
) {
166 /* Save the old ops, since we're about to change the ops in the
169 pGCPriv
->ops
= pGC
->ops
;
174 /* If the client clip is different or moved OR the subwindowMode has
175 * changed OR the window's clip has changed since the last
176 * validation, then we need to recompute the composite clip.
178 if ((changes
& (GCClipXOrigin
|
182 (pDrawable
->serialNumber
!=
183 (pGC
->serialNumber
& DRAWABLE_SERIAL_BITS
))) {
184 miComputeCompositeClip(pGC
, pDrawable
);
187 DMX_GC_FUNC_EPILOGUE(pGC
);
190 /** Set the values in the graphics context on the back-end server
191 * associated with \a pGC's screen. */
192 void dmxChangeGC(GCPtr pGC
, unsigned long mask
)
194 ScreenPtr pScreen
= pGC
->pScreen
;
195 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
196 dmxGCPrivPtr pGCPriv
= DMX_GET_GC_PRIV(pGC
);
199 DMX_GC_FUNC_PROLOGUE(pGC
);
201 pGC
->funcs
->ChangeGC(pGC
, mask
);
204 /* Handle "magic special case" from CreateGC */
206 /* The "magic special case" is used to handle the case where a
207 * foreground pixel is set when the GC is created so that a
208 * "pseudo default-tile" can be created and used in case the
209 * fillstyle was set to FillTiled. This specific case is tested
210 * in xtest (XCreateGC test #3). What has happened in dix by
211 * the time it reaches here is (1) the pGC->tile.pixel has been
212 * set to pGC->fgPixel and pGC->tileIsPixel is set, (2) if a
213 * tile has also been set, then pGC->tileIsPixel is unset and
214 * pGC->tile.pixmap is initialized; else, the default tile is
215 * created and pGC->tileIsPixel is unset and pGC->tile.pixmap is
216 * initialized to the "pseudo default-tile". In either case,
217 * pGC->tile.pixmap is set; however, in the "magic special case"
218 * the mask is not updated to allow us to detect that we should
219 * initialize the GCTile in the back-end server. Thus, we catch
220 * this case in dmxCreateGC and add GCTile to the mask here.
221 * Are there any cases that I've missed?
224 /* Make sure that the tile.pixmap is set, just in case the user
225 * set GCTile in the mask but forgot to set vals.pixmap
227 if (pGC
->tile
.pixmap
) mask
|= GCTile
;
229 /* This only happens once when the GC is created */
230 pGCPriv
->msc
= FALSE
;
233 /* Update back-end server's gc */
234 if (mask
& GCFunction
) v
.function
= pGC
->alu
;
235 if (mask
& GCPlaneMask
) v
.plane_mask
= pGC
->planemask
;
236 if (mask
& GCForeground
) v
.foreground
= pGC
->fgPixel
;
237 if (mask
& GCBackground
) v
.background
= pGC
->bgPixel
;
238 if (mask
& GCLineWidth
) v
.line_width
= pGC
->lineWidth
;
239 if (mask
& GCLineStyle
) v
.line_style
= pGC
->lineStyle
;
240 if (mask
& GCCapStyle
) v
.cap_style
= pGC
->capStyle
;
241 if (mask
& GCJoinStyle
) v
.join_style
= pGC
->joinStyle
;
242 if (mask
& GCFillStyle
) v
.fill_style
= pGC
->fillStyle
;
243 if (mask
& GCFillRule
) v
.fill_rule
= pGC
->fillRule
;
245 if (pGC
->tileIsPixel
) {
248 dmxPixPrivPtr pPixPriv
= DMX_GET_PIXMAP_PRIV(pGC
->tile
.pixmap
);
249 v
.tile
= (Drawable
)pPixPriv
->pixmap
;
252 if (mask
& GCStipple
) {
253 dmxPixPrivPtr pPixPriv
= DMX_GET_PIXMAP_PRIV(pGC
->stipple
);
254 v
.stipple
= (Drawable
)pPixPriv
->pixmap
;
256 if (mask
& GCTileStipXOrigin
) v
.ts_x_origin
= pGC
->patOrg
.x
;
257 if (mask
& GCTileStipYOrigin
) v
.ts_y_origin
= pGC
->patOrg
.y
;
259 if (dmxScreen
->beDisplay
) {
260 dmxFontPrivPtr pFontPriv
;
261 pFontPriv
= FontGetPrivate(pGC
->font
, dmxFontPrivateIndex
);
262 v
.font
= pFontPriv
->font
[pScreen
->myNum
]->fid
;
267 if (mask
& GCSubwindowMode
) v
.subwindow_mode
= pGC
->subWindowMode
;
269 /* Graphics exposures are not needed on the back-ends since they can
270 be generated on the front-end thereby saving bandwidth. */
271 if (mask
& GCGraphicsExposures
) mask
&= ~GCGraphicsExposures
;
273 if (mask
& GCClipXOrigin
) v
.clip_x_origin
= pGC
->clipOrg
.x
;
274 if (mask
& GCClipYOrigin
) v
.clip_y_origin
= pGC
->clipOrg
.y
;
275 if (mask
& GCClipMask
) mask
&= ~GCClipMask
; /* See ChangeClip */
276 if (mask
& GCDashOffset
) v
.dash_offset
= pGC
->dashOffset
;
277 if (mask
& GCDashList
) {
279 if (dmxScreen
->beDisplay
)
280 XSetDashes(dmxScreen
->beDisplay
, pGCPriv
->gc
,
281 pGC
->dashOffset
, (char *)pGC
->dash
,
284 if (mask
& GCArcMode
) v
.arc_mode
= pGC
->arcMode
;
286 if (mask
&& dmxScreen
->beDisplay
) {
287 XChangeGC(dmxScreen
->beDisplay
, pGCPriv
->gc
, mask
, &v
);
288 dmxSync(dmxScreen
, FALSE
);
291 DMX_GC_FUNC_EPILOGUE(pGC
);
294 /** Copy \a pGCSrc to \a pGCDst on the back-end server associated with
295 * \a pGCSrc's screen. */
296 void dmxCopyGC(GCPtr pGCSrc
, unsigned long changes
, GCPtr pGCDst
)
298 ScreenPtr pScreen
= pGCSrc
->pScreen
;
299 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
300 dmxGCPrivPtr pGCSrcPriv
= DMX_GET_GC_PRIV(pGCSrc
);
301 dmxGCPrivPtr pGCDstPriv
= DMX_GET_GC_PRIV(pGCDst
);
303 DMX_GC_FUNC_PROLOGUE(pGCDst
);
304 pGCDst
->funcs
->CopyGC(pGCSrc
, changes
, pGCDst
);
306 /* Copy the GC on the back-end server */
307 if (dmxScreen
->beDisplay
)
308 XCopyGC(dmxScreen
->beDisplay
, pGCSrcPriv
->gc
, changes
, pGCDstPriv
->gc
);
310 DMX_GC_FUNC_EPILOGUE(pGCDst
);
313 /** Free the \a pGC on the back-end server. */
314 Bool
dmxBEFreeGC(GCPtr pGC
)
316 ScreenPtr pScreen
= pGC
->pScreen
;
317 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
318 dmxGCPrivPtr pGCPriv
= DMX_GET_GC_PRIV(pGC
);
321 XFreeGC(dmxScreen
->beDisplay
, pGCPriv
->gc
);
329 /** Destroy the graphics context, \a pGC and free the corresponding GC
330 * on the back-end server. */
331 void dmxDestroyGC(GCPtr pGC
)
333 ScreenPtr pScreen
= pGC
->pScreen
;
334 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
336 DMX_GC_FUNC_PROLOGUE(pGC
);
338 /* Free the GC on the back-end server */
339 if (dmxScreen
->beDisplay
)
342 pGC
->funcs
->DestroyGC(pGC
);
343 DMX_GC_FUNC_EPILOGUE(pGC
);
346 /** Change the clip rects for a GC. */
347 void dmxChangeClip(GCPtr pGC
, int type
, pointer pvalue
, int nrects
)
349 ScreenPtr pScreen
= pGC
->pScreen
;
350 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
351 dmxGCPrivPtr pGCPriv
= DMX_GET_GC_PRIV(pGC
);
356 DMX_GC_FUNC_PROLOGUE(pGC
);
357 pGC
->funcs
->ChangeClip(pGC
, type
, pvalue
, nrects
);
359 /* Set the client clip on the back-end server */
360 switch (pGC
->clientClipType
) {
362 if (dmxScreen
->beDisplay
)
363 XSetClipMask(dmxScreen
->beDisplay
, pGCPriv
->gc
, None
);
367 if (dmxScreen
->beDisplay
) {
368 nRects
= REGION_NUM_RECTS((RegionPtr
)pGC
->clientClip
);
369 pRects
= xalloc(nRects
* sizeof(*pRects
));
370 pBox
= REGION_RECTS((RegionPtr
)pGC
->clientClip
);
372 for (i
= 0; i
< nRects
; i
++) {
373 pRects
[i
].x
= pBox
[i
].x1
;
374 pRects
[i
].y
= pBox
[i
].y1
;
375 pRects
[i
].width
= pBox
[i
].x2
- pBox
[i
].x1
;
376 pRects
[i
].height
= pBox
[i
].y2
- pBox
[i
].y1
;
379 XSetClipRectangles(dmxScreen
->beDisplay
, pGCPriv
->gc
,
380 pGC
->clipOrg
.x
, pGC
->clipOrg
.y
,
381 pRects
, nRects
, Unsorted
);
392 /* These clip types are condensed down to either NONE or REGION
397 DMX_GC_FUNC_EPILOGUE(pGC
);
400 /** Destroy a GC's clip rects. */
401 void dmxDestroyClip(GCPtr pGC
)
403 ScreenPtr pScreen
= pGC
->pScreen
;
404 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
405 dmxGCPrivPtr pGCPriv
= DMX_GET_GC_PRIV(pGC
);
407 DMX_GC_FUNC_PROLOGUE(pGC
);
408 pGC
->funcs
->DestroyClip(pGC
);
410 /* Set the client clip on the back-end server to None */
411 if (dmxScreen
->beDisplay
)
412 XSetClipMask(dmxScreen
->beDisplay
, pGCPriv
->gc
, None
);
414 DMX_GC_FUNC_EPILOGUE(pGC
);
417 /** Copy a GC's clip rects. */
418 void dmxCopyClip(GCPtr pGCDst
, GCPtr pGCSrc
)
420 DMX_GC_FUNC_PROLOGUE(pGCDst
);
421 pGCDst
->funcs
->CopyClip(pGCDst
, pGCSrc
);
422 DMX_GC_FUNC_EPILOGUE(pGCDst
);