1/*
2
3Copyright 1993 by Davor Matic
4
5Permission to use, copy, modify, distribute, and sell this software
6and its documentation for any purpose is hereby granted without fee,
7provided that the above copyright notice appear in all copies and that
8both that copyright notice and this permission notice appear in
9supporting documentation.  Davor Matic makes no representations about
10the suitability of this software for any purpose.  It is provided "as
11is" without express or implied warranty.
12
13*/
14
15#ifdef HAVE_XNEST_CONFIG_H
16#include <xnest-config.h>
17#endif
18
19#include <X11/X.h>
20#include <X11/Xproto.h>
21#include "gcstruct.h"
22#include "windowstr.h"
23#include "pixmapstr.h"
24#include "scrnintstr.h"
25#include <X11/fonts/fontstruct.h>
26#include "mistruct.h"
27#include "region.h"
28
29#include "Xnest.h"
30
31#include "Display.h"
32#include "XNGC.h"
33#include "GCOps.h"
34#include "Drawable.h"
35#include "XNFont.h"
36#include "Color.h"
37
38DevPrivateKeyRec xnestGCPrivateKeyRec;
39
40static GCFuncs xnestFuncs = {
41  xnestValidateGC,
42  xnestChangeGC,
43  xnestCopyGC,
44  xnestDestroyGC,
45  xnestChangeClip,
46  xnestDestroyClip,
47  xnestCopyClip,
48};
49
50static GCOps xnestOps = {
51  xnestFillSpans,
52  xnestSetSpans,
53  xnestPutImage,
54  xnestCopyArea,
55  xnestCopyPlane,
56  xnestPolyPoint,
57  xnestPolylines,
58  xnestPolySegment,
59  xnestPolyRectangle,
60  xnestPolyArc,
61  xnestFillPolygon,
62  xnestPolyFillRect,
63  xnestPolyFillArc,
64  xnestPolyText8,
65  xnestPolyText16,
66  xnestImageText8,
67  xnestImageText16,
68  xnestImageGlyphBlt,
69  xnestPolyGlyphBlt,
70  xnestPushPixels
71};
72
73Bool
74xnestCreateGC(GCPtr pGC)
75{
76  pGC->funcs = &xnestFuncs;
77  pGC->ops = &xnestOps;
78
79  pGC->miTranslate = 1;
80
81  xnestGCPriv(pGC)->gc = XCreateGC(xnestDisplay,
82				   xnestDefaultDrawables[pGC->depth],
83				   0L, NULL);
84  xnestGCPriv(pGC)->nClipRects = 0;
85
86  return True;
87}
88
89void
90xnestValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
91{
92}
93
94void
95xnestChangeGC(GCPtr pGC, unsigned long mask)
96{
97  XGCValues values;
98
99  if (mask & GCFunction)
100    values.function = pGC->alu;
101
102  if (mask & GCPlaneMask)
103    values.plane_mask = pGC->planemask;
104
105  if (mask & GCForeground)
106    values.foreground = xnestPixel(pGC->fgPixel);
107
108  if (mask & GCBackground)
109    values.background = xnestPixel(pGC->bgPixel);
110
111  if (mask & GCLineWidth)
112    values.line_width = pGC->lineWidth;
113
114  if (mask & GCLineStyle)
115    values.line_style = pGC->lineStyle;
116
117  if (mask & GCCapStyle)
118    values.cap_style = pGC->capStyle;
119
120  if (mask & GCJoinStyle)
121    values.join_style = pGC->joinStyle;
122
123  if (mask & GCFillStyle)
124    values.fill_style = pGC->fillStyle;
125
126  if (mask & GCFillRule)
127    values.fill_rule = pGC->fillRule;
128
129  if (mask & GCTile) {
130    if (pGC->tileIsPixel)
131      mask &= ~GCTile;
132    else
133      values.tile = xnestPixmap(pGC->tile.pixmap);
134  }
135
136  if (mask & GCStipple)
137    values.stipple = xnestPixmap(pGC->stipple);
138
139  if (mask & GCTileStipXOrigin)
140    values.ts_x_origin = pGC->patOrg.x;
141
142  if (mask & GCTileStipYOrigin)
143    values.ts_y_origin = pGC->patOrg.y;
144
145  if (mask & GCFont)
146    values.font = xnestFont(pGC->font);
147
148  if (mask & GCSubwindowMode)
149    values.subwindow_mode = pGC->subWindowMode;
150
151  if (mask & GCGraphicsExposures)
152    values.graphics_exposures = pGC->graphicsExposures;
153
154  if (mask & GCClipXOrigin)
155    values.clip_x_origin = pGC->clipOrg.x;
156
157  if (mask & GCClipYOrigin)
158    values.clip_y_origin = pGC->clipOrg.y;
159
160  if (mask & GCClipMask) /* this is handled in change clip */
161    mask &= ~GCClipMask;
162
163  if (mask & GCDashOffset)
164    values.dash_offset = pGC->dashOffset;
165
166  if (mask & GCDashList) {
167    mask &= ~GCDashList;
168    XSetDashes(xnestDisplay, xnestGC(pGC),
169	       pGC->dashOffset, (char *)pGC->dash, pGC->numInDashList);
170  }
171
172  if (mask & GCArcMode)
173    values.arc_mode = pGC->arcMode;
174
175  if (mask)
176    XChangeGC(xnestDisplay, xnestGC(pGC), mask, &values);
177}
178
179void
180xnestCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst)
181{
182  XCopyGC(xnestDisplay, xnestGC(pGCSrc), mask, xnestGC(pGCDst));
183}
184
185void
186xnestDestroyGC(GCPtr pGC)
187{
188  XFreeGC(xnestDisplay, xnestGC(pGC));
189}
190
191void
192xnestChangeClip(GCPtr pGC, int type, pointer pValue, int nRects)
193{
194  int i, size;
195  BoxPtr pBox;
196  XRectangle *pRects;
197
198  xnestDestroyClipHelper(pGC);
199
200  switch(type)
201    {
202    case CT_NONE:
203      XSetClipMask(xnestDisplay, xnestGC(pGC), None);
204      break;
205
206    case CT_REGION:
207      nRects = RegionNumRects((RegionPtr)pValue);
208      size = nRects * sizeof(*pRects);
209      pRects = (XRectangle *) malloc(size);
210      pBox = RegionRects((RegionPtr)pValue);
211      for (i = nRects; i-- > 0; ) {
212	pRects[i].x = pBox[i].x1;
213	pRects[i].y = pBox[i].y1;
214	pRects[i].width = pBox[i].x2 - pBox[i].x1;
215	pRects[i].height = pBox[i].y2 - pBox[i].y1;
216      }
217      XSetClipRectangles(xnestDisplay, xnestGC(pGC), 0, 0,
218			 pRects, nRects, Unsorted);
219      free((char *) pRects);
220      break;
221
222    case CT_PIXMAP:
223      XSetClipMask(xnestDisplay, xnestGC(pGC),
224		   xnestPixmap((PixmapPtr)pValue));
225      /*
226       * Need to change into region, so subsequent uses are with
227       * current pixmap contents.
228       */
229      pGC->clientClip = (pointer) (*pGC->pScreen->BitmapToRegion)((PixmapPtr)pValue);
230      (*pGC->pScreen->DestroyPixmap)((PixmapPtr)pValue);
231      pValue = pGC->clientClip;
232      type = CT_REGION;
233      break;
234
235    case CT_UNSORTED:
236      XSetClipRectangles(xnestDisplay, xnestGC(pGC),
237			 pGC->clipOrg.x, pGC->clipOrg.y,
238			 (XRectangle *)pValue, nRects, Unsorted);
239      break;
240
241    case CT_YSORTED:
242      XSetClipRectangles(xnestDisplay, xnestGC(pGC),
243			 pGC->clipOrg.x, pGC->clipOrg.y,
244			 (XRectangle *)pValue, nRects, YSorted);
245      break;
246
247    case CT_YXSORTED:
248      XSetClipRectangles(xnestDisplay, xnestGC(pGC),
249			 pGC->clipOrg.x, pGC->clipOrg.y,
250			 (XRectangle *)pValue, nRects, YXSorted);
251      break;
252
253    case CT_YXBANDED:
254      XSetClipRectangles(xnestDisplay, xnestGC(pGC),
255			 pGC->clipOrg.x, pGC->clipOrg.y,
256			 (XRectangle *)pValue, nRects, YXBanded);
257      break;
258    }
259
260  switch(type)
261    {
262    default:
263      break;
264
265    case CT_UNSORTED:
266    case CT_YSORTED:
267    case CT_YXSORTED:
268    case CT_YXBANDED:
269
270      /*
271       * other parts of server can only deal with CT_NONE,
272       * CT_PIXMAP and CT_REGION client clips.
273       */
274      pGC->clientClip = (pointer) RegionFromRects(nRects,
275						  (xRectangle *)pValue, type);
276      free(pValue);
277      pValue = pGC->clientClip;
278      type = CT_REGION;
279
280      break;
281    }
282
283  pGC->clientClipType = type;
284  pGC->clientClip = pValue;
285  xnestGCPriv(pGC)->nClipRects = nRects;
286}
287
288void
289xnestDestroyClip(GCPtr pGC)
290{
291  xnestDestroyClipHelper(pGC);
292
293  XSetClipMask(xnestDisplay, xnestGC(pGC), None);
294
295  pGC->clientClipType = CT_NONE;
296  pGC->clientClip = NULL;
297  xnestGCPriv(pGC)->nClipRects = 0;
298}
299
300void
301xnestDestroyClipHelper(GCPtr pGC)
302{
303  switch (pGC->clientClipType)
304    {
305    default:
306    case CT_NONE:
307      break;
308
309    case CT_REGION:
310      RegionDestroy(pGC->clientClip);
311      break;
312    }
313}
314
315void
316xnestCopyClip(GCPtr pGCDst, GCPtr pGCSrc)
317{
318  RegionPtr pRgn;
319
320  switch (pGCSrc->clientClipType)
321    {
322    default:
323    case CT_NONE:
324      xnestDestroyClip(pGCDst);
325      break;
326
327    case CT_REGION:
328      pRgn = RegionCreate(NULL, 1);
329      RegionCopy(pRgn, pGCSrc->clientClip);
330      xnestChangeClip(pGCDst, CT_REGION, pRgn, 0);
331      break;
332    }
333}
334