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 GC operations. */
37
#ifdef HAVE_DMX_CONFIG_H
38
#include <dmx-config.h>
45
#include "dmxwindow.h"
46
#include "dmxpixmap.h"
50
#include "pixmapstr.h"
51
#include "dixfontstr.h"
54
#include "panoramiXsrv.h"
57
#define DMX_GCOPS_SET_DRAWABLE(_pDraw, _draw) \
59
if ((_pDraw)->type == DRAWABLE_WINDOW) { \
60
dmxWinPrivPtr pWinPriv = \
61
DMX_GET_WINDOW_PRIV((WindowPtr)(_pDraw)); \
62
(_draw) = (Drawable)pWinPriv->window; \
64
dmxPixPrivPtr pPixPriv = \
65
DMX_GET_PIXMAP_PRIV((PixmapPtr)(_pDraw)); \
66
(_draw) = (Drawable)pPixPriv->pixmap; \
70
#define DMX_GCOPS_OFFSCREEN(_pDraw) \
71
(!dmxScreens[(_pDraw)->pScreen->myNum].beDisplay || \
73
(_pDraw)->type == DRAWABLE_WINDOW && \
74
(DMX_GET_WINDOW_PRIV((WindowPtr)(_pDraw))->offscreen || \
75
!DMX_GET_WINDOW_PRIV((WindowPtr)(_pDraw))->window)))
77
/** Fill spans -- this function should never be called. */
79
dmxFillSpans(DrawablePtr pDrawable, GCPtr pGC,
80
int nInit, DDXPointPtr pptInit, int *pwidthInit, int fSorted)
82
/* Error -- this should never happen! */
85
/** Set spans -- this function should never be called. */
87
dmxSetSpans(DrawablePtr pDrawable, GCPtr pGC,
88
char *psrc, DDXPointPtr ppt, int *pwidth, int nspans, int fSorted)
90
/* Error -- this should never happen! */
93
/** Transfer \a pBits image to back-end server associated with \a
94
* pDrawable's screen. If primitive subdivision optimization is
95
* enabled, then only transfer the sections of \a pBits that are
96
* visible (i.e., not-clipped) to the back-end server. */
98
dmxPutImage(DrawablePtr pDrawable, GCPtr pGC,
99
int depth, int x, int y, int w, int h,
100
int leftPad, int format, char *pBits)
102
DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
103
dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
106
if (DMX_GCOPS_OFFSCREEN(pDrawable))
109
img = XCreateImage(dmxScreen->beDisplay,
110
dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual,
111
depth, format, leftPad, pBits, w, h,
112
BitmapPad(dmxScreen->beDisplay),
113
(format == ZPixmap) ?
114
PixmapBytePad(w, depth) : BitmapBytePad(w + leftPad));
119
DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
121
if (dmxSubdividePrimitives && pGC->pCompositeClip) {
122
RegionPtr pSubImages;
132
pSubImages = RegionCreate(&box, 1);
134
pClip = RegionCreate(NullBox, 1);
135
RegionCopy(pClip, pGC->pCompositeClip);
136
RegionTranslate(pClip, -pDrawable->x, -pDrawable->y);
137
RegionIntersect(pSubImages, pSubImages, pClip);
139
nBox = RegionNumRects(pSubImages);
140
pBox = RegionRects(pSubImages);
143
XPutImage(dmxScreen->beDisplay, draw, pGCPriv->gc, img,
147
pBox->y1, pBox->x2 - pBox->x1, pBox->y2 - pBox->y1);
150
RegionDestroy(pClip);
151
RegionDestroy(pSubImages);
154
XPutImage(dmxScreen->beDisplay, draw, pGCPriv->gc,
155
img, 0, 0, x, y, w, h);
157
XFree(img); /* Use XFree instead of XDestroyImage
158
* because pBits is passed in from the
161
dmxSync(dmxScreen, FALSE);
164
/* Error -- this should not happen! */
168
/** Copy area from \a pSrc drawable to \a pDst drawable on the back-end
169
* server associated with \a pSrc drawable's screen. If the offscreen
170
* optimization is enabled, only copy when both \a pSrc and \a pDst are
171
* at least partially visible. */
173
dmxCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
174
int srcx, int srcy, int w, int h, int dstx, int dsty)
176
DMXScreenInfo *dmxScreen = &dmxScreens[pSrc->pScreen->myNum];
177
dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
178
Drawable srcDraw, dstDraw;
180
if (DMX_GCOPS_OFFSCREEN(pSrc) || DMX_GCOPS_OFFSCREEN(pDst))
181
return miHandleExposures(pSrc, pDst, pGC, srcx, srcy, w, h,
184
DMX_GCOPS_SET_DRAWABLE(pSrc, srcDraw);
185
DMX_GCOPS_SET_DRAWABLE(pDst, dstDraw);
187
XCopyArea(dmxScreen->beDisplay, srcDraw, dstDraw, pGCPriv->gc,
188
srcx, srcy, w, h, dstx, dsty);
189
dmxSync(dmxScreen, FALSE);
191
return miHandleExposures(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, 0L);
194
/** Copy plane number \a bitPlane from \a pSrc drawable to \a pDst
195
* drawable on the back-end server associated with \a pSrc drawable's
196
* screen. If the offscreen optimization is enabled, only copy when
197
* both \a pSrc and \a pDst are at least partially visible. */
199
dmxCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
200
int srcx, int srcy, int width, int height,
201
int dstx, int dsty, unsigned long bitPlane)
203
DMXScreenInfo *dmxScreen = &dmxScreens[pSrc->pScreen->myNum];
204
dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
205
Drawable srcDraw, dstDraw;
207
if (DMX_GCOPS_OFFSCREEN(pSrc) || DMX_GCOPS_OFFSCREEN(pDst))
208
return miHandleExposures(pSrc, pDst, pGC, srcx, srcy, width, height,
209
dstx, dsty, bitPlane);
211
DMX_GCOPS_SET_DRAWABLE(pSrc, srcDraw);
212
DMX_GCOPS_SET_DRAWABLE(pDst, dstDraw);
214
XCopyPlane(dmxScreen->beDisplay, srcDraw, dstDraw, pGCPriv->gc,
215
srcx, srcy, width, height, dstx, dsty, bitPlane);
216
dmxSync(dmxScreen, FALSE);
218
return miHandleExposures(pSrc, pDst, pGC, srcx, srcy, width, height,
219
dstx, dsty, bitPlane);
222
/** Render list of points, \a pptInit in \a pDrawable on the back-end
223
* server associated with \a pDrawable's screen. If the offscreen
224
* optimization is enabled, only draw when \a pDrawable is at least
225
* partially visible. */
227
dmxPolyPoint(DrawablePtr pDrawable, GCPtr pGC,
228
int mode, int npt, DDXPointPtr pptInit)
230
DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
231
dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
234
if (DMX_GCOPS_OFFSCREEN(pDrawable))
237
DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
239
XDrawPoints(dmxScreen->beDisplay, draw, pGCPriv->gc,
240
(XPoint *) pptInit, npt, mode);
241
dmxSync(dmxScreen, FALSE);
244
/** Render list of connected lines, \a pptInit in \a pDrawable on the
245
* back-end server associated with \a pDrawable's screen. If the
246
* offscreen optimization is enabled, only draw when \a pDrawable is at
247
* least partially visible. */
249
dmxPolylines(DrawablePtr pDrawable, GCPtr pGC,
250
int mode, int npt, DDXPointPtr pptInit)
252
DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
253
dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
256
if (DMX_GCOPS_OFFSCREEN(pDrawable))
259
DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
261
XDrawLines(dmxScreen->beDisplay, draw, pGCPriv->gc,
262
(XPoint *) pptInit, npt, mode);
263
dmxSync(dmxScreen, FALSE);
266
/** Render list of disjoint segments, \a pSegs in \a pDrawable on the
267
* back-end server associated with \a pDrawable's screen. If the
268
* offscreen optimization is enabled, only draw when \a pDrawable is at
269
* least partially visible. */
271
dmxPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment * pSegs)
273
DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
274
dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
277
if (DMX_GCOPS_OFFSCREEN(pDrawable))
280
DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
282
XDrawSegments(dmxScreen->beDisplay, draw, pGCPriv->gc,
283
(XSegment *) pSegs, nseg);
284
dmxSync(dmxScreen, FALSE);
287
/** Render list of rectangle outlines, \a pRects in \a pDrawable on the
288
* back-end server associated with \a pDrawable's screen. If the
289
* offscreen optimization is enabled, only draw when \a pDrawable is at
290
* least partially visible. */
292
dmxPolyRectangle(DrawablePtr pDrawable, GCPtr pGC,
293
int nrects, xRectangle *pRects)
295
DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
296
dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
299
if (DMX_GCOPS_OFFSCREEN(pDrawable))
302
DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
304
XDrawRectangles(dmxScreen->beDisplay, draw, pGCPriv->gc,
305
(XRectangle *) pRects, nrects);
307
dmxSync(dmxScreen, FALSE);
310
/** Render list of arc outlines, \a parcs in \a pDrawable on the
311
* back-end server associated with \a pDrawable's screen. If the
312
* offscreen optimization is enabled, only draw when \a pDrawable is at
313
* least partially visible. */
315
dmxPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc * parcs)
317
DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
318
dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
321
if (DMX_GCOPS_OFFSCREEN(pDrawable))
324
DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
326
XDrawArcs(dmxScreen->beDisplay, draw, pGCPriv->gc, (XArc *) parcs, narcs);
327
dmxSync(dmxScreen, FALSE);
330
/** Render a filled polygons in \a pDrawable on the back-end server
331
* associated with \a pDrawable's screen. If the offscreen
332
* optimization is enabled, only draw when \a pDrawable is at least
333
* partially visible. */
335
dmxFillPolygon(DrawablePtr pDrawable, GCPtr pGC,
336
int shape, int mode, int count, DDXPointPtr pPts)
338
DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
339
dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
342
if (DMX_GCOPS_OFFSCREEN(pDrawable))
345
DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
347
XFillPolygon(dmxScreen->beDisplay, draw, pGCPriv->gc,
348
(XPoint *) pPts, count, shape, mode);
349
dmxSync(dmxScreen, FALSE);
352
/** Render list of filled rectangles, \a prectInit in \a pDrawable on
353
* the back-end server associated with \a pDrawable's screen. If the
354
* offscreen optimization is enabled, only draw when \a pDrawable is at
355
* least partially visible. */
357
dmxPolyFillRect(DrawablePtr pDrawable, GCPtr pGC,
358
int nrectFill, xRectangle *prectInit)
360
DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
361
dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
364
if (DMX_GCOPS_OFFSCREEN(pDrawable))
367
DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
369
XFillRectangles(dmxScreen->beDisplay, draw, pGCPriv->gc,
370
(XRectangle *) prectInit, nrectFill);
371
dmxSync(dmxScreen, FALSE);
374
/** Render list of filled arcs, \a parcs in \a pDrawable on the back-end
375
* server associated with \a pDrawable's screen. If the offscreen
376
* optimization is enabled, only draw when \a pDrawable is at least
377
* partially visible. */
379
dmxPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc * parcs)
381
DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
382
dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
385
if (DMX_GCOPS_OFFSCREEN(pDrawable))
388
DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
390
XFillArcs(dmxScreen->beDisplay, draw, pGCPriv->gc, (XArc *) parcs, narcs);
391
dmxSync(dmxScreen, FALSE);
394
/** Render string of 8-bit \a chars (foreground only) in \a pDrawable on
395
* the back-end server associated with \a pDrawable's screen. If the
396
* offscreen optimization is enabled, only draw when \a pDrawable is at
397
* least partially visible. */
399
dmxPolyText8(DrawablePtr pDrawable, GCPtr pGC,
400
int x, int y, int count, char *chars)
402
DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
403
dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
406
CharInfoPtr charinfo[255];
409
GetGlyphs(pGC->font, (unsigned long) count, (unsigned char *) chars,
410
Linear8Bit, &n, charinfo);
412
/* Calculate text width */
414
for (i = 0; i < n; i++)
415
w += charinfo[i]->metrics.characterWidth;
417
if (n != 0 && !DMX_GCOPS_OFFSCREEN(pDrawable)) {
418
DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
420
XDrawString(dmxScreen->beDisplay, draw, pGCPriv->gc,
422
dmxSync(dmxScreen, FALSE);
428
/** Render string of 16-bit \a chars (foreground only) in \a pDrawable
429
* on the back-end server associated with \a pDrawable's screen. If
430
* the offscreen optimization is enabled, only draw when \a pDrawable
431
* is at least partially visible. */
433
dmxPolyText16(DrawablePtr pDrawable, GCPtr pGC,
434
int x, int y, int count, unsigned short *chars)
436
DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
437
dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
440
CharInfoPtr charinfo[255];
443
GetGlyphs(pGC->font, (unsigned long) count, (unsigned char *) chars,
444
(FONTLASTROW(pGC->font) == 0) ? Linear16Bit : TwoD16Bit,
447
/* Calculate text width */
449
for (i = 0; i < n; i++)
450
w += charinfo[i]->metrics.characterWidth;
452
if (n != 0 && !DMX_GCOPS_OFFSCREEN(pDrawable)) {
453
DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
455
XDrawString16(dmxScreen->beDisplay, draw, pGCPriv->gc,
456
x, y, (XChar2b *) chars, count);
457
dmxSync(dmxScreen, FALSE);
463
/** Render string of 8-bit \a chars (both foreground and background) in
464
* \a pDrawable on the back-end server associated with \a pDrawable's
465
* screen. If the offscreen optimization is enabled, only draw when \a
466
* pDrawable is at least partially visible. */
468
dmxImageText8(DrawablePtr pDrawable, GCPtr pGC,
469
int x, int y, int count, char *chars)
471
DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
472
dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
475
if (DMX_GCOPS_OFFSCREEN(pDrawable))
478
DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
480
XDrawImageString(dmxScreen->beDisplay, draw, pGCPriv->gc,
482
dmxSync(dmxScreen, FALSE);
485
/** Render string of 16-bit \a chars (both foreground and background) in
486
* \a pDrawable on the back-end server associated with \a pDrawable's
487
* screen. If the offscreen optimization is enabled, only draw when \a
488
* pDrawable is at least partially visible. */
490
dmxImageText16(DrawablePtr pDrawable, GCPtr pGC,
491
int x, int y, int count, unsigned short *chars)
493
DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
494
dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC);
497
if (DMX_GCOPS_OFFSCREEN(pDrawable))
500
DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
502
XDrawImageString16(dmxScreen->beDisplay, draw, pGCPriv->gc,
503
x, y, (XChar2b *) chars, count);
504
dmxSync(dmxScreen, FALSE);
507
/** Image Glyph Blt -- this function should never be called. */
509
dmxImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
510
int x, int y, unsigned int nglyph,
511
CharInfoPtr * ppci, void *pglyphBase)
513
/* Error -- this should never happen! */
516
/** Poly Glyph Blt -- this function should never be called. */
518
dmxPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
519
int x, int y, unsigned int nglyph,
520
CharInfoPtr * ppci, void *pglyphBase)
522
/* Error -- this should never happen! */
525
/** Push Pixels -- this function should never be called. */
527
dmxPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDst,
528
int w, int h, int x, int y)
530
/* Error -- this should never happen! */
533
/**********************************************************************
534
* Miscellaneous drawing commands
537
/** When Xinerama is active, the client pixmaps are always obtained from
538
* screen 0. When screen 0 is detached, the pixmaps must be obtained
539
* from any other screen that is not detached. Usually, this is screen
541
static DMXScreenInfo *
542
dmxFindAlternatePixmap(DrawablePtr pDrawable, XID *draw)
545
PanoramiXRes *pXinPix;
547
DMXScreenInfo *dmxScreen;
549
if (noPanoramiXExtension)
551
if (pDrawable->type != DRAWABLE_PIXMAP)
554
if (Success != dixLookupResourceByType((void **) &pXinPix,
555
pDrawable->id, XRT_PIXMAP,
556
NullClient, DixUnknownAccess))
559
FOR_NSCREENS_FORWARD_SKIP(i) {
560
dmxScreen = &dmxScreens[i];
561
if (dmxScreen->beDisplay) {
563
dmxPixPrivPtr pSrcPriv;
565
dixLookupResourceByType((void **) &pSrc, pXinPix->info[i].id,
566
RT_PIXMAP, NullClient, DixUnknownAccess);
567
pSrcPriv = DMX_GET_PIXMAP_PRIV(pSrc);
568
if (pSrcPriv->pixmap) {
569
*draw = pSrcPriv->pixmap;
578
/** Get an image from the back-end server associated with \a pDrawable's
579
* screen. If \a pDrawable is a window, it must be viewable to get an
580
* image from it. If it is not viewable, then get the image from the
581
* first ancestor of \a pDrawable that is viewable. If no viewable
582
* ancestor is found, then simply return without getting an image. */
584
dmxGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h,
585
unsigned int format, unsigned long planeMask, char *pdstLine)
587
DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
591
/* Cannot get image from unviewable window */
592
if (pDrawable->type == DRAWABLE_WINDOW) {
593
WindowPtr pWindow = (WindowPtr) pDrawable;
595
if (!pWindow->viewable) {
596
while (!pWindow->viewable && pWindow->parent) {
597
sx += pWindow->origin.x - wBorderWidth(pWindow);
598
sx += pWindow->origin.y - wBorderWidth(pWindow);
599
pWindow = pWindow->parent;
601
if (!pWindow->viewable) {
605
DMX_GCOPS_SET_DRAWABLE(&pWindow->drawable, draw);
606
if (DMX_GCOPS_OFFSCREEN(&pWindow->drawable))
610
DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
611
if (DMX_GCOPS_OFFSCREEN(pDrawable)) {
612
/* Try to find the pixmap on a non-detached Xinerama screen */
613
dmxScreen = dmxFindAlternatePixmap(pDrawable, &draw);
619
img = XGetImage(dmxScreen->beDisplay, draw,
620
sx, sy, w, h, planeMask, format);
622
int len = img->bytes_per_line * img->height;
624
memmove(pdstLine, img->data, len);
628
dmxSync(dmxScreen, FALSE);
631
/** Get Spans -- this function should never be called. */
633
dmxGetSpans(DrawablePtr pDrawable, int wMax,
634
DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart)
636
/* Error -- this should never happen! */