Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | ||
52 | static GCFuncs dmxGCFuncs = { | |
53 | dmxValidateGC, | |
54 | dmxChangeGC, | |
55 | dmxCopyGC, | |
56 | dmxDestroyGC, | |
57 | dmxChangeClip, | |
58 | dmxDestroyClip, | |
59 | dmxCopyClip, | |
60 | }; | |
61 | ||
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 | |
83 | }; | |
84 | ||
85 | /** Initialize the GC on \a pScreen */ | |
86 | Bool | |
87 | dmxInitGC(ScreenPtr pScreen) | |
88 | { | |
89 | if (!dixRegisterPrivateKey | |
90 | (&dmxGCPrivateKeyRec, PRIVATE_GC, sizeof(dmxGCPrivRec))) | |
91 | return FALSE; | |
92 | return TRUE; | |
93 | } | |
94 | ||
95 | /** Create the GC on the back-end server. */ | |
96 | void | |
97 | dmxBECreateGC(ScreenPtr pScreen, GCPtr pGC) | |
98 | { | |
99 | DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; | |
100 | dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); | |
101 | int i; | |
102 | ||
103 | for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { | |
104 | if (pGC->depth == dmxScreen->bePixmapFormats[i].depth) { | |
105 | unsigned long mask; | |
106 | XGCValues gcvals; | |
107 | ||
108 | mask = GCGraphicsExposures; | |
109 | gcvals.graphics_exposures = FALSE; | |
110 | ||
111 | /* Create GC in the back-end servers */ | |
112 | pGCPriv->gc = XCreateGC(dmxScreen->beDisplay, | |
113 | dmxScreen->scrnDefDrawables[i], | |
114 | mask, &gcvals); | |
115 | break; | |
116 | } | |
117 | } | |
118 | } | |
119 | ||
120 | /** Create a graphics context on the back-end server associated /a pGC's | |
121 | * screen. */ | |
122 | Bool | |
123 | dmxCreateGC(GCPtr pGC) | |
124 | { | |
125 | ScreenPtr pScreen = pGC->pScreen; | |
126 | DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; | |
127 | dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); | |
128 | Bool ret; | |
129 | ||
130 | DMX_UNWRAP(CreateGC, dmxScreen, pScreen); | |
131 | if ((ret = pScreen->CreateGC(pGC))) { | |
132 | /* Save the old funcs */ | |
133 | pGCPriv->funcs = pGC->funcs; | |
134 | pGCPriv->ops = NULL; | |
135 | ||
136 | pGC->funcs = &dmxGCFuncs; | |
137 | ||
138 | if (dmxScreen->beDisplay) { | |
139 | dmxBECreateGC(pScreen, pGC); | |
140 | } | |
141 | else { | |
142 | pGCPriv->gc = NULL; | |
143 | } | |
144 | ||
145 | /* Check for "magic special case" | |
146 | * 1. see CreateGC in dix/gc.c for more info | |
147 | * 2. see dmxChangeGC for more info | |
148 | */ | |
149 | pGCPriv->msc = (!pGC->tileIsPixel && !pGC->tile.pixmap); | |
150 | } | |
151 | DMX_WRAP(CreateGC, dmxCreateGC, dmxScreen, pScreen); | |
152 | ||
153 | return ret; | |
154 | } | |
155 | ||
156 | /** Validate a graphics context, \a pGC, locally in the DMX server and | |
157 | * recompute the composite clip, if necessary. */ | |
158 | void | |
159 | dmxValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) | |
160 | { | |
161 | dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); | |
162 | ||
163 | DMX_GC_FUNC_PROLOGUE(pGC); | |
164 | #if 0 | |
165 | pGC->funcs->ValidateGC(pGC, changes, pDrawable); | |
166 | #endif | |
167 | ||
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 | |
171 | * epilogue. | |
172 | */ | |
173 | pGCPriv->ops = pGC->ops; | |
174 | } | |
175 | else { | |
176 | pGCPriv->ops = NULL; | |
177 | } | |
178 | ||
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. | |
182 | */ | |
183 | if ((changes & (GCClipXOrigin | | |
184 | GCClipYOrigin | | |
185 | GCClipMask | | |
186 | GCSubwindowMode)) || | |
187 | (pDrawable->serialNumber != | |
188 | (pGC->serialNumber & DRAWABLE_SERIAL_BITS))) { | |
189 | miComputeCompositeClip(pGC, pDrawable); | |
190 | } | |
191 | ||
192 | DMX_GC_FUNC_EPILOGUE(pGC); | |
193 | } | |
194 | ||
195 | /** Set the values in the graphics context on the back-end server | |
196 | * associated with \a pGC's screen. */ | |
197 | void | |
198 | dmxChangeGC(GCPtr pGC, unsigned long mask) | |
199 | { | |
200 | ScreenPtr pScreen = pGC->pScreen; | |
201 | DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; | |
202 | dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); | |
203 | XGCValues v; | |
204 | ||
205 | DMX_GC_FUNC_PROLOGUE(pGC); | |
206 | #if 0 | |
207 | pGC->funcs->ChangeGC(pGC, mask); | |
208 | #endif | |
209 | ||
210 | /* Handle "magic special case" from CreateGC */ | |
211 | if (pGCPriv->msc) { | |
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? | |
228 | */ | |
229 | ||
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 | |
232 | */ | |
233 | if (pGC->tile.pixmap) | |
234 | mask |= GCTile; | |
235 | ||
236 | /* This only happens once when the GC is created */ | |
237 | pGCPriv->msc = FALSE; | |
238 | } | |
239 | ||
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; | |
261 | if (mask & GCTile) { | |
262 | if (pGC->tileIsPixel) { | |
263 | mask &= ~GCTile; | |
264 | } | |
265 | else { | |
266 | dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pGC->tile.pixmap); | |
267 | ||
268 | v.tile = (Drawable) pPixPriv->pixmap; | |
269 | } | |
270 | } | |
271 | if (mask & GCStipple) { | |
272 | dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pGC->stipple); | |
273 | ||
274 | v.stipple = (Drawable) pPixPriv->pixmap; | |
275 | } | |
276 | if (mask & GCTileStipXOrigin) | |
277 | v.ts_x_origin = pGC->patOrg.x; | |
278 | if (mask & GCTileStipYOrigin) | |
279 | v.ts_y_origin = pGC->patOrg.y; | |
280 | if (mask & GCFont) { | |
281 | if (dmxScreen->beDisplay) { | |
282 | dmxFontPrivPtr pFontPriv; | |
283 | ||
284 | pFontPriv = FontGetPrivate(pGC->font, dmxFontPrivateIndex); | |
285 | v.font = pFontPriv->font[pScreen->myNum]->fid; | |
286 | } | |
287 | else { | |
288 | mask &= ~GCFont; | |
289 | } | |
290 | } | |
291 | if (mask & GCSubwindowMode) | |
292 | v.subwindow_mode = pGC->subWindowMode; | |
293 | ||
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; | |
298 | ||
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) { | |
308 | mask &= ~GCDashList; | |
309 | if (dmxScreen->beDisplay) | |
310 | XSetDashes(dmxScreen->beDisplay, pGCPriv->gc, | |
311 | pGC->dashOffset, (char *) pGC->dash, pGC->numInDashList); | |
312 | } | |
313 | if (mask & GCArcMode) | |
314 | v.arc_mode = pGC->arcMode; | |
315 | ||
316 | if (mask && dmxScreen->beDisplay) { | |
317 | XChangeGC(dmxScreen->beDisplay, pGCPriv->gc, mask, &v); | |
318 | dmxSync(dmxScreen, FALSE); | |
319 | } | |
320 | ||
321 | DMX_GC_FUNC_EPILOGUE(pGC); | |
322 | } | |
323 | ||
324 | /** Copy \a pGCSrc to \a pGCDst on the back-end server associated with | |
325 | * \a pGCSrc's screen. */ | |
326 | void | |
327 | dmxCopyGC(GCPtr pGCSrc, unsigned long changes, GCPtr pGCDst) | |
328 | { | |
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); | |
333 | ||
334 | DMX_GC_FUNC_PROLOGUE(pGCDst); | |
335 | pGCDst->funcs->CopyGC(pGCSrc, changes, pGCDst); | |
336 | ||
337 | /* Copy the GC on the back-end server */ | |
338 | if (dmxScreen->beDisplay) | |
339 | XCopyGC(dmxScreen->beDisplay, pGCSrcPriv->gc, changes, pGCDstPriv->gc); | |
340 | ||
341 | DMX_GC_FUNC_EPILOGUE(pGCDst); | |
342 | } | |
343 | ||
344 | /** Free the \a pGC on the back-end server. */ | |
345 | Bool | |
346 | dmxBEFreeGC(GCPtr pGC) | |
347 | { | |
348 | ScreenPtr pScreen = pGC->pScreen; | |
349 | DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; | |
350 | dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); | |
351 | ||
352 | if (pGCPriv->gc) { | |
353 | XFreeGC(dmxScreen->beDisplay, pGCPriv->gc); | |
354 | pGCPriv->gc = NULL; | |
355 | return TRUE; | |
356 | } | |
357 | ||
358 | return FALSE; | |
359 | } | |
360 | ||
361 | /** Destroy the graphics context, \a pGC and free the corresponding GC | |
362 | * on the back-end server. */ | |
363 | void | |
364 | dmxDestroyGC(GCPtr pGC) | |
365 | { | |
366 | ScreenPtr pScreen = pGC->pScreen; | |
367 | DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; | |
368 | ||
369 | DMX_GC_FUNC_PROLOGUE(pGC); | |
370 | ||
371 | /* Free the GC on the back-end server */ | |
372 | if (dmxScreen->beDisplay) | |
373 | dmxBEFreeGC(pGC); | |
374 | ||
375 | pGC->funcs->DestroyGC(pGC); | |
376 | DMX_GC_FUNC_EPILOGUE(pGC); | |
377 | } | |
378 | ||
379 | /** Change the clip rects for a GC. */ | |
380 | void | |
381 | dmxChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects) | |
382 | { | |
383 | ScreenPtr pScreen = pGC->pScreen; | |
384 | DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; | |
385 | dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); | |
386 | XRectangle *pRects; | |
387 | BoxPtr pBox; | |
388 | int i, nRects; | |
389 | ||
390 | DMX_GC_FUNC_PROLOGUE(pGC); | |
391 | pGC->funcs->ChangeClip(pGC, type, pvalue, nrects); | |
392 | ||
393 | /* Set the client clip on the back-end server */ | |
394 | switch (pGC->clientClipType) { | |
395 | case CT_NONE: | |
396 | if (dmxScreen->beDisplay) | |
397 | XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None); | |
398 | break; | |
399 | ||
400 | case CT_REGION: | |
401 | if (dmxScreen->beDisplay) { | |
402 | nRects = RegionNumRects((RegionPtr) pGC->clientClip); | |
403 | pRects = malloc(nRects * sizeof(*pRects)); | |
404 | pBox = RegionRects((RegionPtr) pGC->clientClip); | |
405 | ||
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; | |
411 | } | |
412 | ||
413 | XSetClipRectangles(dmxScreen->beDisplay, pGCPriv->gc, | |
414 | pGC->clipOrg.x, pGC->clipOrg.y, | |
415 | pRects, nRects, Unsorted); | |
416 | ||
417 | free(pRects); | |
418 | } | |
419 | break; | |
420 | ||
421 | case CT_PIXMAP: | |
422 | /* Condensed down to REGION in the mi code */ | |
423 | break; | |
424 | } | |
425 | ||
426 | DMX_GC_FUNC_EPILOGUE(pGC); | |
427 | } | |
428 | ||
429 | /** Destroy a GC's clip rects. */ | |
430 | void | |
431 | dmxDestroyClip(GCPtr pGC) | |
432 | { | |
433 | ScreenPtr pScreen = pGC->pScreen; | |
434 | DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; | |
435 | dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); | |
436 | ||
437 | DMX_GC_FUNC_PROLOGUE(pGC); | |
438 | pGC->funcs->DestroyClip(pGC); | |
439 | ||
440 | /* Set the client clip on the back-end server to None */ | |
441 | if (dmxScreen->beDisplay) | |
442 | XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None); | |
443 | ||
444 | DMX_GC_FUNC_EPILOGUE(pGC); | |
445 | } | |
446 | ||
447 | /** Copy a GC's clip rects. */ | |
448 | void | |
449 | dmxCopyClip(GCPtr pGCDst, GCPtr pGCSrc) | |
450 | { | |
451 | DMX_GC_FUNC_PROLOGUE(pGCDst); | |
452 | pGCDst->funcs->CopyClip(pGCDst, pGCSrc); | |
453 | DMX_GC_FUNC_EPILOGUE(pGCDst); | |
454 | } |