dmxgc.c revision 706f2543
1/* 2 * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. 3 * 4 * All Rights Reserved. 5 * 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: 13 * 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. 17 * 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. 26 */ 27 28/* 29 * Authors: 30 * Kevin E. Martin <kem@redhat.com> 31 * 32 */ 33 34/** \file 35 * This file provides support for GCs. */ 36 37#ifdef HAVE_DMX_CONFIG_H 38#include <dmx-config.h> 39#endif 40 41#include "dmx.h" 42#include "dmxsync.h" 43#include "dmxgc.h" 44#include "dmxgcops.h" 45#include "dmxpixmap.h" 46#include "dmxfont.h" 47 48#include "gcstruct.h" 49#include "pixmapstr.h" 50#include "migc.h" 51 52static GCFuncs dmxGCFuncs = { 53 dmxValidateGC, 54 dmxChangeGC, 55 dmxCopyGC, 56 dmxDestroyGC, 57 dmxChangeClip, 58 dmxDestroyClip, 59 dmxCopyClip, 60}; 61 62static 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 83}; 84 85/** Initialize the GC on \a pScreen */ 86Bool dmxInitGC(ScreenPtr pScreen) 87{ 88 if (!dixRegisterPrivateKey(&dmxGCPrivateKeyRec, PRIVATE_GC, sizeof(dmxGCPrivRec))) 89 return FALSE; 90 return TRUE; 91} 92 93/** Create the GC on the back-end server. */ 94void dmxBECreateGC(ScreenPtr pScreen, GCPtr pGC) 95{ 96 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; 97 dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); 98 int i; 99 100 for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { 101 if (pGC->depth == dmxScreen->bePixmapFormats[i].depth) { 102 unsigned long mask; 103 XGCValues gcvals; 104 105 mask = GCGraphicsExposures; 106 gcvals.graphics_exposures = FALSE; 107 108 /* Create GC in the back-end servers */ 109 pGCPriv->gc = XCreateGC(dmxScreen->beDisplay, 110 dmxScreen->scrnDefDrawables[i], 111 mask, &gcvals); 112 break; 113 } 114 } 115} 116 117/** Create a graphics context on the back-end server associated /a pGC's 118 * screen. */ 119Bool dmxCreateGC(GCPtr pGC) 120{ 121 ScreenPtr pScreen = pGC->pScreen; 122 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; 123 dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); 124 Bool ret; 125 126 DMX_UNWRAP(CreateGC, dmxScreen, pScreen); 127 if ((ret = pScreen->CreateGC(pGC))) { 128 /* Save the old funcs */ 129 pGCPriv->funcs = pGC->funcs; 130 pGCPriv->ops = NULL; 131 132 pGC->funcs = &dmxGCFuncs; 133 134 if (dmxScreen->beDisplay) { 135 dmxBECreateGC(pScreen, pGC); 136 } else { 137 pGCPriv->gc = NULL; 138 } 139 140 /* Check for "magic special case" 141 * 1. see CreateGC in dix/gc.c for more info 142 * 2. see dmxChangeGC for more info 143 */ 144 pGCPriv->msc = (!pGC->tileIsPixel && !pGC->tile.pixmap); 145 } 146 DMX_WRAP(CreateGC, dmxCreateGC, dmxScreen, pScreen); 147 148 return ret; 149} 150 151/** Validate a graphics context, \a pGC, locally in the DMX server and 152 * recompute the composite clip, if necessary. */ 153void dmxValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) 154{ 155 dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); 156 157 DMX_GC_FUNC_PROLOGUE(pGC); 158#if 0 159 pGC->funcs->ValidateGC(pGC, changes, pDrawable); 160#endif 161 162 if (pDrawable->type == DRAWABLE_WINDOW || 163 pDrawable->type == DRAWABLE_PIXMAP) { 164 /* Save the old ops, since we're about to change the ops in the 165 * epilogue. 166 */ 167 pGCPriv->ops = pGC->ops; 168 } else { 169 pGCPriv->ops = NULL; 170 } 171 172 /* If the client clip is different or moved OR the subwindowMode has 173 * changed OR the window's clip has changed since the last 174 * validation, then we need to recompute the composite clip. 175 */ 176 if ((changes & (GCClipXOrigin | 177 GCClipYOrigin | 178 GCClipMask | 179 GCSubwindowMode)) || 180 (pDrawable->serialNumber != 181 (pGC->serialNumber & DRAWABLE_SERIAL_BITS))) { 182 miComputeCompositeClip(pGC, pDrawable); 183 } 184 185 DMX_GC_FUNC_EPILOGUE(pGC); 186} 187 188/** Set the values in the graphics context on the back-end server 189 * associated with \a pGC's screen. */ 190void dmxChangeGC(GCPtr pGC, unsigned long mask) 191{ 192 ScreenPtr pScreen = pGC->pScreen; 193 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; 194 dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); 195 XGCValues v; 196 197 DMX_GC_FUNC_PROLOGUE(pGC); 198#if 0 199 pGC->funcs->ChangeGC(pGC, mask); 200#endif 201 202 /* Handle "magic special case" from CreateGC */ 203 if (pGCPriv->msc) { 204 /* The "magic special case" is used to handle the case where a 205 * foreground pixel is set when the GC is created so that a 206 * "pseudo default-tile" can be created and used in case the 207 * fillstyle was set to FillTiled. This specific case is tested 208 * in xtest (XCreateGC test #3). What has happened in dix by 209 * the time it reaches here is (1) the pGC->tile.pixel has been 210 * set to pGC->fgPixel and pGC->tileIsPixel is set, (2) if a 211 * tile has also been set, then pGC->tileIsPixel is unset and 212 * pGC->tile.pixmap is initialized; else, the default tile is 213 * created and pGC->tileIsPixel is unset and pGC->tile.pixmap is 214 * initialized to the "pseudo default-tile". In either case, 215 * pGC->tile.pixmap is set; however, in the "magic special case" 216 * the mask is not updated to allow us to detect that we should 217 * initialize the GCTile in the back-end server. Thus, we catch 218 * this case in dmxCreateGC and add GCTile to the mask here. 219 * Are there any cases that I've missed? 220 */ 221 222 /* Make sure that the tile.pixmap is set, just in case the user 223 * set GCTile in the mask but forgot to set vals.pixmap 224 */ 225 if (pGC->tile.pixmap) mask |= GCTile; 226 227 /* This only happens once when the GC is created */ 228 pGCPriv->msc = FALSE; 229 } 230 231 /* Update back-end server's gc */ 232 if (mask & GCFunction) v.function = pGC->alu; 233 if (mask & GCPlaneMask) v.plane_mask = pGC->planemask; 234 if (mask & GCForeground) v.foreground = pGC->fgPixel; 235 if (mask & GCBackground) v.background = pGC->bgPixel; 236 if (mask & GCLineWidth) v.line_width = pGC->lineWidth; 237 if (mask & GCLineStyle) v.line_style = pGC->lineStyle; 238 if (mask & GCCapStyle) v.cap_style = pGC->capStyle; 239 if (mask & GCJoinStyle) v.join_style = pGC->joinStyle; 240 if (mask & GCFillStyle) v.fill_style = pGC->fillStyle; 241 if (mask & GCFillRule) v.fill_rule = pGC->fillRule; 242 if (mask & GCTile) { 243 if (pGC->tileIsPixel) { 244 mask &= ~GCTile; 245 } else { 246 dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pGC->tile.pixmap); 247 v.tile = (Drawable)pPixPriv->pixmap; 248 } 249 } 250 if (mask & GCStipple) { 251 dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pGC->stipple); 252 v.stipple = (Drawable)pPixPriv->pixmap; 253 } 254 if (mask & GCTileStipXOrigin) v.ts_x_origin = pGC->patOrg.x; 255 if (mask & GCTileStipYOrigin) v.ts_y_origin = pGC->patOrg.y; 256 if (mask & GCFont) { 257 if (dmxScreen->beDisplay) { 258 dmxFontPrivPtr pFontPriv; 259 pFontPriv = FontGetPrivate(pGC->font, dmxFontPrivateIndex); 260 v.font = pFontPriv->font[pScreen->myNum]->fid; 261 } else { 262 mask &= ~GCFont; 263 } 264 } 265 if (mask & GCSubwindowMode) v.subwindow_mode = pGC->subWindowMode; 266 267 /* Graphics exposures are not needed on the back-ends since they can 268 be generated on the front-end thereby saving bandwidth. */ 269 if (mask & GCGraphicsExposures) mask &= ~GCGraphicsExposures; 270 271 if (mask & GCClipXOrigin) v.clip_x_origin = pGC->clipOrg.x; 272 if (mask & GCClipYOrigin) v.clip_y_origin = pGC->clipOrg.y; 273 if (mask & GCClipMask) mask &= ~GCClipMask; /* See ChangeClip */ 274 if (mask & GCDashOffset) v.dash_offset = pGC->dashOffset; 275 if (mask & GCDashList) { 276 mask &= ~GCDashList; 277 if (dmxScreen->beDisplay) 278 XSetDashes(dmxScreen->beDisplay, pGCPriv->gc, 279 pGC->dashOffset, (char *)pGC->dash, 280 pGC->numInDashList); 281 } 282 if (mask & GCArcMode) v.arc_mode = pGC->arcMode; 283 284 if (mask && dmxScreen->beDisplay) { 285 XChangeGC(dmxScreen->beDisplay, pGCPriv->gc, mask, &v); 286 dmxSync(dmxScreen, FALSE); 287 } 288 289 DMX_GC_FUNC_EPILOGUE(pGC); 290} 291 292/** Copy \a pGCSrc to \a pGCDst on the back-end server associated with 293 * \a pGCSrc's screen. */ 294void dmxCopyGC(GCPtr pGCSrc, unsigned long changes, GCPtr pGCDst) 295{ 296 ScreenPtr pScreen = pGCSrc->pScreen; 297 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; 298 dmxGCPrivPtr pGCSrcPriv = DMX_GET_GC_PRIV(pGCSrc); 299 dmxGCPrivPtr pGCDstPriv = DMX_GET_GC_PRIV(pGCDst); 300 301 DMX_GC_FUNC_PROLOGUE(pGCDst); 302 pGCDst->funcs->CopyGC(pGCSrc, changes, pGCDst); 303 304 /* Copy the GC on the back-end server */ 305 if (dmxScreen->beDisplay) 306 XCopyGC(dmxScreen->beDisplay, pGCSrcPriv->gc, changes, pGCDstPriv->gc); 307 308 DMX_GC_FUNC_EPILOGUE(pGCDst); 309} 310 311/** Free the \a pGC on the back-end server. */ 312Bool dmxBEFreeGC(GCPtr pGC) 313{ 314 ScreenPtr pScreen = pGC->pScreen; 315 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; 316 dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); 317 318 if (pGCPriv->gc) { 319 XFreeGC(dmxScreen->beDisplay, pGCPriv->gc); 320 pGCPriv->gc = NULL; 321 return TRUE; 322 } 323 324 return FALSE; 325} 326 327/** Destroy the graphics context, \a pGC and free the corresponding GC 328 * on the back-end server. */ 329void dmxDestroyGC(GCPtr pGC) 330{ 331 ScreenPtr pScreen = pGC->pScreen; 332 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; 333 334 DMX_GC_FUNC_PROLOGUE(pGC); 335 336 /* Free the GC on the back-end server */ 337 if (dmxScreen->beDisplay) 338 dmxBEFreeGC(pGC); 339 340 pGC->funcs->DestroyGC(pGC); 341 DMX_GC_FUNC_EPILOGUE(pGC); 342} 343 344/** Change the clip rects for a GC. */ 345void dmxChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects) 346{ 347 ScreenPtr pScreen = pGC->pScreen; 348 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; 349 dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); 350 XRectangle *pRects; 351 BoxPtr pBox; 352 int i, nRects; 353 354 DMX_GC_FUNC_PROLOGUE(pGC); 355 pGC->funcs->ChangeClip(pGC, type, pvalue, nrects); 356 357 /* Set the client clip on the back-end server */ 358 switch (pGC->clientClipType) { 359 case CT_NONE: 360 if (dmxScreen->beDisplay) 361 XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None); 362 break; 363 364 case CT_REGION: 365 if (dmxScreen->beDisplay) { 366 nRects = RegionNumRects((RegionPtr)pGC->clientClip); 367 pRects = malloc(nRects * sizeof(*pRects)); 368 pBox = RegionRects((RegionPtr)pGC->clientClip); 369 370 for (i = 0; i < nRects; i++) { 371 pRects[i].x = pBox[i].x1; 372 pRects[i].y = pBox[i].y1; 373 pRects[i].width = pBox[i].x2 - pBox[i].x1; 374 pRects[i].height = pBox[i].y2 - pBox[i].y1; 375 } 376 377 XSetClipRectangles(dmxScreen->beDisplay, pGCPriv->gc, 378 pGC->clipOrg.x, pGC->clipOrg.y, 379 pRects, nRects, Unsorted); 380 381 free(pRects); 382 } 383 break; 384 385 case CT_PIXMAP: 386 /* Condensed down to REGION in the mi code */ 387 break; 388 } 389 390 DMX_GC_FUNC_EPILOGUE(pGC); 391} 392 393/** Destroy a GC's clip rects. */ 394void dmxDestroyClip(GCPtr pGC) 395{ 396 ScreenPtr pScreen = pGC->pScreen; 397 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; 398 dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); 399 400 DMX_GC_FUNC_PROLOGUE(pGC); 401 pGC->funcs->DestroyClip(pGC); 402 403 /* Set the client clip on the back-end server to None */ 404 if (dmxScreen->beDisplay) 405 XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None); 406 407 DMX_GC_FUNC_EPILOGUE(pGC); 408} 409 410/** Copy a GC's clip rects. */ 411void dmxCopyClip(GCPtr pGCDst, GCPtr pGCSrc) 412{ 413 DMX_GC_FUNC_PROLOGUE(pGCDst); 414 pGCDst->funcs->CopyClip(pGCDst, pGCSrc); 415 DMX_GC_FUNC_EPILOGUE(pGCDst); 416} 417