First import
[xorg_rtime.git] / xorg-server-1.4 / hw / dmx / dmxgc.c
blob981f64d0aa280b00ca5086480b13bd62736eef2e
1 /*
2 * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina.
4 * All Rights Reserved.
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
25 * SOFTWARE.
29 * Authors:
30 * Kevin E. Martin <kem@redhat.com>
34 /** \file
35 * This file provides support for GCs. */
37 #ifdef HAVE_DMX_CONFIG_H
38 #include <dmx-config.h>
39 #endif
41 #include "dmx.h"
42 #include "dmxsync.h"
43 #include "dmxgc.h"
44 #include "dmxgcops.h"
45 #include "dmxpixmap.h"
46 #include "dmxfont.h"
48 #include "gcstruct.h"
49 #include "pixmapstr.h"
50 #include "migc.h"
52 static GCFuncs dmxGCFuncs = {
53 dmxValidateGC,
54 dmxChangeGC,
55 dmxCopyGC,
56 dmxDestroyGC,
57 dmxChangeClip,
58 dmxDestroyClip,
59 dmxCopyClip,
62 static GCOps dmxGCOps = {
63 dmxFillSpans,
64 dmxSetSpans,
65 dmxPutImage,
66 dmxCopyArea,
67 dmxCopyPlane,
68 dmxPolyPoint,
69 dmxPolylines,
70 dmxPolySegment,
71 dmxPolyRectangle,
72 dmxPolyArc,
73 dmxFillPolygon,
74 dmxPolyFillRect,
75 dmxPolyFillArc,
76 dmxPolyText8,
77 dmxPolyText16,
78 dmxImageText8,
79 dmxImageText16,
80 dmxImageGlyphBlt,
81 dmxPolyGlyphBlt,
82 dmxPushPixels
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)))
90 return FALSE;
92 return TRUE;
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);
100 int i;
102 for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) {
103 if (pGC->depth == dmxScreen->bePixmapFormats[i].depth) {
104 unsigned long mask;
105 XGCValues gcvals;
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],
113 mask, &gcvals);
114 break;
119 /** Create a graphics context on the back-end server associated /a pGC's
120 * screen. */
121 Bool dmxCreateGC(GCPtr pGC)
123 ScreenPtr pScreen = pGC->pScreen;
124 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
125 dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
126 Bool ret;
128 DMX_UNWRAP(CreateGC, dmxScreen, pScreen);
129 if ((ret = pScreen->CreateGC(pGC))) {
130 /* Save the old funcs */
131 pGCPriv->funcs = pGC->funcs;
132 pGCPriv->ops = NULL;
134 pGC->funcs = &dmxGCFuncs;
136 if (dmxScreen->beDisplay) {
137 dmxBECreateGC(pScreen, pGC);
138 } else {
139 pGCPriv->gc = NULL;
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);
150 return ret;
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);
160 #if 0
161 pGC->funcs->ValidateGC(pGC, changes, pDrawable);
162 #endif
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
167 * epilogue.
169 pGCPriv->ops = pGC->ops;
170 } else {
171 pGCPriv->ops = NULL;
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 |
179 GCClipYOrigin |
180 GCClipMask |
181 GCSubwindowMode)) ||
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);
197 XGCValues v;
199 DMX_GC_FUNC_PROLOGUE(pGC);
200 #if 0
201 pGC->funcs->ChangeGC(pGC, mask);
202 #endif
204 /* Handle "magic special case" from CreateGC */
205 if (pGCPriv->msc) {
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;
244 if (mask & GCTile) {
245 if (pGC->tileIsPixel) {
246 mask &= ~GCTile;
247 } else {
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;
258 if (mask & GCFont) {
259 if (dmxScreen->beDisplay) {
260 dmxFontPrivPtr pFontPriv;
261 pFontPriv = FontGetPrivate(pGC->font, dmxFontPrivateIndex);
262 v.font = pFontPriv->font[pScreen->myNum]->fid;
263 } else {
264 mask &= ~GCFont;
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) {
278 mask &= ~GCDashList;
279 if (dmxScreen->beDisplay)
280 XSetDashes(dmxScreen->beDisplay, pGCPriv->gc,
281 pGC->dashOffset, (char *)pGC->dash,
282 pGC->numInDashList);
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);
320 if (pGCPriv->gc) {
321 XFreeGC(dmxScreen->beDisplay, pGCPriv->gc);
322 pGCPriv->gc = NULL;
323 return TRUE;
326 return FALSE;
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)
340 dmxBEFreeGC(pGC);
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);
352 XRectangle *pRects;
353 BoxPtr pBox;
354 int i, nRects;
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) {
361 case CT_NONE:
362 if (dmxScreen->beDisplay)
363 XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None);
364 break;
366 case CT_REGION:
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);
383 xfree(pRects);
385 break;
387 case CT_PIXMAP:
388 case CT_UNSORTED:
389 case CT_YSORTED:
390 case CT_YXSORTED:
391 case CT_YXBANDED:
392 /* These clip types are condensed down to either NONE or REGION
393 in the mi code */
394 break;
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);